แปลง RGB เป็น RGBA เป็นสีขาว


196

ฉันมีสีฐานสิบหกเช่น#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)

ไอเดีย?


โซลูชัน FYI ตามคำตอบของ Guffa:

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)' 
    }

Interseting! คุณยังต้องการให้มันมองเห็นได้ถูกต้องหรือไม่โปร่งใส?
Mrchief

6
คำถามที่น่าสนใจ! มีคำถามตรงข้ามแน่นอนที่stackoverflow.com/questions/2049230/convert-rgba-color-to-rgbมันอาจช่วยได้
apscience

@Mrchief - ใช่ฉันต้องการให้สีดูเหมือนกันเมื่อปรากฏบนสีขาว แต่จะโปร่งใสที่สุด
Mark Kahn

1
เป็นคำถามที่ดีมากฉันสงสัยอยู่เสมอว่าจะทำอย่างไร แต่มักจะเบือนหน้าหนี);
โดมินิค K

1
@ e100 - คำถามที่เฉพาะเจาะจงที่เรียกนี้คือstackoverflow.com/questions/6658350/... โดยทั่วไปฉันต้องการที่จะวางทับเงา CSS บนองค์ประกอบด้วยสีพื้นหลังโดยไม่ปิดกั้นการคลิกผ่านโดยวางองค์ประกอบเงาไว้ด้านบนของทุกสิ่ง ฉันยังอยากจะทำในขณะนี้ดังนั้นฉันสามารถทำสิ่งสุ่มเช่น: jsfiddle.net/qwySW/2 พลัสฉันเพิ่งพบว่ามันเป็นคำถามที่น่าสนใจ :)
มาร์คคาห์น

คำตอบ:


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
ขอบคุณ! ฉันกำลังทำสิ่งที่คล้ายกัน (เช่นรับ.404) แต่ก็ไม่สามารถทำให้ตัวเลขออกมาได้
Mark Kahn

3
FYI ได้โพสต์คำตอบสุดท้ายตามคำตอบของคุณ
Mark Kahn

2
@templatetypedef: การแปลงองค์ประกอบที่ต่ำที่สุดถึงอัลฟาคือการปรับขนาดจากช่วง0..255ถึง0..1และกลับหัว การใช้1.0 - 152 / 255ก็สามารถใช้ได้เช่นกัน แปลงส่วนประกอบของสีเป็นเพียงการปรับจากn..255การ0..255ที่nเป็นส่วนประกอบที่ต่ำที่สุด
Guffa

1
@Christoph: หลักการจะเหมือนกัน แต่มีความซับซ้อนมากขึ้น แทนที่จะใช้ส่วนประกอบที่ต่ำที่สุดในการคำนวณอัลฟาคุณจะคำนวณอัลฟาที่ต่ำที่สุดที่เป็นไปได้สำหรับแต่ละองค์ประกอบ (เช่นค่าอัลฟาที่จะใช้เพื่อให้ได้สีที่ถูกต้องเมื่อใช้ 0 หรือ 255 เป็นค่าส่วนประกอบ) จากนั้นใช้ค่าสูงสุด ของค่าอัลฟาเหล่านั้น จากนั้นคุณสามารถคำนวณค่าสีที่จะใช้สำหรับแต่ละองค์ประกอบด้วยค่าอัลฟานั้นเพื่อให้ได้สีที่ถูกต้อง โปรดทราบว่าการผสมสีบางส่วน (เช่นสีขาวบนพื้นหลังสีดำ) จะให้ 1.0 เป็นค่าอัลฟาที่ต่ำที่สุดที่เป็นไปได้ที่จะใช้
Guffa

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];
}

โปรดทราบว่าฉันสมมติว่า 'มีความทึบที่นี่ มันเป็นเรื่องเล็กน้อยที่จะเปลี่ยนเป็นความโปร่งใส - เพียงแค่ลบ "1 -" ออกจากสูตรสำหรับ ' สิ่งที่น่าสังเกตคือสิ่งนี้ดูเหมือนจะไม่ให้ผลลัพธ์ที่แน่นอน - มันบอกว่าความทึบคือ 0.498 สำหรับตัวอย่างที่คุณให้ไว้ข้างต้น (128, 128, 255) อย่างไรก็ตามสิ่งนี้อยู่ใกล้มาก


หากคุณแจกจ่ายคูณ 255 ในสมการของคุณคุณจะได้รับผลขวา -[255 * (r/255 - 1) / a + 1 * 255, ...] == [(255*r/255 - 255 * 1) / a + 255, ...] == [(r - 255) / a + 255, ...]
gereeter

6

ฉันต้องการแปลง RGB <-> HSL Ie luminosity == จำนวน white == จำนวนความโปร่งใส

สำหรับตัวอย่างของคุณ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 ฉันได้เขียนฟังก์ชัน SCSS ขนาดเล็กเพื่อให้คุณสามารถใช้อัลกอริทึมที่อธิบายโดย @Guffa ได้อย่างง่ายดาย

@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

ฉันแค่อธิบายแนวคิดสำหรับอัลกอริทึมไม่มีวิธีแก้ปัญหาเต็มรูปแบบ:

โดยทั่วไปคุณมีสามตัวเลขx, y, zและคุณกำลังมองหาสามตัวเลขใหม่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แต่ปัญหาคือการหาจำนวนที่มีข้อผิดพลาด discretization น้อยที่สุด


0

สิ่งนี้ควรทำ:

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

ฉันเพิ่งสังเกตเห็นว่าฉันมีข้อผิดพลาดในอัลฟา Calc (แก้ไขแล้ว) นั่นอาจจะมีบางอย่างเกี่ยวข้องกับมันด้วย
trutheality

ยังคงมีปัญหานำโดยคุณและy ไม่ถูกต้องกองกำลังจำนวนมากที่สุดเพื่อคุณจึงมักจะจบลงด้วยการเป็นหนึ่งเดียวเดียวแล้วหมายเลขอื่น: , ฯลฯ ...(y-x)255 / (y-x)25502550, 22, 255255, 0, 55
มาร์คคาห์น

ฉันเห็นแล้วมันจะไม่ยอมให้สีเข้มกว่านี้ ... ฉันควรทำ/aแล้วมันตรงกับคำตอบที่ถูกต้อง
trutheality

-1

คำตอบยอดนิยมไม่ได้สำหรับฉันที่มีองค์ประกอบสีต่ำ ตัวอย่างเช่นจะไม่คำนวณอัลฟาที่ถูกต้องหากสีเป็น # 80000 ในทางเทคนิคแล้วควรทำให้เป็น # ff0000 ด้วย alpha 0.5 ในการแก้ไขปัญหานี้คุณต้องใช้ 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 )ไม่มีที่ไหนใกล้กับสีเดียวกัน ครั้งแรกจะเป็นสีแดงเข้มปลาแซลมอนที่สอง - ish เว้นแต่จะแสดงบนพื้นสีดำฉันก็คิดว่ามันคงเหมือนเดิม
Mark Kahn
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.