Elke waarde die hier gelezen wordt komt uit het gedecodeerde bestand en niet uit het plaatje op je scherm, en die twee lopen uiteen zodra een foto wordt geschaald om in een kolom te passen. Het dominante palet naast de afbeelding wordt geclusterd in plaats van in bakjes gestopt, en daarom komt een foto met bladeren erin niet terug als zes vrijwel identieke bruinen. Het bestand wordt in dit tabblad gedecodeerd en er wordt geen kopie bewaard.
k-means in OKLab, geen bakjes in sRGB
Het palet wordt perceptueel geclusterd. Elke bemonsterde pixel gaat naar OKLab, waar gelijke afstanden er als gelijke verschillen uitzien, en de stalen zijn de middelpunten van de clusters die daar gevonden worden. Het gebruikelijke alternatief is histogrambakjes: hak de kanalen rood, groen en blauw elk in een paar bakjes, tel, en geef de volste bakjes terug. De assen van sRGB liggen niet zoals het oog werkt, dus dat doet twee dingen tegelijk verkeerd. Het splitst één waargenomen kleur over naburige bakjes, omdat een bakrand midden in een lucht valt in plaats van tussen de lucht en het dak, en het voegt kleuren samen die totaal niet op elkaar lijken, omdat het donkere uiteinde van elk kanaal samengedrukt is en een plak zichtbaar verschillende donkergroenen en bruinen in één bakje landt. Het gemiddelde van die tellingen levert dan een middentoon op die in geen enkele pixel van de foto voorkomt. Dat is het mechanisme achter de zes vrijwel identieke bruinen die de meeste gratis extractors teruggeven bij elke foto met bladeren erin.
k-means zelf bestaat uit drie stappen. Zet k middelpunten tussen de bemonsterde kleuren, wijs elk monster toe aan het middelpunt dat er het dichtst bij ligt, en verplaats daarna elk middelpunt naar het gemiddelde van de monsters die het kozen. Herhaal tot er geen monster meer wisselt, wat het algoritme van Lloyd is, en de middelpunten komen tot rust waar de kleuren zich werkelijk verzamelen in plaats van op een raster dat iemand vooraf koos.
De details bepalen het resultaat. Er worden 24.000 pixels bemonsterd, met een stap die relatief priem is met de breedte van de afbeelding zodat een herhalende verticale structuur zoals een hek niet elke keer of juist nooit bemonsterd wordt. De startmiddelpunten worden op de manier van k-means++ uit elkaar gezet, zodat acht startpunten niet allemaal landen in een lucht die 70% van het beeld vult. Twee middelpunten die dichter dan 0,008 in OKLab bij elkaar liggen, ongeveer een kwart van een net waarneembaar verschil, worden samengenomen, en daarom kan een vraag om 8 stalen er 6 opleveren bij een afbeelding die 6 kleuren heeft. De seed ligt vast, dus dezelfde afbeelding geeft elke keer hetzelfde palet.
Waarom er een loep is
De pixel onder je cursor is niet de pixel die je denkt aan te klikken, tenzij de afbeelding op 1:1 getekend wordt. Een foto van 4000 pixels breed in een kolom van 900 pixels wordt door de browser geschaald om te passen, dus wat je op een punt ziet is een menging van meerdere bronpixels, en een menging verzint kleuren: de grens tussen een rood dak en een blauwe lucht wordt getoond als een rij paarsen die nooit gefotografeerd zijn. De loep leest in plaats daarvan het gedecodeerde bestand: het blok van 11 bij 11 rond de cursor op volledige resolutie, met imageSmoothingEnabled uit, zodat elk vakje één echte pixel uit het bestand is en het vakje in de zwart-witte ring in het midden precies de waarde is die gekopieerd wordt.
Wat een uitlezing van het canvas je over kleur kan vertellen, en wat niet
Een uitlezing van het canvas geeft de gedecodeerde sRGB-waarde terug, niet de kleur die je monitor uitstraalt. De browser past tijdens het decoderen het ingebedde ICC-profiel van de afbeelding toe en zet het resultaat om naar sRGB voor een standaard 2D-context, volgens de HTML-specificatie. Een bestand met het label Display P3, Adobe RGB of ProPhoto komt hier dus al omgezet aan, waarbij alles buiten sRGB naar het dichtstbijzijnde sRGB-equivalent is gebracht, en een bestand zonder profiel wordt als sRGB beschouwd. Een viewer met kleurbeheer stuurt datzelfde bestand in zijn eigen ruimte naar een scherm met een breed gamut, waar het zichtbaar verzadigder kan ogen dan de hex hier suggereert. De hex is nog steeds het juiste antwoord voor het web, waar een kleur zonder label sRGB betekent, en het verkeerde antwoord om een drukproef of een P3-asset na te maken: haal die getallen uit een programma dat het bronprofiel bewaart.
Veelvoorkomende problemen
- De hex komt niet overeen met wat een fotobewerker meldt. Meestal het profiel, om de reden hierboven: een bewerker met een andere werkruimte dan sRGB leest dezelfde bytes tegen een andere definitie van rood, groen en blauw. Vergelijk in sRGB voordat je aanneemt dat een van beide fout is.
- Eén kleur vult het grootste deel van het palet. k-means verdeelt naar oppervlak, en een schermafbeelding van een interface is grotendeels één achtergrond. Snijd het deel uit waar het je om gaat en laat de rest vallen.
- De opgehaalde kleur ligt dicht bij je merkkleur maar is hem niet. Een centroïde is het gemiddelde van een cluster, dus die landt in de buurt van de kleuren erin en zelden op een van die kleuren. Heb je de exacte waarde nodig, gebruik dan de loep en klik de pixel aan.
- Er gebeurt niets als ik een bestand neerzet. De browser kon het niet decoderen. Camera raw en, buiten Safari, HEIC zijn de gebruikelijke gevallen. Exporteer eerst een JPEG of PNG.
Veelgestelde vragen
Wordt mijn afbeelding ergens geüpload?
Nee. Het bestand wordt met createImageBitmap gedecodeerd en in dit tabblad op een canvas getekend, en elke pixeluitlezing, omrekening en clustering gebeurt daar. Er is geen server om het naartoe te sturen, en het enige dat ooit in de URL komt is het aantal stalen, als ?k=. De rest van de kleurtools werkt op dezelfde manier.
Waarom is het palet anders dan dat van een andere extractor?
Omdat de ruimte en de methode verschillen, en die veranderen allebei het antwoord. Een extractor met histogrambakjes in sRGB geeft gemiddelden per bakje terug; dit geeft middelpunten van clusters in een perceptuele ruimte. Twee k-means-implementaties verschillen ook als hun startpunten willekeurig zijn, en daarom geven veel extractors bij elke herlading van dezelfde foto een ander palet. Deze gebruikt een vaste seed en vaste tiebreaks, dus deze niet.
Welke beeldformaten kan ik neerzetten?
Wat je browser decodeert: JPEG, PNG, WebP, GIF, AVIF, BMP, ICO en SVG in elke huidige browser. Een bewegende GIF of WebP wordt als zijn eerste frame gelezen. Rawbestanden van een camera zijn voor een browser geen afbeeldingen, en HEIC decodeert alleen in Safari.
Werkt het zonder muis?
Ja. De afbeelding is focusbaar, de pijltoetsen verplaatsen de cursor één pixel en met shift tien, Enter of spatie bewaart de kleur, en elke verplaatsing wordt via een live region aangekondigd met coördinaten, hex en de dichtstbijzijnde CSS-kleurnaam. Elk staal op de pagina draagt zijn hex als tekst en niet alleen als vulling, dus niets hier hangt af van het zien van de kleur.
Wat gebeurt er met transparantie?
Een gekozen pixel houdt zijn alpha, en de waarde laat dat zien: een half doorzichtige pixel is niet de kleur die hij op de achtergrond van deze pagina lijkt. De paletronde is strenger en slaat alles onder 50% dekking over, want een volledig transparante pixel is bijna altijd transparant zwart, en een logo met een grote lege rand zou anders met zwart als dominante kleur terugkomen.
Wordt het traag van een heel grote foto?
Nauwelijks. De kosten van het clusteren worden bepaald door de steekproef van 24.000 en niet door het bestand, dus een foto van 40 megapixel kost ongeveer wat een van 2 megapixel kost: ruwweg 70 ms voor 8 stalen op een desktop, een paar honderd milliseconden op een trage telefoon. Boven 4 megapixel wordt de afbeelding voor de paletronde kleiner opnieuw getekend, met smoothing uit, zodat een telefoon nooit om één enorme allocatie wordt gevraagd. Op het kiezen heeft dat geen invloed: de loep en elke gekozen pixel worden uit het bestand op volledige resolutie gelezen.