709 Stimmen

Programmatisch eine Hex-Farbe aufhellen oder abdunkeln (oder rgb, und Farben mischen)

Hier ist eine Funktion, an der ich gearbeitet habe, um eine hexadezimale Farbe programmatisch um einen bestimmten Betrag aufzuhellen oder abzudunkeln. Geben Sie einfach eine Zeichenkette ein wie "3F6D2A" für die Farbe ( col ) und eine ganze Zahl zur Basis 10 ( amt ) für die Menge, die aufgehellt oder verdunkelt werden soll. Um abzudunkeln, geben Sie eine negative Zahl ein (d. h. -20 ).

Der Grund dafür war, dass alle Lösungen, die ich bisher gefunden habe, das Problem zu kompliziert zu machen schienen. Und ich hatte das Gefühl, dass es mit nur ein paar Zeilen Code getan werden könnte. Bitte lassen Sie mich wissen, wenn Sie irgendwelche Probleme finden oder Anpassungen vornehmen möchten, die das Ganze beschleunigen würden.

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

Für den Einsatz in der Entwicklung gibt es hier eine leichter zu lesende Version:

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

Und schließlich eine Version zur Behandlung von Farben, die das "#" am Anfang haben (oder auch nicht). Und eine Anpassung für unpassende Farbwerte:

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, es sind also nicht nur ein paar Zeilen, aber es scheint viel einfacher zu sein, und wenn Sie das "#" nicht verwenden und nicht auf Farben außerhalb des Bereichs prüfen müssen, sind es auch nur ein paar Zeilen.

Wenn Sie das "#" nicht verwenden, können Sie es einfach in den Code einfügen:

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

Meine Hauptfrage ist wohl, ob ich hier richtig liege. Umfasst dies nicht auch einige (normale) Situationen?

9voto

Natan Braslavski Punkte 780

Basierend auf der obigen Antwort von David Sherret und Pablo wurde die Lösung in eine sicherere Version für Typescript umgewandelt

/**
 * @param color Hex value format: #ffffff or ffffff
 * @param decimal lighten or darken decimal value, example 0.5 to lighten by 50% or 1.5 to darken by 50%.
 */
static shadeColor(color: string, decimal: number): string {
    const base = color.startsWith('#') ? 1 : 0;

    let r = parseInt(color.substring(base, 3), 16);
    let g = parseInt(color.substring(base + 2, 5), 16);
    let b = parseInt(color.substring(base + 4, 7), 16);

    r = Math.round(r / decimal);
    g = Math.round(g / decimal);
    b = Math.round(b / decimal);

    r = (r < 255)? r : 255;
    g = (g < 255)? g : 255;
    b = (b < 255)? b : 255;

    const rr = ((r.toString(16).length === 1)? `0${r.toString(16)}` : r.toString(16));
    const gg = ((g.toString(16).length === 1)? `0${g.toString(16)}` : g.toString(16));
    const bb = ((b.toString(16).length === 1)? `0${b.toString(16)}` : b.toString(16));

    return `#${rr}${gg}${bb}`;
}

6voto

Cool Acid Punkte 153

Ich habe Ihre Funktion ausprobiert und es gab einen kleinen Fehler: Wenn der endgültige 'r'-Wert nur 1 Ziffer ist, sieht das Ergebnis so aus: a0a0a', wenn der richtige Wert z.B. '0a0a0a' ist. Ich habe das Problem schnell behoben, indem ich dies anstelle der Rückgabe hinzugefügt habe:

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;

Vielleicht ist es nicht so schön, aber es macht die Arbeit. Tolle Funktion, BTW. Genau das, was ich brauchte :)

5voto

Ich wollte eine Farbe in eine Farbe ändern spezifisch Helligkeitsstufe - egal, welche Helligkeit die Farbe vorher hatte - hier ist eine einfache JS-Funktion, die gut zu funktionieren scheint, obwohl ich sicher bin, dass sie kürzer sein könnte

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

5voto

Kamil Kiełczewski Punkte 69048

Ihr Ansatz ist in Ordnung :) Ich vereinfache deine kürzeste Version ein wenig (für Sättigungskontrolle aussehen aquí )

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

// Similar to OP shortest version, we not have here # and colors range checking

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

// ------
// TEST
// ------

function update() {
  let c= col.value.padEnd(6,'0').slice(0,6);
  let color = '#'+LightenDarkenColor(c, +amt.value);
  oldColor.innerHTML = 'Old: #'+c;
  oldColor.style = `background: #${c}`;
  newColor.innerHTML = 'New: '+color
  newColor.style = `background: ${color}`;

}

update();

.box{ width: 100px; height: 100px; margin: 10px; display: inline-block}

<input id="col" value="3F6D2A" oninput="update()">
<input id="amt" value="30" oninput="update()"><br>
<div id="oldColor" class="box"></div>
<div id="newColor" class="box"></div>

Und Version mit # und Farbbereichskontrolle

// # and colors range checking

var LightenDarkenColor = 
     (col,amt) => '#'+col.slice(1).match(/../g)
                         .map(x=>(x=+`0x${x}`+amt,x<0?0:(x>255?255:x))
                         .toString(16).padStart(2,0)).join``;

// ------
// TEST
// ------

function update() {
  let c= col.value.padEnd(6,'0').slice(0,7);
  let color = LightenDarkenColor(c, +amt.value);
  oldColor.innerHTML = 'Old: '+c;
  oldColor.style = `background: ${c}`;
  newColor.innerHTML = 'New: '+color
  newColor.style = `background: ${color}`;
}

update();

.box{ width: 100px; height: 100px; margin: 10px; display: inline-block}

<input id="col" value="#3F6D2A" oninput="update()">
<input id="amt" value="40" oninput="update()"><br>
<div id="oldColor" class="box"></div>
<div id="newColor" class="box"></div>

5voto

James Khoury Punkte 19930

Haben Sie über eine rgb > hsl-Konvertierung nachgedacht? dann bewegen Sie einfach die Luminosity nach oben und unten? das ist der Weg, den ich gehen würde.

Eine schnelle Suche nach einigen Algorithmen führte mich zu den folgenden Websites.

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

EDIT der obige Link ist nicht mehr gültig. Sie können den Git-Hub für die Seitenquelle oder die .

Alternativ dazu ein anderes StackOverflow Frage könnte eine gute Anlaufstelle sein.


Auch wenn dies nicht die richtige Wahl für die OP ist, ist das Folgende eine Annäherung an den Code, den ich ursprünglich vorgeschlagen habe. (Vorausgesetzt, Sie haben rgb/hsl Konvertierungsfunktionen)

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

Dies wird vorausgesetzt:

  1. Sie haben Funktionen hslToRgb y rgbToHsl .
  2. Der Parameter colorValue ist eine Zeichenkette in der Form #RRGGBB

Obwohl, wenn wir über css diskutieren, gibt es eine Syntax für die Angabe von hsl/hsla für IE9/Chrome/Firefox.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X