javascript - Ändra en enskild kanal (RGB) av en färg lagrad som ett hexadecimalt heltal


Jag skriver en färgklass som lagrar sin färg med ett enda heltal, och har r, g och b getters och setters som manipulerar/hämtar från det enda heltalet.

export default class Colour {
    private col: number;
    public get r () {
        return (this.col >> 16) & 0xFF;
    }
    public get g () {
        return (this.col >> 8) & 0xFF;
    }
    public get b () {
        return (this.col >> 0) & 0xFF;
    }
    // setters here

    constructor(colour: string);
    constructor(redGreenBlue: number);
    constructor(red: number, green: number, blue: number);
    constructor(colourOrRed: string | number, green?: number, blue?: number) {
        if (typeof colourOrRed == "string") {
            if (colourOrRed.startsWith("#")) colourOrRed = colourOrRed.slice(1);
            this.col = parseInt(colourOrRed, 16);
        } else {
            colourOrRed = Maths.clamp(colourOrRed, 0, 255);
            green = typeof green == "number" ? Maths.clamp(green, 0, 255) : colourOrRed;
            blue = typeof blue == "number" ? Maths.clamp(blue, 0, 255) : colourOrRed;
            this.col = (1 << 24) + (colourOrRed << 16) + (green << 8) + blue;
        }
    }
}

Det enda sättet att göra detta som jag har kunnat komma på är att få de andra kanalerna ur färgen, och sedan ställa in färgheltal på samma sätt som jag gör i konstruktorn.

public set r (red: number) {
    red = Maths.clamp(red, 0, 255);
    this.col = (1 << 24) + (red << 16) + (this.g << 8) + this.b;
}

Hur skulle jag gå tillväga för att ställa in de röda, gröna och blå kanalerna individuellt, utan att behöva hämta de tidigare värdena? Finns det ett sätt att göra detta? Jag antar att det finns avancerade bitvisa operationer som jag kan använda, men jag vet inte hur (de bitvisa operatorerna i denna kod kopierade jag från andra svar).

Svar #1

Du kan använda en bitmask för att hålla de andra färgkanalerna intakta och endast lägga till det begränsade värdet för den specifika kanalen; nästan på samma sätt som du extraherar färgen för en kanal, bara baklänges.

Eftersom jag inte exakt vet hur Maths.clamp() är implementerad, och hur mycket overhead den lägger till, skulle jag föredra de explicita versionerna här.

export default class Colour {
    private col: number;

    public get r () {
        return (this.col >> 16) & 0xFF;
    }
    public set r (value: number) {
        this.col = (this.col & 0x0100FFFF) | (value>0? value<255? value<<16: 0xFF0000: 0);
    }

    public get g () {
        return (this.col >> 8) & 0xFF;
    }
    public set g (value: number) {
        this.col = (this.col & 0x01FF00FF) | (value>0? value<255? value<<8: 0x00FF00: 0);
    }

    public get b () {
        return (this.col >> 0) & 0xFF;
    }
    public set b (value: number) {
        this.col = (this.col & 0x01FFFF00) | (value>0? value<255? value: 0x0000FF: 0);
    }
}

Redigera: uppdaterade maskerna för att inkludera/bevara 1<<24-biten från konstruktorn. Det är förmodligen ett trick för att undvika behovet av att lägga till ledande nollor när färgen konverteras till dess HEX-representation. Något som this.col.toString(16).substr(-6).

Relaterade artiklar