web-dev-qa-db-ja.com

不透明度を持つ「同等の」色を見つける

「リボン」が別の単色で実行されている背景色があるとします。今、私はリボンを部分的に透明にして、一部のディテールをブレンドしたいのですが、リボンを背景上で「同じ色」に保ちます。

リボンの色の不透明度/アルファ<100%に対して、背景上で不透明度が100%の色と同一のRGB値を(簡単に)決定する方法はありますか?

これが写真です。背景はrgb(72, 28, 97)、リボンrgb(45, 34, 70)です。リボンのrgba(r, g, b, a)が必要なので、この単色と同じように見えます。

enter image description here

79
vicvicvic

カラーブレンディングは、チャンネルごとの線形補間です。したがって、計算は非常に簡単です。 RGB2にRGBA1がある場合、効果的な視覚結果RGB3は次のようになります。

r3 = r2 + (r1-r2)*a1
g3 = g2 + (g1-g2)*a1
b3 = b2 + (b1-b2)*a1

…ここで、アルファチャネルは0.0〜1.0です。

完全性チェック:アルファが0の場合、RGB3はRGB2と同じですか?はい。アルファが1の場合、RGB3はRGB1と同じですか?はい。

背景色と最終色のみをロックした場合、要件を満たすことができる多数のRGBA色(無限、浮動小数点空間)があります。したがって、バーの色または必要な不透明度のいずれかを選択し、他の値を見つける必要があります。

アルファに基づいた色の選択

RGB3(最終的に必要な色)、RGB2(背景色)、およびA1(必要な不透明度)がわかっていて、RGB1だけを探している場合、方程式を次のように再配置できます。

r1 = (r3 - r2 + r2*a1)/a1
g1 = (g3 - g2 + g2*a1)/a1
b1 = (b3 - b2 + b2*a1)/a1

理論的には可能ですが、標準のRGBA範囲では不可能な色の組み合わせがいくつかあります。たとえば、背景が純粋な黒の場合、望ましい知覚色は純粋な白で、望ましいアルファは1%です。必要になります:

r1 = g1 = b1 = 255/0.01 = 25500

…利用可能などの製品よりも100倍明るい超高輝度白色

色に基づいてアルファを選択する

RGB3(最終的に望ましい色)、RGB2(背景色)、RGB1(不透明度を変えたい色)がわかっていて、A1だけを探している場合は、方程式はこうして:

a1 = (r3-r2) / (r1-r2)
a1 = (g3-g2) / (g1-g2)
a1 = (b3-b2) / (b1-b2)

これらが異なる値を与える場合、正確に一致させることはできませんが、アルファを可能な限り近づけるために平均化することはできます。たとえば、赤の上に緑を置くことができる不透明度はありません。青を取得します。

112
Phrogz

phrogzの回答を使用して、LESSミックスインを作成しました。あなたが入力:

  1. 色がどう見えるか
  2. 特定のアルファを持つ
  3. 特定の背景(デフォルトは白)

コードは次のとおりです。

.bg_alpha_calc (@desired_colour, @desired_alpha, @background_colour: white) {
    @r3: red(@desired_colour);
    @g3: green(@desired_colour);
    @b3: blue(@desired_colour);

    @r2: red(@background_colour);
    @g2: green(@background_colour);
    @b2: blue(@background_colour);

    // r1 = (r3 - r2 + r2 * a1) / a1
    @r1: ( @r3 - @r2 + (@r2 * @desired_alpha) ) / @desired_alpha;
    @g1: ( @g3 - @g2 + (@g2 * @desired_alpha) ) / @desired_alpha;
    @b1: ( @b3 - @b2 + (@b2 * @desired_alpha) ) / @desired_alpha;

    background-color: @desired_colour;
    background-color: rgba(@r1, @g1, @b1, @desired_alpha);

}

次のような使用法:

@mycolour: #abc;
@another_colour: blue;
.box_overlay {
  // example:
  .bg_alpha_calc (@mycolour, 0.97, @another_colour);
  // or (for white bg) just:
  .bg_alpha_calc (@mycolour, 0.97);
}

明らかに不可能な組み合わせ(Phrogzによると)には機能しません。つまり、サポートされるのはわずかなレベルの透明度だけです。どのように使用するかを確認してください。

12
ephemer

Phrogzephemerの優れた回答のおかげで、ここに自動が最適なRGBAカラーを計算するSASS関数があります。

目的の色と既存の背景を使用して呼び出し、最適な(最も透明な)RGBA色を計算して、各RGBコンポーネントの±1/256以内に望ましい結果を提供します(丸め誤差のため):

@function alphaize($desired-color, $background-color) {

    $r1: red($background-color);
    $g1: green($background-color);
    $b1: blue($background-color);

    $r2: red($desired-color);
    $g2: green($desired-color);
    $b2: blue($desired-color);

    $alpha: 0;
    $r: -1;
    $g: -1;
    $b: -1;

    @while $alpha < 1 and ($r < 0 or $g < 0 or $b < 0
                           or $r > 255 or $g > 255 or $b > 255) {
        $alpha: $alpha + 1/256;
        $inv: 1 / $alpha;
        $r: $r2 * $inv + $r1 * (1 - $inv);
        $g: $g2 * $inv + $g1 * (1 - $inv);
        $b: $b2 * $inv + $b1 * (1 - $inv);
    }

    @return rgba($r, $g, $b, $alpha);
}

いくつかの組み合わせ(すべてのBootswatchテーマ)に対してテストを行ったところ、暗闇での結果と暗闇での結果の両方でうまく機能します。

PS:結果の色に±1/256よりも高い精度が必要な場合は、rgba色をブレンドするときにブラウザーがどの種類の丸めアルゴリズムを適用するかを知る必要があります(標準化されているかどうかはわかりません)。既存の@while、増加し続ける$alpha必要な精度を達成するまで。

7
Tobia

@Phrogzの答えから:

r3 = r2 + (r1-r2)*a1
g3 = g2 + (g1-g2)*a1
b3 = b2 + (b1-b2)*a1

そう:

r3 - r2 = (r1-r2)*a1
g3 - g2 = (g1-g2)*a1
b3 - b2 = (b1-b2)*a1

そう:

r1 = (r3 - r2) / a1 + r2
g1 = (g3 - g2) / a1 + g2
b1 = (b3 - b2) / a1 + b2

a1の任意の値を選択できます。これにより、r1g1、およびb1の対応する値が必要になります。たとえば、1のアルファを選択すると、RGB1 = RGB3が必要であることがわかりますが、0のアルファを選択しても解決策は得られません(明らかに)。

5
Eric

@Tobiaの答えを拡張して、transparentifyのように不透明度を指定できるようにするには:

@function rgbaMorph($desired-color, $background-color: rgb(255,255,255), $desired-alpha: 0) {

    $r1: red($desired-color);
    $g1: green($desired-color);
    $b1: blue($desired-color);

    $r2: red($background-color);
    $g2: green($background-color);
    $b2: blue($background-color);

    $r: -1;
    $g: -1;
    $b: -1;

    @if ($desired-alpha != 0) {
        $r: ( $r1 - $r2 + ($r2 * $desired-alpha) ) / $desired-alpha;
        $g: ( $g1 - $g2 + ($g2 * $desired-alpha) ) / $desired-alpha;
        $b: ( $b1 - $b2 + ($b2 * $desired-alpha) ) / $desired-alpha;
    }

    @if (($desired-alpha == 0) or ($r < 0 or $g < 0 or $b < 0
                           or $r > 255 or $g > 255 or $b > 255)) {
        //if alpha not attainable, this will find lowest alpha that is

        $alpha: $desired-alpha;
        @while $alpha < 1 and ($r < 0 or $g < 0 or $b < 0
                           or $r > 255 or $g > 255 or $b > 255) {
            $alpha: $alpha + 1/256;
            $inv: 1 / $alpha;
            $r: $r1 * $inv + $r2 * (1 - $inv);
            $g: $g1 * $inv + $g2 * (1 - $inv);
            $b: $b1 * $inv + $b2 * (1 - $inv);
        }
        @debug "Color not attainable at opacity using alpha: " $alpha " instead of: " $desired-alpha;

        $desired-alpha: $alpha;
    }

    @return rgba($r, $g, $b, $desired-alpha);
}
0
phazei