Programowo rozjaśnij lub przyciemnij kolor heksadecymalny (lub rgb i mieszaj kolory)

503

Oto funkcja, nad którą pracowałem, aby programowo rozjaśnić lub przyciemnić kolor heksadecymalny o określoną wartość. Wystarczy podać ciąg znaków jak "3F6D2A"dla color ( col) i liczbę całkowitą base10 ( amt) dla ilości rozjaśnienia lub przyciemnienia. Aby przyciemnić, podaj liczbę ujemną (tj -20.).

Powodem, dla którego to zrobiłem, były wszystkie znalezione przeze mnie rozwiązania, które jak dotąd wydawały się nadmiernie komplikować problem. I miałem wrażenie, że można to zrobić za pomocą zaledwie kilku linii kodu. Daj mi znać, jeśli znajdziesz jakieś problemy lub masz jakieś poprawki, aby to przyspieszyć.

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


// TEST
console.log( LightenDarkenColor("3F6D2A",40) );

Do użytku programistycznego tutaj jest łatwiejsza do odczytania wersja:

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


// TEST
console.log(LightenDarkenColor("3F6D2A", -40));

I wreszcie wersja do obsługi kolorów, które mogą (ale nie muszą) mieć na początku „#”. Plus dostosowanie do niewłaściwych wartości kolorów:

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

OK, więc teraz nie jest to tylko kilka linii, ale wydaje się o wiele prostsze, a jeśli nie używasz „#” i nie musisz sprawdzać kolorów poza zakresem, to tylko kilka linii.

Jeśli nie używasz „#”, możesz po prostu dodać go w kodzie:

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

Myślę, że moje główne pytanie brzmi: czy mam rację tutaj? Czy nie obejmuje to niektórych (normalnych) sytuacji?

Pimp Trizkit
źródło
1
Jeśli nie uzyskasz oczekiwanych rezultatów podczas modyfikowania kolorów, sugeruję zajrzenie do przestrzeni kolorów LAB, która jest bliższa ludzkiej wizji. Wiele języków ma biblioteki do konwersji. Z mojego doświadczenia wynika, że ​​szczególnie odcienie pomarańczy mogą być problematyczne podczas przyciemniania lub rozjaśniania.
Henrik,
Bardzo dobra uwaga. Jednak głównym celem tego pytania było znalezienie, po pierwsze, najszybszego czasu działania i formuły o najmniejszym rozmiarze ... a po drugie, jego dokładności. Dlatego dlaczego nie miałem do czynienia z przejściem na HSL lub cokolwiek innego. Tutaj ważniejsza jest szybkość i rozmiar. Ale, jak widać z moją wersją 2 formuły. Zastosowanie LERP do zacienienia da przyjemne pomarańcze w całym zakresie odcieni. Spójrz na poniższą tabelę kolorów i daj mi znać, czy ten zakres odcieni nie jest zbyt bliski rzeczywistej dokładności.
Pimp Trizkit
Trochę się myliłem ze strukturą tutaj, ale masz rację, pomarańczowe poziomy dla shadowColor1 wydają się być bardzo dobre.
Henrik,
Lol, masz na myśli shadowColor2. Myślę, że struktura, o której mówisz, to ogólny układ samej odpowiedzi? Masz jakieś wskazówki, aby wyjaśnić?
Pimp Trizkit
3
Jest tylko jeden problem w funkcji z # powyżej, że nie tworzy ona wiodących zer, jeśli końcowy kod szesnastkowy zaczyna się od zer. Na przykład, jeśli kod szesnastkowy to # 00a6b7, wyświetli go jako # a6b7, co nie będzie działać, jeśli zostanie użyty jako css. Możesz to poprawić, zastępując wiersz powrotu tym: var string = "000000" + (g | (b << 8) | (r << 16)). ToString (16); return (usePound? "#": "") + string.substr (string.length-6);
Rafael Levy

Odpowiedzi:

876

Ta odpowiedź stała się własną bestią. Wiele nowych wersji robiło się głupio długo. Ogromne podziękowania dla wszystkich bardzo wielu autorów tej odpowiedzi. Ale dla uproszczenia dla mas. Zarchiwizowałem wszystkie wersje / historię ewolucji tej odpowiedzi na moim githubie . I zaczął to od nowa w StackOverflow tutaj z najnowszą wersją. Specjalne podziękowania należą się Mike'owi „Pomax” Kamermansowi za tę wersję. Dał mi nową matematykę.


Ta funkcja ( pSBC) przyjmuje kolor WWW HEX lub RGB. pSBCmoże przyciemnić go ciemniej lub jaśniej lub zmieszać go z drugim kolorem, a także przesłać go od razu, ale konwertować z Hex na RGB (Hex2RGB) lub RGB na Hex (RGB2Hex). Wszystko to bez Twojej wiedzy na temat używanego formatu kolorów.

Działa to naprawdę szybko, prawdopodobnie najszybciej, zwłaszcza biorąc pod uwagę jego wiele funkcji. Trwało to długo. Zobacz całą historię na moim githubie . Jeśli chcesz mieć absolutnie najmniejszy i najszybszy możliwy sposób cieniowania lub łączenia, zapoznaj się z poniższymi funkcjami Micro i użyj jednego z 2-liniowych demonów prędkości. Świetnie nadają się do intensywnych animacji, ale ta wersja tutaj jest wystarczająco szybka dla większości animacji.

Ta funkcja wykorzystuje mieszanie logów lub liniowe. Jednak NIE konwertuje on na HSL, aby właściwie rozjaśnić lub przyciemnić kolor. Dlatego wyniki tej funkcji będą się różnić od znacznie większych i wolniejszych funkcji korzystających z HSL.

jsFiddle z pSBC

github> Wiki pSBC

Funkcje:

  • Automatycznie wykrywa i akceptuje standardowe kolory Hex w postaci łańcuchów. Na przykład: "#AA6622"lub "#bb551144".
  • Automatycznie wykrywa i akceptuje standardowe kolory RGB w postaci łańcuchów. Na przykład: "rgb(123,45,76)"lub "rgba(45,15,74,0.45)".
  • Odcienia kolory na biały lub czarny w procentach.
  • Łączy kolory razem w procentach.
  • Czy konwersja Hex2RGB i RGB2Hex w tym samym czasie lub solo.
  • Akceptuje 3-cyfrowe (lub 4-cyfrowe w / alfa) kolorowe kody HEX, w formie #RGB (lub #RGBA). Rozszerzy je. Na przykład: "#C41"staje się "#CC4411".
  • Akceptuje i (liniowy) łączy kanały alfa. Jeśli c0kolor (z) lub c1(do) ​​ma kanał alfa, wówczas zwracany kolor będzie miał kanał alfa. Jeśli oba kolory mają kanał alfa, wówczas zwracany kolor będzie liniowym połączeniem dwóch kanałów alfa z wykorzystaniem podanego procentu (tak jakby to był normalny kanał koloru). Jeśli tylko jeden z dwóch kolorów ma kanał alfa, ta alfa zostanie po prostu przekazana do zwracanego koloru. Umożliwia to mieszanie / cieniowanie przezroczystego koloru przy zachowaniu poziomu przezroczystości. Lub, jeśli poziomy przezroczystości również powinny się mieszać, upewnij się, że oba kolory mają alfy. Podczas cieniowania przejdzie kanał alfa prosto przez. Jeśli chcesz podstawowego cieniowania, które również zacienia kanał alfa, użyj rgb(0,0,0,1)lub rgb(255,255,255,1)jako własnegoc1(do) ​​kolor (lub ich odpowiedniki szesnastkowe). W przypadku kolorów RGB kanał alfa zwracanego koloru zostanie zaokrąglony do 3 miejsc po przecinku.
  • Konwersje RGB2Hex i Hex2RGB są niejawne podczas korzystania z mieszania. Niezależnie od c0(z) koloru; zwracany kolor będzie zawsze w formacie koloru c1(do) ​​koloru, jeśli taki istnieje. Jeśli nie ma c1koloru (do), wprowadź go 'c'jako c1kolor, a będzie cieniował i przekształcał niezależnie od c0koloru. Jeśli pożądana jest tylko konwersja, należy również podać 0wartość procentową ( p). Jeśli c1kolor zostanie pominięty lub nie stringzostanie przekazany żaden element , nie zostanie on przekonwertowany.
  • Druga funkcja jest również dodawana do globalnej. pSBCrmożna przekazać kolor Hex lub RGB i zwraca obiekt zawierający tę informację o kolorze. Ma postać: {r: XXX, g: XXX, b: XXX, a: X.XXX}. Gdzie .r, .gi .bmają zakres od 0 do 255. A gdy nie ma alfa: .awynosi -1. W przeciwnym razie: .ama zakres od 0,000 do 1,000.
  • W przypadku wyjścia RGB, sygnał wyjściowy rgba()kończy się, rgb()gdy kolor z kanałem alfa został przekazany do c0(od) i / lub c1(do).
  • Drobne sprawdzanie błędów zostało dodane. To nie jest idealne. Nadal może powodować awarie lub tworzyć szczypce. Ale to coś złapie. Zasadniczo, jeśli struktura jest w jakiś sposób niepoprawna lub jeśli wartość procentowa nie jest liczbą lub jest poza zakresem, zostanie ona zwrócona null. Przykład: pSBC(0.5,"salt") == nullgdzie, jak myśli, #saltjest prawidłowy kolor. Usuń cztery linie, które kończą się, return null;aby usunąć tę funkcję i uczynić ją szybszą i mniejszą.
  • Używa mieszania dziennika. Przekaż truedla l(czwarty parametr), aby użyć mieszania liniowego.

Kod:

// 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=this.pSBCr(c0),P=p<0,t=c1&&c1!="c"?this.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)
}

Stosowanie:

// 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}

Poniższy obrazek pomoże pokazać różnicę w dwóch metodach mieszania:


Funkcje mikro

Jeśli naprawdę chcesz prędkości i rozmiaru, będziesz musiał użyć RGB, a nie HEX. RGB jest prostszy i prostszy, HEX pisze zbyt wolno i występuje w zbyt wielu odmianach dla prostego dwuliniowego (IE. Może to być 3, 4, 6 lub 8 cyfrowy kod HEX). Będziesz także musiał poświęcić niektóre funkcje, bez sprawdzania błędów, bez HEX2RGB ani RGB2HEX. Musisz także wybrać konkretną funkcję (na podstawie jej nazwy poniżej) dla matematyki mieszania kolorów, a jeśli chcesz cieniować lub mieszać. Te funkcje obsługują kanały alfa. A gdy oba kolory wejściowe mają litery, będzie je liniowo mieszać. Jeśli tylko jeden z dwóch kolorów ma alfa, przekaże go bezpośrednio do uzyskanego koloru. Poniżej znajdują się dwie funkcje liniowe, które są niezwykle szybkie i małe:

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,j=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)+j;
}

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,j=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)+j;
}

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:")");
}

Chcesz więcej informacji? Przeczytaj pełny tekst na github .

PT

(Ps Jeśli ktoś ma matematykę do innej metody mieszania, proszę się podzielić.)

Pimp Trizkit
źródło
8
Wersja PHP dla tych, którzy jej potrzebują: gist.github.com/chaoszcat/5325115#file-gistfile1-php
Lionel Chan
27
Użyłem TinyColor -tinycolor.darken(color,amount);
FWrnr
4
Świetny post ... :) ... właśnie utworzyłem jego szybkie rozszerzenie: gist.github.com/matejukmar/1da47f7a950d1ba68a95
Matej Ukmar
2
Oto wersja PHP zaktualizowanej wersji shadowColor2: function shadeColor2($color, $percent) { $color = str_replace("#", "", $color); $t=$percent<0?0:255; $p=$percent<0?$percent*-1:$percent; $RGB = str_split($color, 2); $R=hexdec($RGB[0]); $G=hexdec($RGB[1]); $B=hexdec($RGB[2]); return '#'.substr(dechex(0x1000000+(round(($t-$R)*$p)+$R)*0x10000+(round(($t-$G)*$p)+$G)*0x100+(round(($t-$B)*$p)+$B)),1); }
Kevin M
2
Przepraszam, najwyraźniej przegapiłem ten punkt. Mogą być dwa powody. Pierwszym i oczywistym jest to, że używam Math.Round i nie używasz liczb dziesiętnych do dokładnego kolorowania (kolory nie mają miejsc dziesiętnych w heksie). Na przykład, jeśli czerwony kanał to 8, dodaj 10%, do 8.8którego rundy 9. Następnie 9.09%od 9i masz 8.1819. Które zaokrągla do, 8więc to zły przykład. Ale nadal pokazuje, że pacjent 9.09%o 9nie 8.8. Może więc być tam kilka liczb, które nie zaokrąglają dokładnie tego samego, co mój przykład tutaj.
Pimp Trizkit,
121

Stworzyłem rozwiązanie, które działa dla mnie bardzo dobrze:

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

Przykład rozjaśnienia:

shadeColor("#63C6FF",40);

Przykład przyciemnienia:

shadeColor("#63C6FF",-40);
Pablo
źródło
4
Fajnie, podoba mi się procent! +1 Tho, bym mógł zrobić R = ((R<255)?R:255).toString(16);następnie R = R.length==1 ? "0"+R : Rdo prędkości. I nie jestem pewien, o co chodzi z toUpperCase?
Pimp Trizkit
To jest niepotrzebne. Dodam to tylko do ładnego wydruku podczas testu. Zmienię to.
Pablo
Bardzo dobrze. Czy jednak 100% jaśniejsze nie powinno stać się całkowicie białe, a 100% ciemne zawsze czarne, bez względu na kolor? wydaje się, że -100 powoduje, że dowolny kolor jest czarny, ale 100 (dodatni) nie czyni go całkowicie białym.
Kevin M
4
nie działa z jednolitymi kolorami, takimi jak # ff0000, # 00ff00, # 0000ff
Hitori
Aby to działało z czarnym kolorem właśnie zrobiłem ten hack var R = parseInt(color.substring(1, 3), 16) var G = parseInt(color.substring(3, 5), 16) var B = parseInt(color.substring(5, 7), 16) if (R == 0) R = 32; if (G == 0) G = 32; if (B == 0) B = 32;
Irfan Raza
20

Oto super prosta liniówka oparta na odpowiedzi Erica

function adjust(color, amount) {
    return '#' + color.replace(/^#/, '').replace(/../g, color => ('0'+Math.min(255, Math.max(0, parseInt(color, 16) + amount)).toString(16)).substr(-2));
}

Przykłady:

adjust('#ffffff', -20) => "#ebebeb"
adjust('000000', 20) => "#141414"
supersan
źródło
7
„super proste”.
Andrew
5

Tego użyłem na podstawie twojej funkcji. Wolę używać kroków powyżej wartości procentowej, ponieważ jest to dla mnie bardziej intuicyjne.

Na przykład 20% z 200 niebieskich wartości różni się znacznie od 20% z 40 niebieskich wartości.

Tak czy inaczej, oto moja modyfikacja, dzięki za oryginalną funkcję.

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;

}
Eric Sloan
źródło
Okazało się to o wiele bardziej przydatne niż górna odpowiedź, ponieważ najwyższa odpowiedź sprawiła, że ​​moje kolory były bardzo intensywne, a nie tylko ciemniejsze. Pozdrawiam, Eric
Worm
4

Wypróbowałem twoją funkcję i wystąpił mały błąd: jeśli jakaś końcowa wartość „r” ma tylko 1 cyfrę, pojawia się wynik: „a0a0a”, gdy poprawną wartością jest na przykład „0a0a0a”. Właśnie to naprawiłem, dodając to zamiast twojego zwrotu:

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;

Może to nie jest takie miłe, ale działa. Świetna funkcja, BTW. Dokładnie to, czego potrzebowałem. :)

Cool Acid
źródło
1
Dzięki za debugowanie i komplement! Szkoda, że ​​nie jest to odpowiedź na pytanie, czy istnieje szybszy sposób, co jest moim głównym pytaniem. Być może używa wszystkich konwersji szesnastkowych i bez konwersji bazowej. Myślę, że powiedziałeś mi, czy mam poprawny kod (+1). Niestety poprawka dodała znacznie więcej narzutu (teraz twoje wywołanie do Tringa 6 razy) i nieco mniej KISS. Być może szybciej byłoby sprawdzić, czy liczba base10 to 15 lub mniej, przed konwersją base16. Ale podoba mi się!
Pimp Trizkit
4

myślałeś o konwersji rgb> hsl? to po prostu przesuwaj Luminosity w górę i w dół? w ten sposób bym poszedł.

Szybki przegląd niektórych algorytmów dał mi następujące strony.

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

EDYTUJ powyższy link nie jest już ważny. Możesz wyświetlić git hub dla źródła strony lub gist

Alternatywnie, dobrym pytaniem może być inne pytanie StackOverflow .


Mimo, że nie jest to właściwy wybór dla OP, poniżej podano przybliżenie kodu, który pierwotnie sugerowałem. (Zakładając, że masz funkcje konwersji 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;
}

Zakłada to:

  1. Masz funkcje hslToRgbi rgbToHsl.
  2. Parametr colorValuejest łańcuchem w postaci #RRGGBB

Chociaż, jeśli dyskutujemy o css, istnieje składnia określająca hsl / hsla dla IE9 / Chrome / Firefox.

James Khoury
źródło
Ciekawe, ale czy nie musiałbym konwertować z ciągu szesnastkowego na rgb na hsl? Wydaje się, że jest to bardziej skomplikowane. Może coś mi umknęło. Ale szukam sposobu KISS, aby to zrobić, tak szybko, jak to możliwe (czas wykonania). Czuję się idealnie, gdybym mógł zrobić to wszystko na hexie, byłoby to najszybsze. Ale rozwiązanie, które tutaj opracowałem, polega na przejściu do rgb, aby móc dodać kwotę przyrostową.
Pimp Trizkit
Tak, zakładam, że byłoby to wolniejsze, bardziej skomplikowane, a jeśli nie użyjesz konwersji rgb na hsl nigdzie indziej, prawdopodobnie nie byłoby to najprostsze rozwiązanie. Byłoby to jednak dokładniejsze niż dodawanie wartości rgb, chociaż sam nie jestem osobą bardzo kolorową. Wszystko zależy od tego, jak dokładny chcesz być.
James Khoury,
Jaką wspomnianą utratę dokładności? Zakładam, że masz na myśli, że wszystkie kolory [web] nie są osiągalne za pomocą rgb czy coś takiego?
Pimp Trizkit
Jak powiedziałem, nie wiem zbyt wiele o kolorze: wiki Teoria kolorów
James Khoury
@Pimp Trizkit: Jest mniej dokładny, ponieważ (a to tylko moja teoria ... nie jestem ekspertem od kolorów) przesuwasz każdy kanał o tę samą wartość, bez względu na to, ile tego koloru był na początku. I pomyśleć , że spowodowałoby zmniejszenie nasycenia, ponieważ jesteś przynosząc kanały bliżej siebie (w procentach). Oczywiście, jeśli przepełnienie / niedopełnienie jest i tak nieuniknione.
Matthew Crumley,
2

Wersja C # ... zauważ, że otrzymuję ciągi kolorów w tym formacie # FF12AE34, i muszę wyciąć #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);
    }
użytkownik1618171
źródło
5
Nigdy wcześniej nie używałem C #, ale wygląda na to, że ostatnie trzy deklaracje zmiennych są dziwne. intI dwa varsdla tego samego typu danych.
Pimp Trizkit,
4
Słowo kluczowe var w języku C # oznacza, że ​​kompilator może wnioskować o typie podczas kompilacji. Tak więc w powyższym przykładzie int i var definiują zmienną tego samego typu - int. Jest to przydatne, jeśli masz długą nazwę typu lub chcesz odwołać się do typu anonimowego. To dziwne, ponieważ user1618171 ma mieszane dwa style deklaracji zmiennych - prawdopodobnie literówkę.
Daniel James Bryars
2

Chciałem zmienić kolor na określony poziom jasności - bez względu na to, jaka była wcześniej jasność koloru - oto prosta funkcja JS, która wydaje się działać dobrze, chociaż jestem pewien, że może być krótsza

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;}
Torbjörn Josefsson
źródło
Coolio! Zakładam, że pma zasięg 0-100? Nie wiem nawet, jak poprawnie zdefiniować jasność w RGB, to jest kwestia HSL. Na przykład jest #FF00FFjaśniejszy niż #FF0000? Jeśli tak, oznaczałoby to, że magenta jest dwa razy jaśniejsza niż czerwień. Dlatego stosuje się czysty czerwony test. Przepuść czystą czerwień #FF0000, ustaw 50% jasności, a oto dostajemy #FF4040, prawda? Domyślam się, że zrobimy czerwoną 50% jasnością, zrobilibyśmy się ciemniejsi, widząc, że jest już w pełni jasna .. tak jak w przypadku #800000150% jasności #FF8080. Czy różowy jest jaśniejszy czerwony? czy czerwony jest już w pełni jasny?
Pimp Trizkit
Masz rację - powinienem wspomnieć, że p musi być w zakresie 1-100!
Torbjörn Josefsson
# FF00FF ma 255 jako wartość w kanale czerwonym, 0 w kanale zielonym i 255 w kanale niebieskim. Im wyższe są połączone wartości w kanałach, tym wyższa jest jasność koloru. Liczba p oznacza, że ​​chcemy, aby nowy kolor był o 50% tak jasny, jak to możliwe. Nie jestem w 100% przekonany, że # FF4040 jest poprawną odpowiedzią na „50% jak najjaśniej czerwonego”. Wytwarzanie ciemniejszych odcieni (z w tym przypadku niższą wartością w kanale czerwonym) wymagałoby modyfikacji
Torbjörn Josefsson
Tak, właśnie zwracałem uwagę na dwuznaczność w mówieniu o jasności w RGB. W przypadku konwersji na HSL Lkanał ma dosłownie jasność. Moim [osobistym mentalnym] problemem jest to, że dla mnie #FF0000jest w pełni jasny. I #FF4040jest jaśniejszy, ale nie jaśniejszy ... dla mnie jaśniejszy oznacza bliżej bieli, tak jak różowy jest. A jasność jest tym, ile ma, a jego kolor jest całkowicie czerwony, więc czerwony jest w pełni jasny. Dlatego #FF0000nie można go rozjaśnić ... ale raczej ... jaśniej ... może jestem po prostu dziwakiem, lol !! Naprawdę nie znam teorii kolorów, więc, tak naprawdę mówię o moim ...
Pimp Trizkit
Ale wiem, że kiedy zmieniam jasność na monitorze, Czerwoni nie zmieniają koloru na różowy ... dla mnie. Prawdopodobnie w tym miejscu zacząłem logikę.
Pimp Trizkit
1

Poniższa metoda pozwala rozjaśnić lub przyciemnić wartość ekspozycji ciągu kolorów szesnastkowych (Hex):

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");
    }

}

Dla ostatniej wartości parametru w GetHexFromRGB () przekaż podwójną wartość gdzieś pomiędzy -1 a 1 (-1 to czarny, 0 to niezmieniony, 1 to biały):

// 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%;
Jason Williams
źródło
0

Jak prosty odcień koloru w PHP?

<?php
function shadeColor ($color='#cccccc', $percent=-25) {

  $color = Str_Replace("#",Null,$color);

  $r = Hexdec(Substr($color,0,2));
  $g = Hexdec(Substr($color,2,2));
  $b = Hexdec(Substr($color,4,2));

  $r = (Int)($r*(100+$percent)/100);
  $g = (Int)($g*(100+$percent)/100);
  $b = (Int)($b*(100+$percent)/100);

  $r = Trim(Dechex(($r<255)?$r:255));  
  $g = Trim(Dechex(($g<255)?$g:255));  
  $b = Trim(Dechex(($b<255)?$b:255));

  $r = ((Strlen($r)==1)?"0{$r}":$r);
  $g = ((Strlen($g)==1)?"0{$g}":$g);
  $b = ((Strlen($b)==1)?"0{$b}":$b);

  return (String)("#{$r}{$g}{$b}");
}

echo shadeColor(); // #999999
jsebestyan
źródło
To jest wersja php odpowiedzi Pablo. Niestety jest dłuższy i wolniejszy niż końcowe rozwiązanie i nie rozjaśnia dokładnie kolorów. Przyciemnia je dokładnie. Testuj na czystej czerwieni (# FF0000), rozjaśnienie 25% powinno wynosić (# FF4040). Sprawdź koniec mojej odpowiedzi na wersję końcową v2 Kevina M. w wersji PHP.
Pimp Trizkit
0

Zrobiłem port doskonałej biblioteki xcolor, aby usunąć jej zależność od jQuery. Istnieje mnóstwo funkcji, w tym rozjaśnianie i przyciemnianie kolorów.

Naprawdę, konwersja heksów na RGB jest całkowicie oddzielną funkcją od rozjaśniania lub przyciemniania kolorów. Proszę, zachowaj suchość. W każdym razie, gdy już masz kolor RGB, możesz po prostu dodać różnicę między pożądanym poziomem światła a poziomem światła, jaki masz do każdej z wartości 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)
}

Więcej informacji na https://github.com/fresheneesz/xolor .

BT
źródło
Nie analizowałem jeszcze kodu, który dotyczy mojego OP (prędkość / rozmiar / dokładność). Ale na początku należy przeczytać kilka uwag: 1) Zgadzam się, że konwersję heksadecymalnej na RGB można postrzegać jako całkowicie oddzielną funkcję. JEŻELI mój problem miał zostać rozwiązany za pomocą funkcji suchej, co nie było wymogiem. Chodziło tutaj o odpowiedź (patrz moja wersja 2), która była super szybka i bardzo malutka (2 linie!) I taka, która rozjaśniała i przyciemniała kolor heksadecymalny ... konkretnie ... jako samodzielny samodzielny funkcjonować. Tak, że w ostatecznym użyciu będzie to proste wywołanie jednej funkcji. <
Cd
2) A w przypadku wersji 3, według powszechnego zapotrzebowania, intencją jest posiadanie całkowicie niezależnej, uniwersalnej funkcji, tak szybko i tak małej, jak to możliwe, która może ślepo przyjmować kolor heksadecymalny lub RGB we wszystkich wariacje. Dlatego konieczna jest konwersja heksadecymatu na RGB. <cd.>
Pimp Trizkit
3) Po prostej analizie kodu. Wydaje się, że działałby znacznie wolniej i jest oczywiście znacznie większy niż moja wersja 2 (co jest prawdziwą odpowiedzią na mój OP; wersja 3 była dla mas). Szczerze mówiąc, powinienem porównać ten kod z moją wersją RGB 2, która nie dokonuje konwersji i wydaje się odpowiadać na twoje pytanie dotyczące suchości. I prawdę mówiąc, twój port nie jest dużo prostszy do zrozumienia niż mój 2 liniowiec dla heksów. Tak więc, chociaż jest to suszarka, wcale nie jest tak dużo, jeśli w ogóle, prostsze. (suchość niewiele pomogła w zrozumieniu) <cd.
Pimp Trizkit
4) Moja wersja RGB 2 to funkcja linii bez konwersji 2, jeśli tego chcesz. Moje szczególne rozwiązanie dla mojego oryginalnego OP chciał hex. Dlatego istnieją dwa różne typy wersji 2. Ale wspominasz o suchości i konwersji heksadecymalnej, więc teraz skupiamy się na wersji 3. Wersja 3 pojawiła się znacznie później; dopiero po tym, jak wersja 2 była popularna. <cd.>
Pimp Trizkit
5) Chociaż zgodzę się, że suchość ogólnie pomaga uniwersalności. I w większości przypadków dla zrozumienia. Niestety w tym przykładzie jest to kosztem. Koszty te polegają na tym, że jest on znacznie większy i pozornie znacznie wolniejszy i pozornie zużywa więcej pamięci zarówno na stosie (ze swoją charakterystyką rekurencyjną), jak i na poziomie globalnym (2 funkcje; w porównaniu z wersją v2).
Pimp Trizkit
0

Od dawna chciałem być w stanie tworzyć odcienie / odcienie kolorów, oto moje rozwiązanie 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);
    }
};
użytkownik2655360
źródło
Pomogą w tym niektóre przykłady użycia. I może jakieś wyjaśnienie, dlaczego ta wersja jest lepsza od innych. Ta wersja wydaje się działać znacznie wolniej. I to znacznie dłużej. I wydaje się, że nie zacienia dokładnie. Wygląda na to, że używasz LERP lub coś podobnego ... co jest dobre. Niestety, jest tylko z jednego kanału, więc ta sama wartość jest używana we wszystkich kanałach. To nie jest właściwe, aby uzyskać większą dokładność, LERP należy dla każdego kanału osobno. Tak jak moja odpowiedź na to pytanie. Plus jest mniejszy i szybszy, sprawdza błędy i obsługuje rgb i wykonuje konwersje, mógłbym kontynuować
Pimp Trizkit
Przykład użycia: replaceHue („6e124c”, 77), gdzie pierwszym argumentem jest kolor szesnastkowy, a drugim zmiana procentowa. Dodatnia zmiana procentowa powoduje przyciemnienie (przyciemnienie), a ujemna wartość powoduje przyciemnienie (rozjaśnienie) wyniku. Rutynę napisałem jako pierwszą próbę na kilka godzin przed wejściem na tę stronę i opublikowałem ją jako przedmiot zainteresowania. Nie wiedziałem, że muszę poprawić twój wysiłek lub że potrzebowałem twojej zgody przed tym. To całkowicie moja własna praca bez odniesienia do nikogo innego. Nie słyszałem o LERP. Sprawdzę to, dzięki za sugestię.
user2655360,
Hehe, oczywiście, że nie musisz nic robić! I wszyscy dziękujemy za wasze wysiłki! Moimi pierwszymi głównymi obawami były te wymienione na początku. Próbuję pomóc Ci w uzyskaniu odpowiedzi, aby uzyskać głosy. (pokaż zwyczaje i wyjaśnienie jak to działa, itp) Innych rzeczy jest oczywiście szybkie analizy służące dalszej każdy wiedzy. Przepraszam, jeśli wydawało się to nieco agresywne. Ale inną sugestią jest zaakceptowanie #kolorów heksadecymalnych. Przepraszam, jeśli wydawało się to… „zatwierdzeniem”… Widziałem to jako recenzję. Jeśli nie chcesz, aby ktoś analizował Twój kod lub udzielał opinii, przepraszam.
Pimp Trizkit
0

Twoje podejście jest w porządku :) Upraszczam trochę twoją najkrótszą wersję (w celu kontroli nasycenia zajrzyj tutaj )

(col,amt)=> (+('0x'+col)+amt*0x010101).toString(16).padStart(6,0)

I wersja ze sprawdzaniem # i zakresów kolorów

Kamil Kiełczewski
źródło
0

Zrobiłem też prosty pakiet. Użyłem wypukłości IR ^ 3, oczywiście wartości RGB są w IN ^ 3, co nie jest wypukłe, więc to nie jest naprawdę idealne

Aby przyciemnić, użyłem następujących

for (let i = 0; i < rgb.length; i++) {
   rgb[i] = Math.floor(rgb[i] - ratio * rgb[i]);
}

I rozjaśnić

for (let i = 0; i < rgb.length; i++) {
   rgb[i] = Math.ceil(rgb[i] + ratio * (255 - rgb[i]));
}

Oto pakiet https://github.com/MarchWorks/colortone

Demo https://colortone.now.sh/

ze sposobem, w jaki robię rzeczy, jeśli przekroczysz współczynnik -1, skończysz na czarnym, białym, jeśli współczynnik wynosi 1. Przekazanie 0, ponieważ współczynnik nie zmieni koloru

evgeni fotia
źródło
0

Potrzebowałem go w języku C #, może to pomóc programistom .net

public static string LightenDarkenColor(string color, int amount)
    {
        int colorHex = int.Parse(color, System.Globalization.NumberStyles.HexNumber);
        string output = (((colorHex & 0x0000FF) + amount) | ((((colorHex >> 0x8) & 0x00FF) + amount) << 0x8) | (((colorHex >> 0xF) + amount) << 0xF)).ToString("x6");
        return output;
    }
Nassim
źródło
Przekształciłeś funkcję „niedziałającą”, która nie radzi sobie z zerami wiodącymi, i może przekroczyć FF w sumach, = zmodyfikować składnik koloru powyżej ...
B. Idź
Kiedy wypróbowałem tę funkcję, nie działała z powodu wartości innych niż szesnastkowe (16 = 0xF) i (8 = 0x8) i daje kolor w 8 pozycjach, ale teraz działa bardzo dobrze
Nassim
próbowałeś zwiększyć z FF? (powiedzmy od 0xFFFFFF + 0x000004): twoje bułki kod powyżej tej wartości max nie (powiedzmy do 0x1000003), zamiast rosnąć, a zwłaszcza ustawiania 2 górne elementy kolorów do 00, która jest największa zmiana mogli zrobić ...
B. Idź
masz rację, dziękuję za uwagę, z wyjątkiem wprowadzenia limitów wokół fff i 000, będzie dobrze.
Nassim