Программно осветлить или затемнить шестнадцатеричный цвет (или RGB, и смешать цвета) - PullRequest
440 голосов
/ 06 апреля 2011

Вот функция, над которой я работал, чтобы программно осветлить или затемнить шестнадцатеричный цвет на определенную величину. Просто введите строку типа "3F6D2A" для цвета (col) и целое число base10 (amt) для количества, которое нужно осветлить или затемнить. Чтобы затемнить, передайте отрицательное число (т.е. -20).

Причина, по которой я это сделал, заключалась в том, что все решения, которые я нашел, до сих пор, казалось, слишком усложняли проблему. И у меня было ощущение, что это можно сделать всего несколькими строками кода. Пожалуйста, дайте мне знать, если вы обнаружите какие-либо проблемы или внесете какие-либо изменения, которые позволят ускорить его.

function LightenDarkenColor(col,amt) {
    col = parseInt(col,16);
    return (((col & 0x0000FF) + amt) | ((((col>> 8) & 0x00FF) + amt) << 8) | (((col >> 16) + amt) << 16)).toString(16);
}

Для разработки используйте здесь более легкую для чтения версию:

function LightenDarkenColor(col,amt) {
    var num = parseInt(col,16);
    var r = (num >> 16) + amt;
    var b = ((num >> 8) & 0x00FF) + amt;
    var g = (num & 0x0000FF) + amt;
    var newColor = g | (b << 8) | (r << 16);
    return newColor.toString(16);
}

И, наконец, версия для обработки цветов, которые могут (или не могут) иметь "#" в начале. Плюс настройка для неправильных значений цвета:

function LightenDarkenColor(col,amt) {
    var usePound = false;
    if ( col[0] == "#" ) {
        col = col.slice(1);
        usePound = true;
    }

    var num = parseInt(col,16);

    var r = (num >> 16) + amt;

    if ( r > 255 ) r = 255;
    else if  (r < 0) r = 0;

    var b = ((num >> 8) & 0x00FF) + amt;

    if ( b > 255 ) b = 255;
    else if  (b < 0) b = 0;

    var g = (num & 0x0000FF) + amt;

    if ( g > 255 ) g = 255;
    else if  ( g < 0 ) g = 0;

    return (usePound?"#":"") + (g | (b << 8) | (r << 16)).toString(16);
}

ОК, так что теперь это не просто пара строк, но кажется, что это намного проще, и если вы не используете "#" и вам не нужно проверять цвета вне диапазона, это всего лишь пара линий.

Если вы не используете "#", вы можете просто добавить его в код, например:

var myColor = "3F6D2A";
myColor = LightenDarkenColor(myColor,10);
thePlaceTheColorIsUsed = ("#" + myColor);

Я предполагаю, что мой главный вопрос, я прав здесь? Разве это не распространяется на некоторые (нормальные) ситуации?

Ответы [ 11 ]

839 голосов
/ 24 ноября 2012

Ну, этот ответ стал своим собственным зверем.Много новых версий, это было глупо долго.Большое спасибо всем великим авторам этого ответа.Но, чтобы все было просто для масс.Я заархивировал все версии / историю развития этого ответа на свой github .И все началось с новой версии StackOverflow.Особая благодарность Майку 'Pomax' Kamermans за эту версию.Он дал мне новую математику.


Эта функция (pSBC) будет принимать цвета HEX или RGB.pSBC может затенить его темнее или светлее или смешать со вторым цветом, а также может передать его прямо через него, но конвертировать из шестнадцатеричного в RGB (Hex2RGB) или из шестнадцатеричного RGB в RGB (RGB2Hex).И все без того, чтобы вы даже не знали, какой цветовой формат вы используете.

Это работает очень быстро, возможно, быстрее всего, особенно учитывая его многочисленные функции.Это было долгое время в процессе создания.Смотрите всю историю на моем github .Если вы хотите абсолютно наименьший и самый быстрый способ затенения или смешивания, посмотрите Микро-функции ниже и используйте одного из демонов скорости с 2-мя слоями.Они отлично подходят для интенсивной анимации, но эта версия достаточно быстра для большинства анимаций.

Эта функция использует Log Blending или Linear Blending.Тем не менее, он не конвертируется в HSL, чтобы правильно осветлить или затемнить цвет.Следовательно, результаты от этой функции будут отличаться от тех гораздо более крупных и более медленных функций, использующих HSL.

jsFiddle с pSBC

github> pSBC Wiki

Особенности:

  • Автоматически определяет и принимает стандартные шестнадцатеричные цвета в виде строк.Например: "#AA6622" или "#bb551144".
  • Автоматически определяет и принимает стандартные цвета RGB в виде строк.Например: "rgb(123,45,76)" или "rgba(45,15,74,0.45)".
  • Затенение цветов на белый или черный в процентах.
  • Смешивание цветов в процентах.
  • Преобразует ли Hex2RGB и RGB2Hex преобразование вв то же время или в одиночку.
  • Принимает трехзначные (или четырехзначные w / alpha) цветовые коды HEX в форме #RGB (или #RGBA).Это расширит их.Например: "#C41" становится "#CC4411".
  • Принимает и (линейно) смешивает альфа-каналы.Если у цвета c0 (from) или цвета c1 (to) есть альфа-канал, то возвращаемый цвет будет иметь альфа-канал.Если оба цвета имеют альфа-канал, то возвращаемый цвет будет представлять собой линейную смесь двух альфа-каналов с использованием заданного процента (как если бы это был обычный цветовой канал).Если только один из двух цветов имеет альфа-канал, эта альфа будет просто передана возвращаемому цвету.Это позволяет смешивать / затенять прозрачный цвет, сохраняя уровень прозрачности.Или, если уровни прозрачности также должны смешиваться, убедитесь, что оба цвета имеют альфа.Когда затенение, это пройдет альфа-канал прямо через.Если вам нужна базовая заливка, которая также затеняет альфа-канал, используйте rgb(0,0,0,1) или rgb(255,255,255,1) в качестве цвета c1 (to) (или их шестнадцатеричных эквивалентов).Для цветов RGB альфа-канал возвращаемого цвета будет округлен до 3 десятичных разрядов.
  • Преобразования RGB2Hex и Hex2RGB неявны при использовании смешивания.Независимо от цвета c0 (от);возвращаемый цвет всегда будет в формате цвета c1 (to), если он существует.Если цвет c1 (to) отсутствует, то передайте 'c' в качестве цвета c1, и он закрасит и преобразует цвет c0.Если требуется только преобразование, то передайте 0 в качестве процента (p).Если цвет c1 пропущен или передан ложный текст, он не будет преобразован.
  • В глобальную добавлена ​​также вторичная функция.pSBCr может быть передан цвет Hex или RGB, и он возвращает объект, содержащий эту информацию о цвете.Это в форме: {r: XXX, g: XXX, b: XXX, a: X.XXX}.Где .r, .g и .b имеют диапазон от 0 до 255. А когда нет альфа: .a равно -1.В противном случае: .a имеет диапазон от 0,000 до 1.000.
  • Для вывода RGB выводится rgba() более rgb(), когда цвет с альфа-каналом был передан в c0 (from) и / или c1 (to).
  • Добавлена ​​проверка незначительных ошибок.Это не идеально.Это все еще может привести к сбою или созданию тряски.Но это поймает некоторые вещи.По сути, если структура в некотором смысле неверна или процент не является числом или выходит за рамки, он вернет null.Пример: pSBC(0.5,"salt") == null, где, как он думает, #salt является допустимым цветом.Удалите четыре строки, которые заканчиваются return null;, чтобы удалить эту функцию и сделать ее быстрее и меньше.
  • Использует смешивание журналов.Передайте true in для l (4-й параметр) для использования линейного смешивания.

Код:

// Version 4.0
const pSBC=(p,c0,c1,l)=>{
    let r,g,b,P,f,t,h,i=parseInt,m=Math.round,a=typeof(c1)=="string";
    if(typeof(p)!="number"||p<-1||p>1||typeof(c0)!="string"||(c0[0]!='r'&&c0[0]!='#')||(c1&&!a))return null;
    if(!this.pSBCr)this.pSBCr=(d)=>{
        let n=d.length,x={};
        if(n>9){
            [r,g,b,a]=d=d.split(","),n=d.length;
            if(n<3||n>4)return null;
            x.r=i(r[3]=="a"?r.slice(5):r.slice(4)),x.g=i(g),x.b=i(b),x.a=a?parseFloat(a):-1
        }else{
            if(n==8||n==6||n<4)return null;
            if(n<6)d="#"+d[1]+d[1]+d[2]+d[2]+d[3]+d[3]+(n>4?d[4]+d[4]:"");
            d=i(d.slice(1),16);
            if(n==9||n==5)x.r=d>>24&255,x.g=d>>16&255,x.b=d>>8&255,x.a=m((d&255)/0.255)/1000;
            else x.r=d>>16,x.g=d>>8&255,x.b=d&255,x.a=-1
        }return x};
    h=c0.length>9,h=a?c1.length>9?true:c1=="c"?!h:false:h,f=pSBCr(c0),P=p<0,t=c1&&c1!="c"?pSBCr(c1):P?{r:0,g:0,b:0,a:-1}:{r:255,g:255,b:255,a:-1},p=P?p*-1:p,P=1-p;
    if(!f||!t)return null;
    if(l)r=m(P*f.r+p*t.r),g=m(P*f.g+p*t.g),b=m(P*f.b+p*t.b);
    else r=m((P*f.r**2+p*t.r**2)**0.5),g=m((P*f.g**2+p*t.g**2)**0.5),b=m((P*f.b**2+p*t.b**2)**0.5);
    a=f.a,t=t.a,f=a>=0||t>=0,a=f?a<0?t:t<0?a:a*P+t*p:0;
    if(h)return"rgb"+(f?"a(":"(")+r+","+g+","+b+(f?","+m(a*1000)/1000:"")+")";
    else return"#"+(4294967296+r*16777216+g*65536+b*256+(f?m(a*255):0)).toString(16).slice(1,f?undefined:-2)
}

Использование:

// Setup:

let color1 = "rgb(20,60,200)";
let color2 = "rgba(20,60,200,0.67423)";
let color3 = "#67DAF0";
let color4 = "#5567DAF0";
let color5 = "#F3A";
let color6 = "#F3A9";
let color7 = "rgb(200,60,20)";
let color8 = "rgba(200,60,20,0.98631)";

// Tests:

/*** Log Blending ***/
// Shade (Lighten or Darken)
pSBC ( 0.42, color1 ); // rgb(20,60,200) + [42% Lighter] => rgb(166,171,225)
pSBC ( -0.4, color5 ); // #F3A + [40% Darker] => #c62884
pSBC ( 0.42, color8 ); // rgba(200,60,20,0.98631) + [42% Lighter] => rgba(225,171,166,0.98631)

// Shade with Conversion (use "c" as your "to" color)
pSBC ( 0.42, color2, "c" ); // rgba(20,60,200,0.67423) + [42% Lighter] + [Convert] => #a6abe1ac

// RGB2Hex & Hex2RGB Conversion Only (set percentage to zero)
pSBC ( 0, color6, "c" ); // #F3A9 + [Convert] => rgba(255,51,170,0.6)

// Blending
pSBC ( -0.5, color2, color8 ); // rgba(20,60,200,0.67423) + rgba(200,60,20,0.98631) + [50% Blend] => rgba(142,60,142,0.83)
pSBC ( 0.7, color2, color7 ); // rgba(20,60,200,0.67423) + rgb(200,60,20) + [70% Blend] => rgba(168,60,111,0.67423)
pSBC ( 0.25, color3, color7 ); // #67DAF0 + rgb(200,60,20) + [25% Blend] => rgb(134,191,208)
pSBC ( 0.75, color7, color3 ); // rgb(200,60,20) + #67DAF0 + [75% Blend] => #86bfd0

/*** Linear Blending ***/
// Shade (Lighten or Darken)
pSBC ( 0.42, color1, false, true ); // rgb(20,60,200) + [42% Lighter] => rgb(119,142,223)
pSBC ( -0.4, color5, false, true ); // #F3A + [40% Darker] => #991f66
pSBC ( 0.42, color8, false, true ); // rgba(200,60,20,0.98631) + [42% Lighter] => rgba(223,142,119,0.98631)

// Shade with Conversion (use "c" as your "to" color)
pSBC ( 0.42, color2, "c", true ); // rgba(20,60,200,0.67423) + [42% Lighter] + [Convert] => #778edfac

// RGB2Hex & Hex2RGB Conversion Only (set percentage to zero)
pSBC ( 0, color6, "c", true ); // #F3A9 + [Convert] => rgba(255,51,170,0.6)

// Blending
pSBC ( -0.5, color2, color8, true ); // rgba(20,60,200,0.67423) + rgba(200,60,20,0.98631) + [50% Blend] => rgba(110,60,110,0.83)
pSBC ( 0.7, color2, color7, true ); // rgba(20,60,200,0.67423) + rgb(200,60,20) + [70% Blend] => rgba(146,60,74,0.67423)
pSBC ( 0.25, color3, color7, true ); // #67DAF0 + rgb(200,60,20) + [25% Blend] => rgb(127,179,185)
pSBC ( 0.75, color7, color3, true ); // rgb(200,60,20) + #67DAF0 + [75% Blend] => #7fb3b9

/*** Other Stuff ***/
// Error Checking
pSBC ( 0.42, "#FFBAA" ); // #FFBAA + [42% Lighter] => null  (Invalid Input Color)
pSBC ( 42, color1, color5 ); // rgb(20,60,200) + #F3A + [4200% Blend] => null  (Invalid Percentage Range)
pSBC ( 0.42, {} ); // [object Object] + [42% Lighter] => null  (Strings Only for Color)
pSBC ( "42", color1 ); // rgb(20,60,200) + ["42"] => null  (Numbers Only for Percentage)
pSBC ( 0.42, "salt" ); // salt + [42% Lighter] => null  (A Little Salt is No Good...)

// Error Check Fails (Some Errors are not Caught)
pSBC ( 0.42, "#salt" ); // #salt + [42% Lighter] => #a5a5a500  (...and a Pound of Salt is Jibberish)

// Ripping
pSBCr ( color4 ); // #5567DAF0 + [Rip] => [object Object] => {'r':85,'g':103,'b':218,'a':0.941}

Рисунок ниже поможет показать разницу в двух методах наложения:


Микро-функции

Если вам действительно нужны скорость и размер, вам придется использовать RGB, а не HEX.RGB более прост и прост, HEX пишет слишком медленно и имеет слишком много разновидностей для простого двухстрочного (т. Е. Это может быть 3, 4, 6 или 8-значный код HEX).Вам также придется пожертвовать некоторыми функциями, без проверки ошибок, без HEX2RGB и RGB2HEX.Кроме того, вам нужно будет выбрать конкретную функцию (на основе ее имени ниже) для математики смешивания цветов, а также, если вы хотите, чтобы затемнение или смешивание.Эти функции поддерживают альфа-каналы.И когда оба входных цвета имеют альфы, они будут линейно смешаны.Если только у одного из двух цветов есть альфа, он передаст его прямо к полученному цвету.Ниже приведены две невероятно быстрые и небольшие функции вкладыша:

const RGB_Linear_Blend=(p,c0,c1)=>{
    var i=parseInt,r=Math.round,P=1-p,[a,b,c,d]=c0.split(","),[e,f,g,h]=c1.split(","),x=d||h,d=x?","+(!d?h:!h?d:r((parseFloat(d)*P+parseFloat(h)*p)*1000)/1000+")"):")";
    return"rgb"+(x?"a(":"(")+r(i(a[3]=="a"?a.slice(5):a.slice(4))*P+i(e[3]=="a"?e.slice(5):e.slice(4))*p)+","+r(i(b)*P+i(f)*p)+","+r(i(c)*P+i(g)*p)+d;
}

const RGB_Linear_Shade=(p,c)=>{
    var i=parseInt,r=Math.round,[a,b,c,d]=c.split(","),P=p<0,t=P?0:255*p,P=P?1+p:1-p;
    return"rgb"+(d?"a(":"(")+r(i(a[3]=="a"?a.slice(5):a.slice(4))*P+t)+","+r(i(b)*P+t)+","+r(i(c)*P+t)+(d?","+d:")");
}

const RGB_Log_Blend=(p,c0,c1)=>{
    var i=parseInt,r=Math.round,P=1-p,[a,b,c,d]=c0.split(","),[e,f,g,h]=c1.split(","),x=d||h,d=x?","+(!d?h:!h?d:r((parseFloat(d)*P+parseFloat(h)*p)*1000)/1000+")"):")";
    return"rgb"+(x?"a(":"(")+r((P*i(a[3]=="a"?a.slice(5):a.slice(4))**2+p*i(e[3]=="a"?e.slice(5):e.slice(4))**2)**0.5)+","+r((P*i(b)**2+p*i(f)**2)**0.5)+","+r((P*i(c)**2+p*i(g)**2)**0.5)+d;
}

const RGB_Log_Shade=(p,c)=>{
    var i=parseInt,r=Math.round,[a,b,c,d]=c.split(","),P=p<0,t=P?0:p*255**2,P=P?1+p:1-p;
    return"rgb"+(d?"a(":"(")+r((P*i(a[3]=="a"?a.slice(5):a.slice(4))**2+t)**0.5)+","+r((P*i(b)**2+t)**0.5)+","+r((P*i(c)**2+t)**0.5)+(d?","+d:")");
}

Хотите узнать больше?Прочитайте полную запись на github .

PT

(Ps. Если у кого-то есть математика для другого метода смешивания, пожалуйста, поделитесь.)

96 голосов
/ 23 ноября 2012

Я сделал решение, которое работает очень хорошо для меня:

function shadeColor(color, percent) {

    var R = parseInt(color.substring(1,3),16);
    var G = parseInt(color.substring(3,5),16);
    var B = parseInt(color.substring(5,7),16);

    R = parseInt(R * (100 + percent) / 100);
    G = parseInt(G * (100 + percent) / 100);
    B = parseInt(B * (100 + percent) / 100);

    R = (R<255)?R:255;  
    G = (G<255)?G:255;  
    B = (B<255)?B:255;  

    var RR = ((R.toString(16).length==1)?"0"+R.toString(16):R.toString(16));
    var GG = ((G.toString(16).length==1)?"0"+G.toString(16):G.toString(16));
    var BB = ((B.toString(16).length==1)?"0"+B.toString(16):B.toString(16));

    return "#"+RR+GG+BB;
}

Пример Lighten:

shadeColor("#63C6FF",40);

Пример Darken:

shadeColor("#63C6FF",-40);
4 голосов
/ 02 июня 2016

Это то, что я использовал, основываясь на вашей функции. Я предпочитаю использовать шаги над процентом, потому что это более интуитивно для меня.

Например, 20% от значения 200 синего цвета сильно отличается от 20% от значения 40 синего цвета.

В любом случае, вот моя модификация, спасибо за вашу оригинальную функцию.

function adjustBrightness(col, amt) {

    var usePound = false;

    if (col[0] == "#") {
        col = col.slice(1);
        usePound = true;
    }

    var R = parseInt(col.substring(0,2),16);
    var G = parseInt(col.substring(2,4),16);
    var B = parseInt(col.substring(4,6),16);

    // to make the colour less bright than the input
    // change the following three "+" symbols to "-"
    R = R + amt;
    G = G + amt;
    B = B + amt;

    if (R > 255) R = 255;
    else if (R < 0) R = 0;

    if (G > 255) G = 255;
    else if (G < 0) G = 0;

    if (B > 255) B = 255;
    else if (B < 0) B = 0;

    var RR = ((R.toString(16).length==1)?"0"+R.toString(16):R.toString(16));
    var GG = ((G.toString(16).length==1)?"0"+G.toString(16):G.toString(16));
    var BB = ((B.toString(16).length==1)?"0"+B.toString(16):B.toString(16));

    return (usePound?"#":"") + RR + GG + BB;

}
4 голосов
/ 07 января 2012

Я попробовал вашу функцию, и возникла небольшая ошибка: если какое-то окончательное значение 'r' состоит только из 1 цифры, результат будет выглядеть следующим образом: 'a0a0a', когда правильное значение равно, например, '0a0a0a'. Я просто быстро исправил это, добавив это вместо вашего возврата:

var rStr = (r.toString(16).length < 2)?'0'+r.toString(16):r.toString(16);
var gStr = (g.toString(16).length < 2)?'0'+g.toString(16):g.toString(16);
var bStr = (b.toString(16).length < 2)?'0'+b.toString(16):b.toString(16);

return (usePound?"#":"") + rStr + gStr + bStr;

Может быть, это не так хорошо, но это делает работу. Отличная функция, кстати. Как раз то, что мне было нужно. :)

4 голосов
/ 06 апреля 2011

ты думал о преобразовании rgb> hsl?тогда просто двигайте Светимость вверх и вниз?Вот как бы я поступил.

Быстрый просмотр некоторых алгоритмов дал мне следующие сайты.

PHP: http://serennu.com/colour/rgbtohsl.php

Javascript: http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript

РЕДАКТИРОВАТЬ вышеуказанная ссылка больше не действительна.Вы можете просмотреть git hub для источника страницы или gist

В качестве альтернативы может подойти другой StackOverflow вопрос .


Несмотря на то, что это неправильный выбор для ФП, ниже приводится пример кода, который я изначально предлагал.(Предполагая, что у вас есть функции преобразования rgb / hsl)

var SHADE_SHIFT_AMOUNT = 0.1; 

function lightenShade(colorValue)
{
    if(colorValue && colorValue.length >= 6)
    {
        var redValue = parseInt(colorValue.slice(-6,-4), 16);
        var greenValue = parseInt(colorValue.slice(-4,-2), 16);
        var blueValue = parseInt(colorValue.slice(-2), 16);

        var hsl = rgbToHsl(redValue, greenValue, blueValue);
        hsl[2]= Math.min(hsl[2] + SHADE_SHIFT_AMOUNT, 1);
        var rgb = hslToRgb(hsl[0], hsl[1], hsl[2]);
        return "#" + rgb[0].toString(16) + rgb[1].toString(16) + rgb[2].toString(16);
    }
    return null;
}

function darkenShade(colorValue)
{
    if(colorValue && colorValue.length >= 6)
    {
        var redValue = parseInt(colorValue.slice(-6,-4), 16);
        var greenValue = parseInt(colorValue.slice(-4,-2), 16);
        var blueValue = parseInt(colorValue.slice(-2), 16);

        var hsl = rgbToHsl(redValue, greenValue, blueValue);
        hsl[2]= Math.max(hsl[2] - SHADE_SHIFT_AMOUNT, 0);
        var rgb = hslToRgb(hsl[0], hsl[1], hsl[2]);
        return "#" + rgb[0].toString(16) + rgb[1].toString(16) + rgb[2].toString(16);
    }
    return null;
}

Это предполагает:

  1. У вас есть функции hslToRgb и rgbToHsl.
  2. ПараметрcolorValue - это строка в форме # RRGGBB

Хотя, если мы обсуждаем css, существует синтаксис для указания hsl / hsla для IE9 /Chrome / Firefox.

2 голосов
/ 07 марта 2018

Я хотел изменить цвет на определенный уровень яркости - независимо от того, какая яркость был раньше - вот простая функция JS, которая, кажется, работает хорошо, хотя я уверен, что она может быть короче

function setLightPercentage(col: any, p: number) {
    const R = parseInt(col.substring(1, 3), 16);
    const G = parseInt(col.substring(3, 5), 16);
    const B = parseInt(col.substring(5, 7), 16);
    const curr_total_dark = (255 * 3) - (R + G + B);

    // calculate how much of the current darkness comes from the different channels
    const RR = ((255 - R) / curr_total_dark);
    const GR = ((255 - G) / curr_total_dark);
    const BR = ((255 - B) / curr_total_dark);

    // calculate how much darkness there should be in the new color
    const new_total_dark = ((255 - 255 * (p / 100)) * 3);

    // make the new channels contain the same % of available dark as the old ones did
    const NR = 255 - Math.round(RR * new_total_dark);
    const NG = 255 - Math.round(GR * new_total_dark);
    const NB = 255 - Math.round(BR * new_total_dark);

    const RO = ((NR.toString(16).length === 1) ? "0" + NR.toString(16) : NR.toString(16));
    const GO = ((NG.toString(16).length === 1) ? "0" + NG.toString(16) : NG.toString(16));
    const BO = ((NB.toString(16).length === 1) ? "0" + NB.toString(16) : NB.toString(16));

    return "#" + RO + GO + BO;}
1 голос
/ 22 февраля 2017

Следующий метод позволит вам осветлить или затемнить значение экспозиции шестнадцатеричной (шестнадцатеричной) цветовой строки:

private static string GetHexFromRGB(byte r, byte g, byte b, double exposure)
{
    exposure = Math.Max(Math.Min(exposure, 1.0), -1.0);
    if (exposure >= 0)
    {
        return "#"
            + ((byte)(r + ((byte.MaxValue - r) * exposure))).ToString("X2")
            + ((byte)(g + ((byte.MaxValue - g) * exposure))).ToString("X2")
            + ((byte)(b + ((byte.MaxValue - b) * exposure))).ToString("X2");
    }
    else
    {
        return "#"
            + ((byte)(r + (r * exposure))).ToString("X2")
            + ((byte)(g + (g * exposure))).ToString("X2")
            + ((byte)(b + (b * exposure))).ToString("X2");
    }

}

Для последнего значения параметра в GetHexFromRGB () передайте где-нибудь двойное значениеот -1 до 1 (-1 черный, 0 неизменен, 1 белый):

// split color (#e04006) into three strings
var r = Convert.ToByte("e0", 16);
var g = Convert.ToByte("40", 16);
var b = Convert.ToByte("06", 16);

GetHexFromRGB(r, g, b, 0.25);  // Lighten by 25%;
1 голос
/ 24 сентября 2014

C # версия ... обратите внимание, что я получаю цветные строки в этом формате # FF12AE34, и мне нужно вырезать # FF.

    private string GetSmartShadeColorByBase(string s, float percent)
    {
        if (string.IsNullOrEmpty(s))
            return "";
        var r = s.Substring(3, 2);
        int rInt = int.Parse(r, NumberStyles.HexNumber);
        var g = s.Substring(5, 2);
        int gInt = int.Parse(g, NumberStyles.HexNumber);
        var b = s.Substring(7, 2);
        int bInt = int.Parse(b, NumberStyles.HexNumber);

        var t = percent < 0 ? 0 : 255;
        var p = percent < 0 ? percent*-1 : percent;

        int newR = Convert.ToInt32(Math.Round((t - rInt) * p) + rInt);
        var newG = Convert.ToInt32(Math.Round((t - gInt) * p) + gInt);
        var newB = Convert.ToInt32(Math.Round((t - bInt) * p) + bInt);

        return String.Format("#{0:X2}{1:X2}{2:X2}", newR, newG, newB);
    }
0 голосов
/ 29 августа 2017

Я давно хотел иметь возможность создавать оттенки / оттенки цветов, вот мое решение JavaScript:

const varyHue = function (hueIn, pcIn) {
    const truncate = function (valIn) {
        if (valIn > 255) {
            valIn = 255;
        } else if (valIn < 0)  {
            valIn = 0;
        }
        return valIn;
    };

    let red   = parseInt(hueIn.substring(0, 2), 16);
    let green = parseInt(hueIn.substring(2, 4), 16);
    let blue  = parseInt(hueIn.substring(4, 6), 16);
    let pc    = parseInt(pcIn, 10);    //shade positive, tint negative
    let max   = 0;
    let dif   = 0;

    max = red;

    if (pc < 0) {    //tint: make lighter
        if (green < max) {
            max = green;
        }

        if (blue < max) {
            max = blue;
        }

        dif = parseInt(((Math.abs(pc) / 100) * (255 - max)), 10);

        return leftPad(((truncate(red + dif)).toString(16)), '0', 2)  + leftPad(((truncate(green + dif)).toString(16)), '0', 2) + leftPad(((truncate(blue + dif)).toString(16)), '0', 2);
    } else {    //shade: make darker
        if (green > max) {
            max = green;
        }

        if (blue > max) {
            max = blue;
        }

        dif = parseInt(((pc / 100) * max), 10);

        return leftPad(((truncate(red - dif)).toString(16)), '0', 2)  + leftPad(((truncate(green - dif)).toString(16)), '0', 2) + leftPad(((truncate(blue - dif)).toString(16)), '0', 2);
    }
};
0 голосов
/ 17 января 2017

Я сделал порт превосходной библиотеки xcolor, чтобы удалить ее зависимость от jQuery.Там есть множество функций, включая светлые и темные цвета.

Действительно, преобразование гекса в RGB - это совершенно отдельная функция от осветления или затемнения цветов.Держите вещи сухими, пожалуйста.В любом случае, если у вас есть цвет RGB, вы можете просто добавить разницу между желаемым уровнем освещения и уровнем освещения для каждого из значений RGB:

var lightness = function(level) {
    if(level === undefined) {
        return Math.max(this.g,this.r,this.b)
    } else {
        var roundedLevel = Math.round(level) // fractions won't work here
        var levelChange = roundedLevel - this.lightness()

        var r = Math.max(0,this.r+levelChange)
        var g = Math.max(0,this.g+levelChange)
        var b = Math.max(0,this.b+levelChange)

        if(r > 0xff) r = 0xff
        if(g > 0xff) g = 0xff
        if(b > 0xff) b = 0xff

        return xolor({r: r, g: g, b: b})
    }
}

var lighter = function(amount) {
    return this.lightness(this.lightness()+amount)
}

См. https://github.com/fresheneesz/xolor для большего количества источника.

...