白でRGBをRGBAに変換


196

16進数の色があります(例:(#F4F8FBまたはrgb(244, 248, 251)))、可能な限り透明な rgba色に変換したい(白で表示した場合)。理にかなっていますか?私はアルゴリズムを探しています。少なくとも、アルゴリズムのアイデアを探しています。

例えば:

rgb( 128, 128, 255 ) --> rgba(   0,   0, 255,  .5 )
rgb( 152, 177, 202 ) --> rgba(  50, 100, 150,  .5 ) // can be better(lower alpha)

アイデア?


Guffaの回答に基づくFYIソリューション:

function RGBtoRGBA(r, g, b){
    if((g == null) && (typeof r === 'string')){
        var hex = r.replace(/^\s*#|\s*$/g, '');
        if(hex.length === 3){
            hex = hex.replace(/(.)/g, '$1$1');
        }
        r = parseInt(hex.substr(0, 2), 16);
        g = parseInt(hex.substr(2, 2), 16);
        b = parseInt(hex.substr(4, 2), 16);
    }

    var min, a = (255 - (min = Math.min(r, g, b))) / 255;

    return {
        r    : r = 0|(r - min) / a,
        g    : g = 0|(g - min) / a,
        b    : b = 0|(b - min) / a,
        a    : a = (0|1000*a)/1000,
        rgba : 'rgba(' + r + ', ' + g + ', ' + b + ', ' + a + ')'
    };
}

RGBtoRGBA(204, 153, 102) == RGBtoRGBA('#CC9966') == RGBtoRGBA('C96') == 
    {
       r    : 170,
       g    : 85 ,
       b    : 0  ,
       a    : 0.6,
       rgba : 'rgba(170, 85, 0, 0.6)' 
    }

差し込む!完全に透明ではなく、正しく表示したいですか?
Mrchief 2011

6
興味深い質問です!stackoverflow.com/questions/2049230/convert-rgba-color-to-rgbに正反対の質問があります。それが役立つかもしれません
apscience

@Mrchief-はい、白で表示したときに色が同じに見えるようにしますが、できるだけ透明にします。
Mark Kahn

1
すばらしい質問です。これを行う方法は常に疑問に思っていましたが、通常は回避しました;)+1
Dominic K

1
@ e100-これを引き起こした特定の質問は、stackoverflow.com / questions / 6658350 /…でした。基本的に、すべての上にシャドウ要素を配置することで、クリックスルーをブロックせずに、要素の上にCSSシャドウを背景色でオーバーレイできるようにしたいと考えました。また、これをしばらく実行したいと思っていたので、jsfiddle.net / qwySW/2などのランダムなことを実行できます。加えて、私はそれが魅力的な質問であることがわかりました:)
Mark Kahn

回答:


185

最も低い色成分を取り、それをアルファ値に変換します。次に、最低値を減算し、アルファ値で除算することにより、カラーコンポーネントをスケーリングします。

例:

152 converts to an alpha value of (255 - 152) / 255 ~ 0.404

152 scales using (152 - 152) / 0.404 = 0
177 scales using (177 - 152) / 0.404 ~ 62
202 scales using (202 - 152) / 0.404 ~ 123

したがって、とrgb(152, 177, 202)表示されrgba(0, 62, 123, .404)ます。

Photoshopで実際に色が完全に一致することを確認しました。


1
ありがとうございました!私は似たようなことをしていましたが(たとえばget .404)、数値をうまく計算することができませんでした。
Mark Kahn

3
参考までに、質問の回答に基づいて最終的な解決策を投稿しました
Mark Kahn

2
@templatetypedef:一番下のコンポーネントをアルファに変換すると、範囲0..255からにスケーリングされ、0..1反転します。を使用1.0 - 152 / 255することもできます。色成分の変換は、最小の成分であるからn..255へのスケーリングです。0..255n
Guffa

1
@Christoph:原則は同じですが、もっと複雑です。アルファを計算するために最低のコンポーネントを使用する代わりに、各コンポーネントの最低のアルファを計算します(つまり、コンポーネント値として0または255を使用するときに正しい色を取得するために使用するアルファ値)。次に最高のアルファを計算します。それらのアルファ値の。これから、そのアルファ値を持つ各コンポーネントに使用する色値を計算して、正しい色を取得できます。一部の色の組み合わせ(たとえば、黒の背景に白)では、使用できる最小のアルファ値として1.0が指定されます。
Guffa 2013年

2
このソリューションを実装する小さなフィドルを書きました。こちらがリンクです。jsfiddle.net/wb5fwLoc/1。多分あなたの一人がそれを使うことができます。それはただの、バグのないスクリプトではありません..遊び回るのに十分なはずです。
chsymann

23

r、g、およびbを入力値、r '、g'、b '、およびa'を出力値とし、すべて1と0の間でスケーリングされます(今のところ、これは数学をより美しくするためです)。次に、色を重ねる式:

r = a' * r' + 1 - a'
g = a' * g' + 1 - a'
b = a' * b' + 1 - a'

1-a '用語はバックグラウンド寄与を表し、他の用語はフォアグラウンドを表します。代数を実行します。

r = a' * (r' - 1) + 1
r - 1 = a' * (r' - 1)
(r - 1) / (r' - 1) = a'
(r' - 1) / (r - 1) = 1 / a'
r' - 1 = (r - 1) / a'
r' = (r - 1) / a' + 1

直感的には、最小カラー値が問題の制限要因になると思われるため、これをmにバインドします。

m = min(r, g, b)

透明度を最大化するため、対応する出力値m 'をゼロに設定します。

0 = (m - 1) / a' + 1
-1 = (m - 1) / a'
-a' = m - 1
a' = 1 - m

したがって、JavaScriptでは(途中で1から255に変換されます):

function rgba(r, g, b) {
    var a = 1 - Math.min(r, Math.min(g, b)) / 255;
    return [255 + (r - 255) / a, 255 + (g - 255) / a, 255 + (b - 255) / a, a];
}

ここではa 'が不透明であると想定していることに注意してください。透明度に変更するのは簡単です。a 'の式から「1」を削除するだけです。注目に値するのは、これは正確な結果を生み出すようには見えないということです-上記の例(128、128、255)の不透明度は0.498でした。しかし、これは非常に近いです。


乗算された255を方程式に分配すると、正しい結果が得られます[255 * (r/255 - 1) / a + 1 * 255, ...] == [(255*r/255 - 255 * 1) / a + 255, ...] == [(r - 255) / a + 255, ...]
gereeter

6

RGB <-> HSL変換に注目します。つまり、明度==白の量==透明度。

あなたの例rgb( 128, 128, 255 )では、RGB値を0最初に最大量、つまりrgb( 0, 0, 128 )- にシフトする必要があります。これは、可能な限り白が少ない色です。その後、輝度の式を使用して、元の色を取得するために暗い色に追加する必要がある白の量を計算します。これがアルファになります。

L = (MAX(R,G,B) + MIN(R,G,B))/2
L1 = (255 + 128) / 2 = 191.5
L2 = (128 + 0) /2 = 64
A = (191,5 - 64) / 255 = 0,5;

それが理にかなっていると思います。:)


6

SASS / SCSSを使用している方のために、@ Guffaで説明されているアルゴリズムを簡単に使用できるように、小さなSCSS関数を作成しました

@function transparentize-on-white($color)
{
    $red: red($color);
    $green: green($color);
    $blue: blue($color);
    $lowestColorComponent: min($red, $green, $blue);
    $alpha: (255 - $lowestColorComponent) / 255;

    @return rgba(
        ($red - $lowestColorComponent) / $alpha,
        ($green - $lowestColorComponent) / $alpha,
        ($blue - $lowestColorComponent) / $alpha,
        $alpha
    );
}

3

私はアルゴリズムのアイデアを説明しているだけで、完全な解決策はありません:

基本的には、3つの数字を持ってxyzと次の3つの新しい番号を探しているx'y'z'および乗算器a[0,1]、このようなことを範囲内:

x = a + (1 - a) x'
y = a + (1 - a) y'
z = a + (1 - a) z'

これは、チャネルも[0,1]の範囲の値を取る単位で書き込まれます。8ビットの離散値では、次のようになります。

x = 255 a + (1 - a) x'
y = 255 a + (1 - a) y'
z = 255 a + (1 - a) z'

さらに、できるだけ大きな値が必要ですa。あなたは解決することができます:

a  = (x - x')/(255 - x')          x' = (x - 255 a)/(1 - a)

など実際の値では、これには無限に多くの解があり、任意の実数を接続するだけですaが、問題は、離散化誤差が最小である数を見つけることです。


0

これはそれを行うはずです:

let x = min(r,g,b)
a = 1 - x/255                    # Correction 1
r,g,b = ( (r,g,b) - x ) / a      # Correction 2

アルファ計算(現在修正済み)にエラーがあることに気づきました。だからそれも何か関係があるのか​​もしれない。
真実性2011

yとによってまだ問題が発生しています(y-x)255 / (y-x)誤っへの最大数を強制的に255あなたは常に単一で終わると思いますので、0シングル255:その後、別の番号0, 22, 255255, 0, 55...など、
マーク・カーン

なるほど、暗い色は許されません...私はそれを作るだけで/a正しい答えにマッチします。
真実性2011

-1

上の答えは、色成分が少ないとうまくいきませんでした。たとえば、色が#80000の場合、正しいアルファは計算されません。技術的には、アルファ0.5で#ff0000にする必要があります。これを解決するには、RGB-> HSL-> RGBA変換を使用する必要があります。これは、正しい値を取得するための擬似コードです。

//Convert RGB to HSL
hsl = new HSL(rgb)

//Use lightness as alpha
alpha = hsl.Lightness

//For #80000 lightness is 0.5, so we have to take this into account.
//Lightness more than 0.5 converts to alpha 1 and below is a linear ratio
if (alpha > 0.5)
{
    alpha = 1;
}
else
{
    alpha = alpha / 0.5;
    //We need to drop the lightness of the color to 0.5 to get the actual color
    //that needs to display. Alpha blending will take care of that.
    hsl.Lightness = 0.5;
}

newRgb = hsl.convertToRgb()

「newRgb」には、新しく調整された色の値が含まれ、「alpha」変数を使用して透明度を制御します。


#800000そしてrgba( 255, 0, 0, .5 )、どこにも同じ色はありません。1つ目は濃い赤、2つ目はサーモン風です。黒で表示しない限り、同じだと思います。
Mark Kahn
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.