วิธีตรวจสอบว่าสีฐานสิบหก“ ดำเกินไป” หรือไม่?


111

ฉันกำลังพยายามประเมินความมืดของสีที่ตัวเลือกสีเลือกเพื่อดูว่า "ดำเกินไป" หรือไม่และถ้าเป็นเช่นนั้นให้ตั้งค่าเป็นสีขาว ฉันคิดว่าฉันสามารถใช้อักขระตัวแรกของค่าฐานสิบหกเพื่อดึงสิ่งนี้ออก มันใช้งานได้ แต่ก็เปลี่ยนสี "อ่อน" ที่ถูกต้องด้วย

ฉันมีรหัสทำสิ่งนี้:

        if (lightcolor.substring(0,3) == "#00"|| lightcolor.substring(0,3) == "#010"){
            lightcolor="#FFFFFF";
            color=lightcolor;
        }

ต้องมีวิธีที่มีประสิทธิภาพมากขึ้นในการคำนวณเลขฐานสิบหกเพื่อที่จะรู้ว่าสีได้ไปไกลกว่าความมืดระดับหนึ่งหรือไม่? เช่นถ้า lightcolor + "some hex value" <= "some hex value" จากนั้นตั้งค่าเป็นสีขาว

ฉันได้เพิ่ม tinyColor ซึ่งอาจมีประโยชน์สำหรับสิ่งนี้ แต่ฉันไม่รู้แน่ชัด


1
คุณได้ลองใช้ตัวเลือกสีและตรวจสอบค่าต่างๆแล้วหรือยัง? ฉันสังเกตว่าเมื่อ R, G และ B ต่ำกว่า ~ 70 มันจะมืดลง นี่อาจไม่ใช่วิธีที่เหมาะสม แต่เป็นวิธีหนึ่ง
Rick Kuipers

1
ในขณะที่คุณใช้ tinyColor อยู่แล้วให้เปลี่ยนสีเป็นHSLและดูส่วนประกอบL 1 = ขาว, 0 = ดำ
Andreas

4
@Andreas ความสว่าง HSL ไม่ได้คำนึงถึงการรับรู้ของมนุษย์ ค่า L เท่ากับ 0.5 จะมีความสว่างที่รับรู้แตกต่างกันสำหรับเฉดสีที่ต่างกัน
Alnitak

1
@Alnitak คุณพูดถูก แต่คำอธิบายของ TO ไม่เป๊ะ ดังนั้นค่าใด ๆ ที่ต่ำกว่า 3/8 อาจมืดพอสำหรับจุดประสงค์ของเขา
Andreas

1
@Andreas ขึ้นอยู่กับ - ถ้าคุณดูที่ค่าความส่องสว่างของ ITU ในคำตอบของฉันคุณจะเห็นว่าสีน้ำเงินมีความสว่างเท่ากับสีเขียวเพียง 1/10
Alnitak

คำตอบ:


226

คุณต้องแยกส่วนประกอบ RGB ทั้งสามออกจากกันจากนั้นใช้สูตรมาตรฐานเพื่อแปลงค่า RGB ที่ได้เป็นค่าความสว่างที่รับรู้ได้

สมมติว่ามีอักขระหกสี:

var c = c.substring(1);      // strip #
var rgb = parseInt(c, 16);   // convert rrggbb to decimal
var r = (rgb >> 16) & 0xff;  // extract red
var g = (rgb >>  8) & 0xff;  // extract green
var b = (rgb >>  0) & 0xff;  // extract blue

var luma = 0.2126 * r + 0.7152 * g + 0.0722 * b; // per ITU-R BT.709

if (luma < 40) {
    // pick a different colour
}

แก้ไข

ตั้งแต่เดือนพฤษภาคม 2014 tinycolorมีgetBrightness()ฟังก์ชันนี้แล้วแม้ว่าจะใช้ปัจจัยการถ่วงน้ำหนัก CCIR601 แทน ITU-R ข้างต้น

แก้ไข

ช่วงค่าลูมาที่ได้คือ 0..255 โดยที่ 0 คือมืดที่สุดและ 255 เป็นค่าที่เบาที่สุด ค่ามากกว่า 128 tinycolorได้รับการพิจารณาโดยแสง (คัดลอกอย่างไร้ยางอายจากความคิดเห็นโดย @ pau.moreno และ @Alnitak)


12
ไม่เคยเห็นการจัดการบิตที่ดีในจาวาสคริปต์มาระยะหนึ่งแล้ว สิ่งที่เย็น. en.wikipedia.org/wiki/Rec._709#Luma_coefficients
jbabey

2
รหัสดี แต่หลังจากการทดสอบฉันแนะนำ var luma = (r + g + b) / 3; ถ้า (luma <128) {// จะมีประโยชน์มากขึ้น }
Terry Lin

2
@TerryLin ทำไม? ค่าสัมประสิทธิ์ที่ให้เป็นค่า ITU มาตรฐานที่อนุญาตให้รับรู้ว่าสีเขียวมีความสว่างมากกว่าสีแดง (แล้วจึงเป็นสีน้ำเงิน)
Alnitak

1
ส่งผลให้lumaช่วงค่าเป็น0..255ที่0เป็นที่มืดที่สุดและ255เป็นที่เบา (รวมสามสัมประสิทธิ์การอย่างใดอย่างหนึ่ง)
pau.moreno

1
@gabssnake ตั้งแต่เดือนพฤษภาคม 2014 เท่านั้นและisDark()ขีด จำกัด นั้นกำหนดไว้ที่ 128
Alnitak

21

TinyColorห้องสมุด (คุณได้กล่าวไว้ก่อนแล้ว) ให้การทำงานหลายอย่างสำหรับการตรวจสอบและจัดการสีในหมู่พวกเขา:

  • getBrightness

    ผลตอบแทนที่ได้รับรู้ความสว่างของสี 0-255 ตามที่กำหนดโดยWeb Content Accessibility แนวทาง (เวอร์ชั่น 1.0)

    tinycolor("#fff").getBrightness(); // 255
  • isLight

    ส่งคืนบูลีนที่ระบุว่าความสว่างที่รับรู้ของสีนั้นสว่างหรือไม่

    tinycolor("#fff").isLight(); // true
    tinycolor("#000").isLight(); // false
  • isDark

    ส่งคืนบูลีนที่ระบุว่าความสว่างที่รับรู้ของสีนั้นมืดหรือไม่

    tinycolor("#fff").isDark(); // false
    tinycolor("#000").isDark(); // true
  • getLuminance

    ผลตอบแทนที่ได้รับรู้ความสว่างของสี, 0-1 ตามที่กำหนดโดยWeb Content แนวทางการเข้าถึง (เวอร์ชั่น 2.0)

    tinycolor("#fff").getLuminance(); // 1

15

ฉันพบฟังก์ชัน WooCommerce Wordpress PHP ( wc_hex_is_light ) และฉันแปลงเป็น JavaScript ใช้ได้ดี!

function wc_hex_is_light(color) {
    const hex = color.replace('#', '');
    const c_r = parseInt(hex.substr(0, 2), 16);
    const c_g = parseInt(hex.substr(2, 2), 16);
    const c_b = parseInt(hex.substr(4, 2), 16);
    const brightness = ((c_r * 299) + (c_g * 587) + (c_b * 114)) / 1000;
    return brightness > 155;
}

1
สุดยอดมากขอบคุณ! ฉันทดสอบด้วยสีหลายสีการตรวจจับถูกต้องกับทุกสี :)
David Dal Busco

colorIsDarkOrLight (สี) {var hex = color.replace ("#", ""); var c_r, c_g, c_b, ความสว่าง = ""; ถ้า (hex.length == 3) {c_r = parseInt (hex.substr (0, 2), 16); c_g = parseInt (hex.substr (1, 2), 16); c_b = parseInt (hex.substr (2, 2), 16); ความสว่าง = (c_r * 299 + c_g * 587 + c_b * 114) / 1,000; } else {c_r = parseInt (hex.substr (0, 2), 16); c_g = parseInt (hex.substr (2, 2), 16); c_b = parseInt (hex.substr (4, 2), 16); } คืนความสว่าง> 155; },
Pedro Henrique

ใช้กับตัวอักษร hex 3 และ 6
Pedro Henrique

6

คุณสามารถคำนวณความสว่าง :

ความส่องสว่างจึงเป็นตัวบ่งชี้ว่าพื้นผิวจะสว่างเพียงใด

ดังนั้นจึงเป็นการดีที่จะเลือกว่าข้อความควรเป็นสีขาวหรือดำ

var getRGB = function(b){
    var a;
    if(b&&b.constructor==Array&&b.length==3)return b;
    if(a=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(b))return[parseInt(a[1]),parseInt(a[2]),parseInt(a[3])];
    if(a=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(b))return[parseFloat(a[1])*2.55,parseFloat(a[2])*2.55,parseFloat(a[3])*2.55];
    if(a=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(b))return[parseInt(a[1],16),parseInt(a[2],16),parseInt(a[3],
16)];
    if(a=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(b))return[parseInt(a[1]+a[1],16),parseInt(a[2]+a[2],16),parseInt(a[3]+a[3],16)];
    return (typeof (colors) != "undefined")?colors[jQuery.trim(b).toLowerCase()]:null
};

var luminance_get = function(color) {
    var rgb = getRGB(color);
    if (!rgb) return null;
        return 0.2126 * rgb[0] + 0.7152 * rgb[1] + 0.0722 * rgb[2];
}

วิธีการดังกล่าวข้างต้นจะช่วยให้คุณผ่านการสีในรูปแบบที่แตกต่างกัน luminance_getแต่ขั้นตอนวิธีการนั้นเป็นเพียงแค่ใน

ตอนที่ใช้ฉันตั้งค่าสีเป็นสีดำถ้าความสว่างมากกว่า180สีขาว


5

มีความแตกต่างที่สำคัญระหว่างความสว่างและความสว่าง ความส่องสว่างในตอนท้ายของวันเป็นการวัดปริมาณพลังงานที่เดินทางผ่านพื้นที่หนึ่ง ๆ และไม่สนใจว่าระบบการรับรู้ของเรารับรู้พลังงานนั้นอย่างไร ในทางกลับกันความสว่างเป็นการวัดว่าเรารับรู้พลังงานนั้นอย่างไรและคำนึงถึงความสัมพันธ์ระหว่างความส่องสว่างและระบบการรับรู้ของเรา (เพื่อให้เกิดความสับสนมีคำที่เรียกว่าความส่องสว่างสัมพัทธ์ซึ่งดูเหมือนว่าจะใช้ในคำพ้องความหมายกับความสว่างมันทำให้ฉันสะดุดใจ)

เพื่อความแม่นยำคุณกำลังมองหา "ความสว่าง" หรือ "ค่า" หรือ "ความสว่างที่ค่อนข้างชัดเจน" ตามที่คนอื่น ๆ แนะนำ คุณสามารถคำนวณสิ่งนี้ได้หลายวิธี (เช่นการเป็นมนุษย์!) http://en.wikipedia.org/wiki/HSL_and_HSV#Lightness

  1. ใช้ค่าสูงสุดของ R, G และ B
  2. หาค่าเฉลี่ยสูงสุดและค่าต่ำสุดจาก R, G และ B
  3. หาค่าเฉลี่ยของทั้งสามอย่าง
  4. ใช้ค่าเฉลี่ยถ่วงน้ำหนักตามที่คนอื่น ๆ แนะนำไว้ที่นี่

AFAIK มีเพียงการคำนวณลูมาที่อธิบายไว้ในหน้า Wikipedia เท่านั้นที่เป็นแบบจำลองตามการรับรู้
Alnitak

2
เป็นเรื่องดีที่จะชี้ให้เห็นถึงความแตกต่างระหว่างพลังงานแสงทางกายภาพและการรับรู้ความสว่าง แต่ฉันคิดว่าคุณมีหลายอย่างที่ค่อนข้างปนกัน ส่วนของบทความ Wikipedia ที่คุณเชื่อมโยงมีสัญลักษณ์แสดงหัวข้อย่อยที่สี่ซึ่งระบุว่า " ทางเลือกที่เกี่ยวข้องกับการรับรู้มากกว่าคือการใช้ luma, Y ′เป็นมิติความสว่าง" (ของฉันที่เน้น) จากนั้นจึงดำเนินการต่อเพื่อให้สูตรที่นำเสนอใน Alnitak และคำตอบของโรบิน กล่าวอีกนัยหนึ่งวิธีการที่คุณไม่ได้ใช้และแนะนำคือวิธีที่ตรงกับการรับรู้ของมนุษย์มากที่สุด
John Y

@ จอห์นใช่นั่นคือสิ่งที่ฉันพยายามจะพูด - เขาถูกทิ้งไว้เพียงคนเดียวที่ตรงกับคำตอบที่เหลือของเขา
Alnitak

ใช่ปรากฎว่าฉันเป็นคนเดียวที่สับสนที่นี่ ฉันไม่เป็นไร :) ฉันแค่อยากจะเข้าใจประเด็นสำคัญว่ามีความแตกต่างกันระหว่างพลังงานและการรับรู้ ฉันจะอัปเดตคำตอบของฉันตามลำดับ
David Nguyen

4

ทำงานกับ hex เช่น #fefefe

function isTooDark(hexcolor){
    var r = parseInt(hexcolor.substr(1,2),16);
    var g = parseInt(hexcolor.substr(3,2),16);
    var b = parseInt(hexcolor.substr(4,2),16);
    var yiq = ((r*299)+(g*587)+(b*114))/1000;
    // Return new color if to dark, else return the original
    return (yiq < 40) ? '#2980b9' : hexcolor;
}

คุณสามารถเปลี่ยนเป็นคืนtrueหรือfalseเปลี่ยนได้

return (yiq < 40) ? '#2980b9' : hexcolor;

ถึง

return (yiq < 40);

@ Vivek ว่าเพราะคุณจะต้องใช้ค่าฐานสิบหกเล่ม (# 000000 และ #ffffff)
TheCrazyProfessor

2

วิธีการแก้ปัญหาที่เป็นไปได้ที่จะแปลงสีจาก RGB เพื่อ HSB HSB ย่อมาจากสีความอิ่มตัวและความสว่าง (หรือที่เรียกว่า HSV โดยที่ V เป็นค่า) จากนั้นคุณมีเพียงพารามิเตอร์เดียวที่ต้องตรวจสอบ: ความสว่าง


1

ฉันรู้ว่าบทสนทนานี้มีอายุไม่กี่ปี แต่ก็ยังมีความเกี่ยวข้อง ฉันต้องการเพิ่มว่าทีมของฉันมีปัญหาเดียวกันใน Java (SWT) และพบว่าสิ่งนี้แม่นยำกว่าเล็กน้อย:

private Color getFontColor(RGB bgColor) {
    Color COLOR_BLACK = new Color(Display.getDefault(), 0, 0, 0);
    Color COLOR_WHITE = new Color(Display.getDefault(), 255, 255, 255);

    double luminance = Math.sqrt(0.241 
       * Math.pow(bgColor.red, 2) + 0.691 * Math.pow(bgColor.green, 2) +  0.068 
       * Math.pow(bgColor.blue, 2));
    if (luminance >= 130) {
        return COLOR_BLACK;
    } else {
        return COLOR_WHITE;
    }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.