Konvertera Färg Utrymmen i JavaScript

0
17

En utmaning jag står inför att bygga en bild “emojifier” var att jag behövde ändra färg utrymmen av värden som erhålls med getImageData() från RGB till HSL. Jag använde kedjor av emojis arrangeras av ljusstyrka och mättnad, och de var HSL-baserad för de bästa matcherna i genomsnitt pixel färger med emojis.

I denna artikel kommer vi att studera funktioner som kommer att vara användbar för att konvertera både oklara och alpha-aktiverade färg värden. Moderna webbläsare stöder för närvarande färgsystem RGB(A), hex, och HSL(EN). Funktioner och beteckningar för dessa är rgb(), rgba(), #rgb/#rrggbb, #rgba/#rrggbbaa, hsl(), och hsla(). Webbläsare har alltid stöttat inbyggd namn som aliceblue.

Längs vägen, vi kommer att stöta på användningen av lite färg syntaxer som tillhandahålls av en ny Nivå 4 i CSS Färger Modul. Till exempel, vi har nu hex med alpha som vi nämnde (#rgba/#rrggbbaa) och RGB och HSL syntaxer inte längre kräver kommatecken (värden som rgb(255 0 0) och hsl(240 100% 50%) blev lagligt!).

Webbläsare-stöd för CSS Färger Nivå 4 är inte universell när detta skrivs, så förvänta dig inte ny färg syntaxer för att arbeta i Microsoft webbläsare eller Safari om att pröva dem i CSS.

RGB till Hex

Konvertera RGB till hex är bara en förändring av radices. Vi konvertera den röda, gröna och blåa värden från decimalt till hexadecimalt med hjälp av toString(16). Efter tillagd 0s till ensiffriga tal och under, vi kan slå samman dem och # för att en enda return.

funktion RGBToHex(r,g,b) {
r = r.toString(16);
g = g.toString(16);
b = b.toString(16);

om (r.längd == 1)
r = “0” + r;
om (g.längd == 1)
g = “0” + g;
om b.längd == 1)
b = “0” + b;

tillbaka “#” + r + g + b;
}
RGB i Sträng

Alternativt kan vi använda en enda sträng argument med röd, grön och blå separerade med kommatecken eller mellanslag (t ex “rgb(255,25,2)”, “rgb(255 25 2)”). Delsträng att eliminera rgb(, dela upp vad som är kvar av den ), för att sedan dela det resultat som första objekt av vilken skiljetecknet (sep). r, g och b ska bli lokala variabler nu. Då vi använd + före split strängar för att konvertera tillbaka dem till tal innan de har fått hex-värden.

funktion RGBToHex(rgb) {
// Sätt rätt avgränsare
låt sep = rgb.indexOf(“,”) > -1 ? “,” : “”;
// Turn “rgb(r,g,b)” [r,g,b]
rgb = rgb.substr(4).split(“)”)[0].split(sep);

låt r = (+rgb[0]).toString(16),
g = (+rgb[1]).toString(16),
b = (+rgb[2]).toString(16);

om (r.längd == 1)
r = “0” + r;
om (g.längd == 1)
g = “0” + g;
om b.längd == 1)
b = “0” + b;

tillbaka “#” + r + g + b;
}

Dessutom kan vi tillåter strängar med kanal värden som procenttal genom att lägga till slingan efter att omdefiniera rgb. Det kommer strip %s och förvandla vad som finns kvar till ett värde av 255.

funktion RGBToHex(rgb) {
låt sep = rgb.indexOf(“,”) > -1 ? “,” : “”;
rgb = rgb.substr(4).split(“)”)[0].split(sep);

// Konvertera %s för att 0-255
för (låt R i rgb) {
låt r = rgb[R];
om (r.indexOf(“%”) > -1)
rgb[R] = Math.runda(r.substr(0,r.längd – 1) / 100 * 255);
/* Exempel:
75% -> 191
75/100 = 0.75, * 255 = 191.25 -> 191
*/
}


}

Nu kan vi leverera värden som någon av dessa:

  • rgb(255,25,2)
  • rgb(255 25 2)
  • rgb(50%,30%,10%)
  • rgb(50% 30% 10%)

RGBA till Hex (#rrggbbaa)

Konvertera RGBA till hex med #rgba eller #rrggbbaa notation följer i stort sett samma process som ogenomskinlig motsvarighet. Eftersom alfa (a) är normalt ett värde mellan 0 och 1, vi måste multiplicera det med 255, runda resultatet, för att sedan konvertera det till hexadecimalt värde.

funktion RGBAToHexA(r,g,b,a) {
r = r.toString(16);
g = g.toString(16);
b = b.toString(16);
a = Matematik.runda(a * 255).toString(16);

om (r.längd == 1)
r = “0” + r;
om (g.längd == 1)
g = “0” + g;
om b.längd == 1)
b = “0” + b;
om a.längd == 1)
en = “0” + a;

tillbaka “#” + r + g + b + a;
}

För att göra detta med en sträng (bland annat med procentsatser), kan vi följa vad vi gjorde tidigare. Observera också den extra steg för skarvning ut ett snedstreck. Eftersom CSS Färger Nivå 4 stöder syntax rgba(r g b / a), det är där vi tillåter det. Alpha värden kan nu vara procentsatser! Detta tar bort 0-1-bara bojor som vi brukade ha. Därför, för loop cykling genom rgba skall innehålla en del att torka % från alpha utan att multiplicera med 255 (när R är 3 för alpha). Snart kan vi använda värden som rgba(255 128 0 / 0.8) och rgba(100% 21% 100% / 30%)!

funktion RGBAToHexA(rgba) {
låt sep = rgba.indexOf(“,”) > -1 ? “,” : “”;
rgba = rgba.substr(5).split(“)”)[0].split(sep);

// Band slash om du använder separerade med mellanslag, syntax
om (rgba.indexOf(“/”) > -1)
rgba.splice(3,1);

för (låt R i rgba) {
låt r = rgba[R];
om (r.indexOf(“%”) > -1) {
låt p = r.substr(0,r.längd – 1) / 100;

if (R < 3) {
rgba[R] = Math.round(p * 255);
} else {
rgba[R] = p;
}
}
}
}

Sedan, när kanalerna är konverterade till hex, vi justera för att använda ett objekt av rgba[].

funktion RGBAToHexA(rgba) {

låt r = (+rgba[0]).toString(16),
g = (+rgba[1]).toString(16),
b = (+rgba[2]).toString(16),
a = Matematik.runda(+rgba[3] * 255).toString(16);

om (r.längd == 1)
r = “0” + r;
om (g.längd == 1)
g = “0” + g;
om b.längd == 1)
b = “0” + b;
om a.längd == 1)
en = “0” + a;

tillbaka “#” + r + g + b + a;
}

Nu funktionen stöder följande:

  • rgba(255,25,2,0.5)
  • rgba(255 25 2 / 0.5)
  • rgba(50%,30%,10%,0.5)
  • rgba(50%,30%,10%,50%)
  • rgba(50% 30% 10% / 0.5)
  • rgba(50% 30% 10% / 50%)

Hex till RGB

Vi vet att längden av hex-värden ska vara antingen 3 eller 6 (plus #). I båda fallen, vi börjar varje rött (r), grönt (g), och blått (b) värdet med “0x” för att konvertera dem till hex. Om vi ger ett 3-siffrigt värde, kan vi slå samman samma värde två gånger för varje kanal. Om det är ett 6-siffrigt värde, kan vi slå samman de två första för röd, nästa två för grön, och de två sista för blå. För att få värdena från den sista rgb() string, vi lägga variablerna med + att omvandla dem från strängar tillbaka på siffror, vilket kommer att ge den decimaler vi behöver.

funktion hexToRGB(h) {
låt r = 0, g = 0, b = 0;

// 3 siffror
om h.längd == 4) {
r = “0x” + h[1] + h[1];
g = “0x” + h[2] + h[2];
b = “0x” + h[3] + h[3];

// 6 siffror
} else if (h.längd == 7) {
r = “0x” + h[1] + h[2];
g = “0x” + h[3] + h[4];
b = “0x” + h[5] + h[6];
}

avkastning “rgb(“+ +r + “, ” + i +g + “, ” + ” och ” +b + “)”;
}
Utgång RGB med %s

Om vi vill returnera rgb() använder procentsatser, då kan vi ändra funktion för att använda sig av en valfri isPct parameter som så:

funktion hexToRGB(h,isPct) {
låt r = 0, g = 0, b = 0;
isPct = isPct === true;

om h.längd == 4) {
r = “0x” + h[1] + h[1];
g = “0x” + h[2] + h[2];
b = “0x” + h[3] + h[3];

} else if (h.längd == 7) {
r = “0x” + h[1] + h[2];
g = “0x” + h[3] + h[4];
b = “0x” + h[5] + h[6];
}

om (isPct) {
r = +(r / 255 * 100).toFixed(1);
g = +(g / 255 * 100).toFixed(1);
b = +(b / 255 * 100).toFixed(1);
}

avkastning “rgb(” + (isPct ? r + “%,” + g + “%,” + b + “%” : +r + “, ” + i +g + “, ” + ” och ” +b) + “)”;
}

Under de senaste uttalande om, med hjälp av +s kommer att konvertera r, g och b-nummer. Varje toFixed(1) tillsammans med dem kommer avrunda resultatet till närmaste tiondel. Dessutom kommer vi inte att ha hela tal med .0 eller decennier gamla sarkasm som producerar nummer som 0.30000000000000004. Därför, i gengäld, vi utelämnat +s precis innan den första r, g och b för att förhindra NaNs som orsakas av %s. Nu kan vi använda hexToRGB(“#ff0”,true) för att få rgb(100%,100%,0%)!

Hex (#rrggbbaa) för att RGBA

Förfarandet för hex-värden med alpha återigen bör vara identisk med den förra. Vi har helt enkelt upptäcka en 4 – eller 8-siffrigt värde (plus #) för att sedan omvandla alfa och dela det med 255. För att få mer exakta utgång men inte långa decimaltal för alpha, vi kan använda toFixed(3).

funktion hexAToRGBA(h) {
låt r = 0, g = 0, b = 0, a = 1;

om h.längd == 5) {
r = “0x” + h[1] + h[1];
g = “0x” + h[2] + h[2];
b = “0x” + h[3] + h[3];
en = “0x” + h[4] + h[4];

} else if (h.längd == 9) {
r = “0x” + h[1] + h[2];
g = “0x” + h[3] + h[4];
b = “0x” + h[5] + h[6];
en = “0x” + h[7] + h[8];
}
a = +(a / 255).toFixed(3);

return “rgba(” + +r + “, ” + i +g + “, ” + ” och ” +b + “,” + a + “)”;
}
Produktionen RGBA med %s

För en version som utgångar procentsatser, vi kan göra vad vi gjorde i hexToRGB()—växlar r, g och b till 0-100% när isPct är sant.

funktion hexAToRGBA(h,isPct) {
låt r = 0, g = 0, b = 0, a = 1;
isPct = isPct === true;

// Hantering av siffror

om (isPct) {
r = +(r / 255 * 100).toFixed(1);
g = +(g / 255 * 100).toFixed(1);
b = +(b / 255 * 100).toFixed(1);
}
a = +(a / 255).toFixed(3);

return “rgba(” + (isPct ? r + “%,” + g + “%,” + b + “%,” + a : +r + “, ” + i +g + “, ” + ” och ” +b + “,” + a) + “)”;
}

Här är en snabb fix om alpha borde vara en del också: flytta uttalande där en omdefinieras ovanför den sista if-sats. Sedan i det uttalandet, ändra en vara som r, g och b. När isPct är sant, måste också få %.

funktion hexAToRGBA(h,isPct) {

a = +(a / 255).toFixed(3);
om (isPct) {
r = +(r / 255 * 100).toFixed(1);
g = +(g / 255 * 100).toFixed(1);
b = +(b / 255 * 100).toFixed(1);
a = +(a * 100).toFixed(1);
}

return “rgba(” + (isPct ? r + “%,” + g + “%,” + b + “%,” + a + “%” : +r + “, ” + i +g + “, ” + ” och ” +b + “,” + a) + “)”;
}

När vi går in i #7f7fff80 nu, vi ska få rgba(127,127,255,0.502) eller rgba(49.8%,49.8%,100%,50.2%).

RGB till HSL

Få HSL värden från RGB-eller hex är lite mer utmanande eftersom det finns en större formeln är inblandade. Första, vi måste dela upp de röda, gröna och blå av 255 för att använda värden mellan 0 och 1. Då får vi hitta de lägsta och högsta av dessa värden (cmin och cmax) samt skillnaden mellan dem (delta). Vi behöver det resultat som en del av beräkningen nyans och mättnad. Direkt efter att delta, låt oss initiera nyans (h), mättnad (s) och ljushet (l).

funktion RGBToHSL(r,g,b) {
// R, g och b fraktioner av 1
r /= 255;
g /= 255;
b /= 255;

// Hitta största och minsta värden kanal
låt cmin = Matematik.min(r,g,b),
cmax = Matematik.max(r,g,b),
delta = cmax – cmin,
h = 0,
s = 0,
l = 0;
}

Nästa, måste vi beräkna nyans, som bestäms av den största kanalen värde i cmax (eller om alla kanaler är de samma). Om det är någon skillnad mellan kanaler, nyans kommer att vara 0. Om cmax är röd, då formel (g – b) / delta) % 6. Om grönt, och sedan (b – r) / delta + 2. Sedan, om blå, (r – g) / delta + 4. Slutligen, multiplicera resultatet med 60 (för att få grad-värde) och runt det. Sedan nyanser bör inte vara negativ, och vi lägger till 360 för att det, om det behövs.

funktion RGBToHSL(r,g,b) {

// Beräknar nyans
// Ingen skillnad
om (delta == 0)
h = 0;
// Röd finns max
else if (cmax == r)
h = (g – b) / delta) % 6;
// Gröna är max
else if (cmax == g)
h = (b – r) / delta + 2;
// Blue max
annat
h = (r – g) / delta + 4;

h = Matematik.runda(h * 60);

// Gör negativa nyanser positivt bakom 360°
om h < 0)
h += 360;
}

Alla som är kvar är det mättnad och ljushet. Låt oss beräkna den lätthet innan vi gör mättnad, eftersom mättnaden kommer att bero på det. Det är summan av den högsta och lägsta kanal värden halveras ((cmax + cmin) / 2). Då delta kommer att avgöra vad mättnaden kommer att bli. Om det är 0 (ingen skillnad mellan cmax och cmin), då mättnad är automatiskt 0. Annars, det kommer att vara 1 minus den absoluta värde av två gånger lätthet minus 1 (1 – Matematik.abs(2 * l – 1)). När vi har dessa värderingar, vi måste konvertera dem till värden av 100%, så vi multiplicera med 100 och avrunda till närmaste tiondel. Nu kan vi ihop våra hsl().

funktion RGBToHSL(r,g,b) {

// Beräknar lätthet
l = (cmax + cmin) / 2;

// Beräknar mättnad
s = delta == 0 ? 0 : delta / (1 – Matematik.abs(2 * l – 1));

// Multiplicera l-och s-100
s = +(n * 100).toFixed(1);
l = +(l * 100).toFixed(1);

return “(hsl(” + h + “,” + s+ “%, ” + ” och ” l + “%)”;
}
RGB i Sträng

För en sträng, split argumentet med kommatecken eller mellanslag, band %s, och lokalisera r, g och b som vi gjorde innan.

funktion RGBToHSL(rgb) {
låt sep = rgb.indexOf(“,”) > -1 ? “,” : “”;
rgb = rgb.substr(4).split(“)”)[0].split(sep);

för (låt R i rgb) {
låt r = rgb[R];
om (r.indexOf(“%”) > -1)
rgb[R] = Math.runda(r.substr(0,r.längd – 1) / 100 * 255);
}

// R, g och b fraktioner av 1
låt r = rgb[0] / 255,
g = rgb[1] / 255,
b = rgb[2] / 255;


}

RGBA att HSLA

Jämfört med vad vi gjorde bara för att konvertera RGB till HSL, alpha motpart kommer att vara i stort sett ingenting! Vi bara återanvända koden för RGB till HSL (multi-argument version), lämna en ensam, och passerar en till tillbaka HSLA. Tänk på att det bör vara mellan 0 och 1.

funktion RGBAToHSLA(r,g,b,a) {
// Kod för RGBToHSL(r,g,b) innan retur

return “hsla(” + h + “,” + s+ “%, ” + ” och ” l + “%,” + a + “)”;
}
RGBA i Sträng

För string-värden, vi tillämpar dela och skrapa logik igen men använd den fjärde punkten i rgba för en. Kom ihåg den nya rgba(r g b / a) syntax? Vi anställa acceptans av det som vi gjorde för RGBAToHexA(). Sedan resten av koden är normalt RGB till HSL konvertering.

funktion RGBAToHSLA(rgba) {
låt sep = rgba.indexOf(“,”) > -1 ? “,” : “”;
rgba = rgba.substr(5).split(“)”)[0].split(sep);

// Band slash om du använder separerade med mellanslag, syntax
om (rgba.indexOf(“/”) > -1)
rgba.splice(3,1);

för (låt R i rgba) {
låt r = rgba[R];
om (r.indexOf(“%”) > -1) {
låt p = r.substr(0,r.längd – 1) / 100;

if (R < 3) {
rgba[R] = Math.round(p * 255);
} else {
rgba[R] = p;
}
}
}

// R, g och b fraktioner av 1
låt r = rgba[0] / 255,
g = rgba[1] / 255,
b = rgba[2] / 255,
a = rgba[3];

// Övriga RGB till HSL logik

}

Önskar att lämna alpha som är? Ta bort den annars uttalande från for-loop.

för (låt R i rgba) {
låt r = rgba[R];
om (r.indexOf(“%”) > -1) {
låt p = r.substr(0,r.längd – 1) / 100;

if (R < 3) {
rgba[R] = Math.round(p * 255);
}
}
}

HSL till RGB

Det tar något mindre logik för att konvertera HSL tillbaka till RGB-än tvärtom. Eftersom vi använder en rad 0-100 för mättnad och ljushet, det första steget är att dela dem med 100 till värden mellan 0 och 1. Nästa, finner vi chroma (c), som är färg intensitet, så att (1 – Matematik.abs(2 * l – 1)) * s. Då vi använder x för den näst största komponenten (den första är chroma), belopp för att lägga till varje kanal för att matcha den lätthet (m), och initiera r, g, b.

funktion HSLToRGB(h,s,l) {
// Måste vara fraktioner av 1
s /= 100;
l /= 100;

låt c = (1 – Matematik.abs(2 * l – 1)) * s,
x = c * (1 – Matematik.abs((h / 60) % 2 – 1)),
m = l – c/2,
r = 0,
g = 0,
b = 0;
}

Nyans kommer att avgöra vad som är den röda, gröna och blå bör vara beroende av vilka 60° – sektor av färghjulet det ligger.

Färg hjulet delas in i 60° segment

Då c-och x skall tilldelas som visas nedan, lämna en kanal på 0. För att få den slutliga RGB-värde, lägger vi m för varje kanal, multiplicera det med 255, och runt det.

funktion HSLToRGB(h,s,l) {

om (0 <= t && h < 60) {
r = c, g = x, b = 0;
} else if (60 <= h && h < 120) {
r = x; g = c; b = 0;
} else if (120 <= h && h < 180) {
r = 0, g = c; b = x;
} else if (180 <= h && h < 240) {
r = 0, g = x, b = c;
} else if (240 <= h && h < 300) {
r = x; g = 0, b = c;
} else if (300 <= h && h < 360) {
r = c, g = 0; b = x;
}
r = Matematik.round((r + m) * 255);
g = Matematik.runda (g + m) * 255);
b = Matematik.round((b + m) * 255);

avkastning “rgb(” + r + “,” + g + “,” + b + “)”;
}
HSL i Sträng

För det enda sträng version ändrar vi först några uttalanden i princip samma sätt som vi gjorde för RGBToHSL(r,g,b). Ta bort s /= 100; och l /= 100; och vi kommer att använda den nya uttalanden för att torka de första 4 tecknen och ) för vårt utbud av HSL-värden, då den %s från s och l innan du delar dem med 100.

funktion HSLToRGB(hsl) {
låt sep = hsl.indexOf(“,”) > -1 ? “,” : “”;
hsl = hsl.substr(4).split(“)”)[0].split(sep);

låt h = hsl[0],
s = hsl[1].substr(0,hsl[1].längd – 1) / 100,
l = hsl[2].substr(0,hsl[2].längd – 1) / 100;


}

Nästa handfull rapporter ska hantera nyanser försedd med en enhet—grader, radianer eller svängar. Vi multiplicerar radianer 180/π och visar med 360. Om resultatet hamnar över 360, vi föreningen modul dela sig för att hålla det inom tillämpningsområdet. Allt detta kommer att hända innan vi tar itu med c, x, och m.

funktion HSLToRGB(hsl) {

// Band-etikett och omvandlar den till grader (om nödvändigt)
om h.indexOf(“deg”) > -1)
h = h.substr(0,h.längd – 3);
else if (h.indexOf(“rad”) > -1)
h = Matematik.runda(h.substr(0,h.längd – 3) * (180 / i Matematik.PI));
else if (h.indexOf(“turn”) > -1)
h = Matematik.runda(h.substr(0,h.längd – 4) * 360);
// Håll nyans bråkdel av 360 om att hamna över
om h >= 360)
h %= 360;

// Omvandling till RGB börjar

}

Efter genomförandet av ovanstående åtgärder nu följande kan användas på ett säkert sätt:

  • hsl(180 100% 50%)
  • hsl(180deg,100%,50%)
  • hsl(180deg 100% 50%)
  • hsl(3.14 rad,100%,50%)
  • hsl(3.14 rad 100% 50%)
  • hsl(0.5 turn,100%,50%)
  • hsl(0.5 sin tur 100% 50%)

Usch, det är ganska flexibilitet!

Utgång RGB med %s

På samma sätt kan vi modifiera denna funktion för att återgå procent värderingar, precis som vi gjorde i hexToRGB().

funktion HSLToRGB(hsl,isPct) {
låt sep = hsl.indexOf(“,”) > -1 ? “,” : “”;
hsl = hsl.substr(4).split(“)”)[0].split(sep);
isPct = isPct === true;

om (isPct) {
r = +(r / 255 * 100).toFixed(1);
g = +(g / 255 * 100).toFixed(1);
b = +(b / 255 * 100).toFixed(1);
}

avkastning “rgb(“+ (isPct ? r + “%,” + g + “%,” + b + “%” : +r + “, ” + i +g + “, ” + ” och ” +b) + “)”;
}

HSLA att RGBA

Återigen, hantering alpha kommer att vara en no-brainer. Vi kan återanvända koden för den ursprungliga HSLToRGB(h,s,l), och lägg till avkastning.

funktion HSLAToRGBA(h,s,l,a) {
// Kod för HSLToRGB(h,s,l) innan retur

return “rgba(” + r + “,” + g + “,” + b + “,” + a + “)”;
}
HSLA i Sträng

Ändra det till ett argument, hur vi ska hantera strängar här kommer inte vara för mycket annorlunda än vad vi gjorde tidigare. En ny HSLA-syntax från Färger Nivå 4 använder (värde värde värde / value) precis som RGBA, så ha kod för att hantera det, för att vi ska kunna koppla in något som hsla(210 100% 50% / 0.5) här.

funktion HSLAToRGBA(hsla) {
låt sep = hsla.indexOf(“,”) > -1 ? “,” : “”;
hsla = hsla.substr(5).split(“)”)[0].split(sep);

om (hsla.indexOf(“/”) > -1)
hsla.splice(3,1);

låt h = hsla[0],
s = hsla[1].substr(0,hsla[1].längd – 1) / 100,
l = hsla[2].substr(0,hsla[2].längd – 1) / 100,
a = hsla[3];

om h.indexOf(“deg”) > -1)
h = h.substr(0,h.längd – 3);
else if (h.indexOf(“rad”) > -1)
h = Matematik.runda(h.substr(0,h.längd – 3) * (180 / i Matematik.PI));
else if (h.indexOf(“turn”) > -1)
h = Matematik.runda(h.substr(0,h.längd – 4) * 360);
om h >= 360)
h %= 360;


}

Dessutom, dessa andra kombinationer har blivit möjligt:

  • hsla(180,100%,50%,50%)
  • hsla(180 100% 50% / 50%)
  • hsla(180deg,100%,50%,0.5)
  • hsla(3.14 rad,100%,50%,0.5)
  • hsla(0.5 sin tur 100% 50% / 50%)

RGBA med %s

Då kan vi replikera samma logik för att mata procentsatser, inklusive alfa. Om alfa bör vara en procentsats (sökas i pctFound), här är hur vi kan hantera det:

  1. Om r, g och b är att omvandlas till procent, då ska multipliceras med 100, om inte redan en procent. Annars, släpp %, och det kommer att läggas tillbaka i retur.
  2. Om r, g och b bör vara ifred, ta sedan bort % från och dela med 100.

funktion HSLAToRGBA(hsla,isPct) {
// Kod för upp till slash strippa

isPct = isPct === true;

// h, s, l, a definierad av avrundning av r, g, b

låt pctFound = en.indexOf(“%”) > -1;

om (isPct) {
r = +(r / 255 * 100).toFixed(1);
g = +(g / 255 * 100).toFixed(1);
b = +(b / 255 * 100).toFixed(1);
if (!pctFound) {
*= 100;
} else {
a = a.substr(0,.längd – 1);
}

} else if (pctFound) {
a = a.substr(0,.längd – 1) / 100;
}

return “rgba(“+ (isPct ? r + “%,” + g + “%,” + b + “%,” + a + “%” : +r + “, ” + i +g + “, ” + ” och ” +b + “, ” + ” och ” +a) + “)”;
}

Hex till HSL

Du kanske tror att denna och nästa är galnare processer än de andra, men de bara kommer i två delar med återvunnet logik. För det första, vi konvertera till RGB hex. Som ger oss den bas 10s vi behöver för att konvertera till HSL.

funktion hexToHSL(H) {
// Konvertera till RGB hex första
låt r = 0, g = 0, b = 0;
om (H. längd == 4) {
r = “0x” + H[1] + H[1];
g = “0x” + H[2] + H[2];
b = “0x” + H[3] + H[3];
} else if (H. längd == 7) {
r = “0x” + H[1] + H[2];
g = “0x” + H[3] + H[4];
b = “0x” + H[5] + H[6];
}
// Sedan till HSL
r /= 255;
g /= 255;
b /= 255;
låt cmin = Matematik.min(r,g,b),
cmax = Matematik.max(r,g,b),
delta = cmax – cmin,
h = 0,
s = 0,
l = 0;

om (delta == 0)
h = 0;
else if (cmax == r)
h = (g – b) / delta) % 6;
else if (cmax == g)
h = (b – r) / delta + 2;
annat
h = (r – g) / delta + 4;

h = Matematik.runda(h * 60);

om h < 0)
h += 360;

l = (cmax + cmin) / 2;
s = delta == 0 ? 0 : delta / (1 – Matematik.abs(2 * l – 1));
s = +(n * 100).toFixed(1);
l = +(l * 100).toFixed(1);

return “(hsl(” + h + “,” + s+ “%, ” + ” och ” l + “%)”;
}

Hex (#rrggbbaa) för att HSLA

Det finns inte så många rader för att ändra på detta. Vi kommer att upprepa vad vi gjorde nyligen för att få alpha genom att omvandla till hex, men kommer inte att dela det med 255 direkt. Första, vi måste få den nyans, mättnad och ljusstyrka som vi gjorde i den andra att-HSL funktioner. Då, innan det slutar tillbaka, vi delar alpha och ange decimaler.

funktion hexAToHSLA(H) {
låt r = 0, g = 0, b = 0, a = 1;

om (H. längd == 5) {
r = “0x” + H[1] + H[1];
g = “0x” + H[2] + H[2];
b = “0x” + H[3] + H[3];
en = “0x” + H[4] + H[4];
} else if (H. längd == 9) {
r = “0x” + H[1] + H[2];
g = “0x” + H[3] + H[4];
b = “0x” + H[5] + H[6];
en = “0x” + H[7] + H[8];
}

// Normal konvertering till HSL

a = (a / 255).toFixed(3);

return “hsla(“+ h + “,” + s+ “%, ” + ” och ” l + “%,” + a + “)”;
}

HSL till Hex

Detta börjar som en konvertering till RGB, men det är ett extra steg till Matte.round()s för att konvertera RGB-resultat till hex.

funktion HSLToHex(h,s,l) {
s /= 100;
l /= 100;

låt c = (1 – Matematik.abs(2 * l – 1)) * s,
x = c * (1 – Matematik.abs((h / 60) % 2 – 1)),
m = l – c/2,
r = 0,
g = 0,
b = 0;

om (0 <= t && h < 60) {
r = c, g = x, b = 0;
} else if (60 <= h && h < 120) {
r = x; g = c; b = 0;
} else if (120 <= h && h < 180) {
r = 0, g = c; b = x;
} else if (180 <= h && h < 240) {
r = 0, g = x, b = c;
} else if (240 <= h && h < 300) {
r = x; g = 0, b = c;
} else if (300 <= h && h < 360) {
r = c, g = 0; b = x;
}
// Har erhållit RGB, omvandla till hex-kanaler
r = Matematik.round((r + m) * 255).toString(16);
g = Matematik.runda (g + m) * 255).toString(16);
b = Matematik.round((b + m) * 255).toString(16);

// Du låta 0s, om det är nödvändigt
om (r.längd == 1)
r = “0” + r;
om (g.längd == 1)
g = “0” + g;
om b.längd == 1)
b = “0” + b;

tillbaka “#” + r + g + b;
}
HSL i Sträng

Även de första raderna av denna funktion kommer att vara som de i HSLToRGB() om vi ändrade det till att acceptera en enda sträng. Detta är hur vi har kunnat få den nyans, mättnad och ljusstyrka separat i första hand. Låt oss inte glömma det steg för att ta bort färg etikett och omvandlar den till grader också. Allt detta kommer att finnas på plats på s /= 100; och l /= 100;.

funktion HSLToHex(hsl) {
låt sep = hsl.indexOf(“,”) > -1 ? “,” : “”;
hsl = hsl.substr(4).split(“)”)[0].split(sep);

låt h = hsl[0],
s = hsl[1].substr(0,hsl[1].längd – 1) / 100,
l = hsl[2].substr(0,hsl[2].längd – 1) / 100;

// Band-etikett och omvandlar den till grader (om nödvändigt)
om h.indexOf(“deg”) > -1)
h = h.substr(0,h.längd – 3);
else if (h.indexOf(“rad”) > -1)
h = Matematik.runda(h.substr(0,h.längd – 3) * (180 / i Matematik.PI));
else if (h.indexOf(“turn”) > -1)
h = Matematik.runda(h.substr(0,h.längd – 4) * 360);
om h >= 360)
h %= 360;


}

HSLA till Hex (#rrggbbaa)

Lägga till alpha till mixen, vi omvandla till hex och lägga till en fjärde om att lägga till en 0, om det är nödvändigt. Du har förmodligen redan är bekant med denna logik eftersom vi använde det senast i RGBAToHexA().

funktion HSLAToHexA(h,s,l,a) {
// Upprepa kod från HSLToHex(h,s,l) tills 3 `toString(16) s

a = Matematik.runda(a * 255).toString(16);

om (r.längd == 1)
r = “0” + r;
om (g.längd == 1)
g = “0” + g;
om b.längd == 1)
b = “0” + b;
om a.längd == 1)
en = “0” + a;

tillbaka “#” + r + g + b + a;
}
HSLA i Sträng

Slutligen, rader det enda argument version upp till a = hsla[3] är inte annorlunda än de av HSLAToRGBA().

funktion HSLAToHexA(hsla) {
låt sep = hsla.indexOf(“,”) > -1 ? “,” : “”;
hsla = hsla.substr(5).split(“)”)[0].split(sep);

// Band slash
om (hsla.indexOf(“/”) > -1)
hsla.splice(3,1);

låt h = hsla[0],
s = hsla[1].substr(0,hsla[1].längd – 1) / 100,
l = hsla[2].substr(0,hsla[2].längd – 1) / 100,
a = hsla[3];


}

Inbyggd Namn

För att konvertera en namngiven färg RGB -, hex, eller HSL, kan du överväga att vända denna tabell 140+ namn och hex-värden i ett massivt objekt i början. Sanningen är att vi egentligen inte behöver, eftersom det här är vad vi kan göra:

  1. Skapa ett element
  2. Ge det en text färg
  3. Få fram värdet av egendomen
  4. Ta bort elementet
  5. Tillbaka lagras färg värde, som kommer att vara i RGB som standard

Så, vår funktion för att få RGB kommer bara vara sju uttalanden!

funktion nameToRGB(namn) {
// Skapa falska div
låt fakeDiv = dokument.createElement(“div”);
fakeDiv.style.färg = namn;
dokumentet.organ.appendChild(fakeDiv);

// Get färg av div
låt cs = fönster.getComputedStyle(fakeDiv),
pv = cs.getPropertyValue(“color”);

// Ta bort div efter att få önskad färg värde
dokumentet.organ.removeChild(fakeDiv);

tillbaka pv;
}

Låt oss gå ännu längre. Hur vi ändra produktionen till hex istället?

funktion nameToHex(namn) {
// Hämta från RGB heter färg i tillfälliga div
låt fakeDiv = dokument.createElement(“div”);
fakeDiv.style.färg = namn;
dokumentet.organ.appendChild(fakeDiv);

låt cs = fönster.getComputedStyle(fakeDiv),
pv = cs.getPropertyValue(“color”);

dokumentet.organ.removeChild(fakeDiv);

// Kod för rippade från RGBToHex() (utom pv är substringed)
låt rgb = pv.substr(4).split(“)”)[0].split(“,”),
r = (+rgb[0]).toString(16),
g = (+rgb[1]).toString(16),
b = (+rgb[2]).toString(16);

om (r.längd == 1)
r = “0” + r;
om (g.längd == 1)
g = “0” + g;
om b.längd == 1)
b = “0” + b;

tillbaka “#” + r + g + b;
}

Eller, varför inte HRT? 😉

funktion nameToHSL(namn) {
låt fakeDiv = dokument.createElement(“div”);
fakeDiv.style.färg = namn;
dokumentet.organ.appendChild(fakeDiv);

låt cs = fönster.getComputedStyle(fakeDiv),
pv = cs.getPropertyValue(“color”);

dokumentet.organ.removeChild(fakeDiv);

// Kod för rippade från RGBToHSL() (utom pv är substringed)
låt rgb = pv.substr(4).split(“)”)[0].split(“,”),
r = rgb[0] / 255,
g = rgb[1] / 255,
b = rgb[2] / 255,
cmin = Matematik.min(r,g,b),
cmax = Matematik.max(r,g,b),
delta = cmax – cmin,
h = 0,
s = 0,
l = 0;

om (delta == 0)
h = 0;
else if (cmax == r)
h = (g – b) / delta) % 6;
else if (cmax == g)
h = (b – r) / delta + 2;
annat
h = (r – g) / delta + 4;

h = Matematik.runda(h * 60);

om h < 0)
h += 360;

l = (cmax + cmin) / 2;
s = delta == 0 ? 0 : delta / (1 – Matematik.abs(2 * l – 1));
s = +(n * 100).toFixed(1);
l = +(l * 100).toFixed(1);

return “(hsl(” + h + “,” + s+ “%, ” + ” och ” l + “%)”;
}

I det långa loppet, varje omvandling från ett namn blir en konvertering från RGB efter knäcka namn.

Validera Färger

I alla dessa funktioner, det har inte varit några åtgärder för att förhindra eller rätta till skrattretande ingång (säger nyanser över 360 eller procentsatser över 100). Om vi bara manipulera pixlar på en <canvas> som hämtas med hjälp av getImageData(), validering av färg värden är inte nödvändigt innan du konverterar för att de ska vara rätt oavsett vad. Om vi skapar en färg konvertering verktyg där användarna leverans färgen, sedan validering skulle vara välbehövligt.

Det är lätt att hantera felaktiga indata för kanaler som separata argument som denna för RGB:

// Rätta röda
om (r > 255)
r = 255;
else if (r < 0)
r = 0;

Om validering av en hel rad, sedan ett reguljärt uttryck som behövs. Till exempel, detta är RGBToHex() funktion ges en validering steg med ett uttryck:

funktion RGBToHex(rgb) {
// Ett uttryck för rgb() syntaxer
låt ex = /^rgb((((((((1?[1-9]?d)|10d|(2[0-4]d)|25[0-5]),s?)){2}|((((1?[1-9]?d)|10d|(2[0-4]d)|25[0-5])s)){2})((1?[1-9]?d)|10d|(2[0-4]d)|25[0-5]))|((((([1-9]?d(.d+)?)|100|(.d+))%,s?){2}|((([1-9]?d(.d+)?)|100|(.d+))%s){2})(([1-9]?d(.d+)?)|100|(.d+))%)))$/i;

om (ex.test(rgb)) {
// Logik för att konvertera RGB till hex

} else {
// Något att göra om färgen är ogiltig
}
}

För att testa andra typer av värderingar, nedan är en tabell av uttryck för att täcka både oklara och alpha-aktiverad:

Färg Värde
RegEx
RGB /^rgb((((((((1?[1-9]?d)|10d|(2[0-4]d)|25[0-5]),s?)){2}|((((1?[1-9]?d)|10d|(2[0-4]d)|25[0-5])s)){2})((1?[1-9]?d)|10d|(2[0-4]d)|25[0-5]))|((((([1-9]?d(.d+)?)|100|(.d+))%,s?){2}|((([1-9]?d(.d+)?)|100|(.d+))%s){2})(([1-9]?d(.d+)?)|100|(.d+))%)))$/i
RGBA /^rgba((((((((1?[1-9]?d)|10d|(2[0-4]d)|25[0-5]),s?)){3})|(((([1-9]?d(.d+)?)|100|(.d+))%,s?){3}))|(((((1?[1-9]?d)|10d|(2[0-4]d)|25[0-5])s){3})|(((([1-9]?d(.d+)?)|100|(.d+))%s){3}))/s)((0?.d+)|[01]|(([1-9]?d(.d+)?)|100|(.d+))%))$/i
Hex /^#([da-f]{3}){1,2}$/jag
Hex (med Alpha -) /^#([da-f]{4}){1,2}$/jag
HRT /^hsl(((((([12]?[1-9]?d)|[12]0d|(3[0-5]d))(.d+)?)|(.d+))(deg)?|(0/0?.d+)turn|(([0-6](.d+)?)|(.d+))rad)((,s?(([1-9]?d(.d+)?)|100|(.d+))%){2}|(s(([1-9]?d(.d+)?)|100|(.d+))%){2}))$/i
HSLA /^hsla(((((([12]?[1-9]?d)|[12]0d|(3[0-5]d))(.d+)?)|(.d+))(deg)?|(0/0?.d+)turn|(([0-6](.d+)?)|(.d+))rad)(((,s?(([1-9]?d(.d+)?)|100|(.d+))%){2},s?)|((s(([1-9]?d(.d+)?)|100|(.d+))%){2}s/s))((0?.d+)|[01]|(([1-9]?d(.d+)?)|100|(.d+))%))$/i

Titta på uttryck för RGB(A) och HSL(A), du har förmodligen stora ögon just nu, detta var gjort tillräckligt omfattande för att omfatta de flesta av de nya värdena från CSS Färger Nivå 4. Hex, å andra sidan, behöver inte uttryck så länge som andra på grund av endast siffran räknas. I en stund, vi ska dissekera dessa och tolka delar. Observera att case-insensitive värden (/jag) klara alla dessa.

RGB
/^rgb((((((((1?[1-9]?d)|10d|(2[0-4]d)|25[0-5]),s?)){2}|((((1?[1-9]?d)|10d|(2[0-4]d)|25[0-5])s)){2})((1?[1-9]?d)|10d|(2[0-4]d)|25[0-5]))|((((([1-9]?d(.d+)?)|100|(.d+))%,s?){2}|((([1-9]?d(.d+)?)|100|(.d+))%s){2})(([1-9]?d(.d+)?)|100|(.d+))%)))$/i

Eftersom rgb() accepterar alla heltal eller alla procentsatser, både fall som omfattas. I den största gruppen, mellan ^rgb( och )$, det är inre grupper för både heltal och procentsatser, alla kommatecken-utrymmen eller utrymmen endast som avdelare:

  1. (((((1?[1-9]?d)|10d|(2[0-4]d)|25[0-5]),s?){2}|(((1?[1-9]?d)|10d|(2[0-4]d)|25[0-5])s){2})((1?[1-9]?d)|10d|(2[0-4]d)|25[0-5]))
  2. ((((([1-9]?d(.d+)?)|100|(.d+))%,s?){2}|((([1-9]?d(.d+)?)|100|(.d+))%s){2})(([1-9]?d(.d+)?)|100|(.d+))%)

I första halvlek, vi accepterar två fall av heltal för rött och grönt från 0-99 eller 111-199 ((1?[1-9]?d)), 100-109 (10d), 200-249 ((2[0-4]d)), eller 250-255 (25[0-5]). Vi kunde helt enkelt inte göra d{1,3} eftersom värden som 03 eller 017 och de som är större än 255 borde inte vara tillåtet. Efter det går kommatecken och valfritt utrymme (s?). På andra sidan av | efter de första {2} (som anger att två instanser av heltal), vi söker efter samma sak med utrymme separatorer om vänstra sida är false. Sedan för blå, samma bör accepteras, men utan en separator.

I den andra hälften, acceptabla värden för procent, bland annat flottar, bör antingen vara 0-99, uttryckligen 100 och inte ett flyttal, eller flyter under 1 med 0 sjunkit. Därför är det segment här är (([1-9]?d(.d+)?)|100|(.d+)), och det förekommer tre gånger, två gånger med separator (s?){2}, %s){2}), en gång utan.

Det är lagligt att använda procentsatser utan utrymme separatorer (rgb(100%50%10%) för exempel) i CSS, men de funktioner som vi skrev inte stöder detta. Det samma gäller för rgba(100%50%10%/50%), hsl(40 100%50%), och hsla(40 100%50%/0.5). Detta kan mycket väl vara ett plus för kod golf och minification!

RGBA
/^rgba((((((((1?[1-9]?d)|10d|(2[0-4]d)|25[0-5]),s?)){3})|(((([1-9]?d(.d+)?)|100|(.d+))%,s?){3}))|(((((1?[1-9]?d)|10d|(2[0-4]d)|25[0-5])s){3})|(((([1-9]?d(.d+)?)|100|(.d+))%s){3}))/s)((0?.d+)|[01]|(([1-9]?d(.d+)?)|100|(.d+))%))$/i

Nästa uttryck är mycket lik den föregående, men i tre fall av heltal (((((1?[1-9]?d)|10d|(2[0-4]d)|25[0-5])s?){3})) eller i procent ((((([1-9]?d(.d+)?)|100|(.d+))%,n?){3})), plus kommatecken valfritt utrymme kontrolleras. Annars ser det ut för samma sak men med utrymme separatorer, plus ett snedstreck och utrymme (/s) efter den blå. Bredvid det är ((0?.d+)|[01]|(([1-9]?d(.d+)?)|100|(.d+))%) där vi accepterar flyter med eller utan inledande 0 ((0?.d+)), 0 eller 1 ([01]) på pricken, eller 0-100% ((([1-9]?d(.d+)?)|100|(.d+))%).

Hex med Alpha
// #rgb/#rrggbb
/^#([da-f]{3}){1,2}$/jag
// #rgba/#rrggbbaa
/^#([da-f]{4}){1,2}$/jag

För både hex—med och utan alpha—fall av siffror eller bokstäver a–f ([da-f]) accepteras. Sedan en eller två instanser av detta räknas till antingen kort eller longhand värden som levereras (#rgb eller #rrggbb). Som en illustration, vi har samma kort mönstret: /^#([da-f]{n}){1,2}$/jag. Helt enkelt ändra n till 3 eller 4.

HSL och HSLA
// HSL
/^hsl(((((([12]?[1-9]?d)|[12]0d|(3[0-5]d))(.d+)?)|(.d+))(deg)?|(0/0?.d+)turn|(([0-6\.d+)?)|(.d+))rad)((,s?(([1-9]?d(.d+)?)|100|(.d+))%){2}|(s(([1-9]?d(.d+)?)|100|(.d+))%){2}))$/jag
// HSLA
/^hsla(((((([12]?[1-9]?d)|[12]0d|(3[0-5]d))(.d+)?)|(.d+))(deg)?|(0/0?.d+)turn|(([0-6\.d+)?)|(.d+))rad)(((,s?(([1-9]?d(.d+)?)|100|(.d+))%){2},s?)|((s(([1-9]?d(.d+)?)|100|(.d+))%){2}s/s))((0?.d+)|[01]|(([1-9]?d(.d+)?)|100|(.d+))%))$/i

Efter den ( i både uttryck för HSL och HSLA denna stora datamängd är för nyans:

((((([12]?[1-9]?d)|[12]0d|(3[0-5]d))(.d+)?)|(.d+))(deg)?|(0/0?.d+)turn|(([0-6\.d+)?)|(.d+))rad)

([12]?[1-9]?d) omfattar 0-99, 110-199, och 210-299. [12]0d omfattar 110-109 och 200-209. Då (3[0-5]d) tar hand om 300-359. Anledningen till denna uppdelning av det produktutbud som är liknande till det av heltal i rgb() syntax: dom ut nollor som kommer först och värden som är större än den maximala. Sedan nyanser kan vara flyttal, den första (.d+)? är för det.

Bredvid | efter ovannämnda segment av kod, den andra (.d+) är för flyter utan inledande nolla.

Låt oss nu flytta upp en nivå och dechiffrera nästa lilla stycke:

(deg)?|(0/0?.d+)stäng|(([0-6\.d+)?)|(.d+))rad

Den här innehåller de etiketter som vi kan använda för hue—grader, vänder sig om, eller radianer. Vi kan omfatta alla eller ingen av deg. Värden som i sin tur måste vara under 1. För radianer, kan vi acceptera något flyta mellan 0-7. Vi vet dock att en 360° varv är 2π, och det slutar ungefär vid 6.28. Du kanske tror 6.3 och över bör inte godtas. Eftersom 2π är ett irrationellt tal, det skulle bli för rörigt för detta exempel för att försöka tillgodose varje decimal tillhandahålls av JavaScript-konsol. Dessutom har vi det här kodavsnittet i vår HSLTo_() fungerar som ett andra lager av säkerhet om nyanser 360° eller över var att hända:

// Håll nyans bråkdel av 360 om att hamna över
om h >= 360)
h %= 360;

Låt oss nu flytta upp en nivå och dechiffrera den andra burken:

(s?(([1-9]?d(.d+)?)|100|(.d+))%){2}

Vi räknar två fall av kommatecken-space-procentsatser för mättnad och ljushet (tillval). I gruppen efter ,s?, vi test för värden 0-99 med eller utan decimaler (([1-9]?d(.d+)?)), exakt 100, eller flyter under 1 utan inledande 0 ((.d+)).

Den sista delen HSL uttryck, före ending ()$/), är ett liknande uttryck om utrymmen är bara separator:

(s(([1-9]?d(.d+)?)|100|(.d+))%){2}

s är i början i stället för att ,s?. Sedan i HSLA uttryck, samma stycke är inuti en annan grupp medn? efter sin {2}.

((s?(([1-9]?d(.d+)?)|100|(.d+))%){2},s?)

Som räknar med kommatecken utrymme mellan lätthet och alpha. Sedan om vi har utrymmen som avgränsare måste vi kontrollera för en utrymme-slash-utrymme (s/s) efter att ha räknat på två tillfällen om utrymme och en procent.

((s(([1-9]?d(.d+)?)|100|(.d+))%){2}s/s))

Efter att vi har denna vänster för att kontrollera alfa-värde:

(((0?.d+)|[01])|(([1-9]?d(.d+)?)|100|(.d+))%)

Matcher (0?.d+) inkluderar flyter under 1, med eller utan inledande 0, 0 eller 1 för [01], och 0-100%.

Slutsats

Om din utmaning är att konvertera en färgrymd till en annan, nu har du några idéer om hur man närmar sig det. Eftersom det skulle vara jobbigt att gå igenom konverterar varje färg utrymme som någonsin uppfunnits i ett inlägg diskuterade vi de mest praktiska och webbläsare som stöds och kära. Om du vill gå längre än som stöds färg utrymmen (säger CMYK, XYZ, eller CIE L*a*b*), EasyRGB) ger en fantastisk uppsättning av kod-färdiga formler.

För att se alla omvandlingar visat här, jag har satt upp en CodePen demo som visar in-och utgångar i en tabell. Du kan prova olika färger på linjer 2-10 och se den kompletta funktioner i JavaScript-panel.

Se Pennan Färg Konvertering av Jon Kantner (@jkantner) på CodePen.