Skip to content

Commit

Permalink
Supports alpha between different color functions
Browse files Browse the repository at this point in the history
  • Loading branch information
anapnoe committed Oct 2, 2024
1 parent 5fcd60d commit 83096f1
Showing 1 changed file with 67 additions and 51 deletions.
118 changes: 67 additions & 51 deletions extensions-builtin/anapnoe-sd-theme-editor/javascript/ui_theme.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,32 @@
function hexToRgb(color) {
let hex = color[0] === "#" ? color.slice(1) : color;
let c;
// Check if the color string starts with a '#' and remove it
let hex = color.startsWith("#") ? color.slice(1) : color;
let a = 1; // Default alpha value

// If the hex is 8 characters long, it includes alpha
if (hex.length === 8) {
a = parseInt(hex.slice(6, 8), 16) / 255; // Get the alpha value from the last two chars
hex = hex.slice(0, 6); // Remove the alpha from hex
} else if (hex.length === 3) {
hex = hex.split("").map((c) => c + c).join(""); // Convert 3-digit hex to 6-digit
}

// Validate hex length
if (hex.length !== 6) {
hex = (() => {
const result = [];
for (let i = 0; i < Array.from(hex).length; i++) {
c = Array.from(hex)[i];
result.push(`${c}${c}`);
}
return result;
})().join("");
throw new Error("Invalid HEX color.");
}

const colorStr = hex.match(/#?(.{2})(.{2})(.{2})/).slice(1);
const rgb = colorStr.map((col) => parseInt(col, 16));
rgb.push(1);
// Convert hex to RGB
const rgb = hex.match(/.{2}/g).map((col) => parseInt(col, 16));
rgb.push(a); // Add alpha to the RGB array
return rgb;
}

function rgbToHsl(rgb) {
const r = rgb[0] / 255;
const g = rgb[1] / 255;
const b = rgb[2] / 255;

const max = Math.max(r, g, b);
const min = Math.min(r, g, b);
const diff = max - min;
Expand All @@ -45,54 +49,59 @@ function rgbToHsl(rgb) {
diff / add :
diff / (2 - add);

// Check for alpha channel. If not present, default to 1
const alpha = rgb.length === 4 ? rgb[3] : 1;

return [
Math.round(hue),
Math.round(sat * 100),
Math.round(lum * 100),
rgb[3] || 1,
alpha,
];
}

function hexToHsl(color) {
const rgb = hexToRgb(color);
const hsl = rgbToHsl(rgb);
return `hsl(${hsl[0]}deg ${hsl[1]}% ${hsl[2]}%)`;
return `hsl(${hsl[0]}deg ${hsl[1]}% ${hsl[2]}% / ${hsl[3]})`;
}

function hslToHex(h, s, l) {
function hslToHex(h, s, l, a = 1) {
l /= 100;
const a = (s * Math.min(l, 1 - l)) / 100;

const alphaHex = ((a * 255) | 1 << 8).toString(16).slice(1); // Convert alpha to hex
const f = (n) => {
const k = (n + h / 30) % 12;
const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
return (
Math.round(255 * Math.max(0, Math.min(color, 1)))
.toString(16)
.padStart(2, "0")
);
const color = l - (s * Math.min(l, 1 - l)) / 100 * Math.max(Math.min(k - 3, 9 - k, 1), -1);
return Math.round(255 * Math.max(0, Math.min(color, 1)))
.toString(16)
.padStart(2, "0");
};

return `#${f(0)}${f(8)}${f(4)}`;
return `#${f(0)}${f(8)}${f(4)}${alphaHex}`;
}

function hsl2rgb(h, s, l) {
const a = s * Math.min(l, 1 - l);

function hsl2rgb(h, s, l, a = 1) {
const alpha = a;
const f = (n) => {
return l - a * Math.max(Math.min(n - 3, 9 - n, 1), -1);
const k = (n + h / 30) % 12;
return l - (s / 100 * Math.min(l, 1 - l)) * Math.max(Math.min(k - 3, 9 - k, 1), -1);
};

return [f(0), f(8), f(4)];
return [f(0) * 255, f(8) * 255, f(4) * 255, alpha];
}

function invertColor(hex) {
if (hex.startsWith("#")) {
hex = hex.slice(1);
hex = hex.slice(1); // Remove '#' character
}

let a = 1; // Default alpha if not provided
// If there is an alpha in the hex string (8 characters long)
if (hex.length === 8) {
a = parseInt(hex.slice(6, 8), 16) / 255;
hex = hex.slice(0, 6); // Remove the alpha from hex
}

if (hex.length === 3) {
hex = hex.split("").map((c) => c + c).join("");
hex = hex.split("").map((c) => c + c).join(""); // Convert 3-digit hex to 6-digit
}

if (hex.length !== 6) {
Expand All @@ -103,14 +112,16 @@ function invertColor(hex) {
const g = (255 - parseInt(hex.slice(2, 4), 16)).toString(16);
const b = (255 - parseInt(hex.slice(4, 6), 16)).toString(16);

return `#${padZero(r)}${padZero(g)}${padZero(b)}`;
return `#${padZero(r)}${padZero(g)}${padZero(b)}${padZero(Math.round(a * 255).toString(16))}`;
}

function padZero(str, len = 2) {
const zeros = new Array(len).join("0");
return (zeros + str).slice(-len);
}



function getValsWrappedIn(str, c1, c2) {
const rg = new RegExp(`(?<=\\${c1})(.*?)(?=\\${c2})`, "g");
return str.match(rg);
Expand All @@ -119,10 +130,10 @@ function getValsWrappedIn(str, c1, c2) {
const styleobj = {};
const hslobj = {};
let isColorsInv;
let hsloffset = [0, 0, 0];
let hsloffset = [0, 0, 0, 0];

const toHSLArray = (hslStr) =>
hslStr.match(/\d+/g).map(Number);
const toColorArray = (colStr) =>
colStr.match(/[\d.]+/g).map(Number);

function updateColorHSV(el, key, keyVal, ohsl) {
let hsl;
Expand All @@ -134,25 +145,26 @@ function updateColorHSV(el, key, keyVal, ohsl) {
styleobj[key] = hexColor;
}
hsl = rgbToHsl(hexToRgb(hexColor));
} else if (keyVal.includes("hsl")) {
} else if (keyVal.includes("hsl") || keyVal.includes("rgb")) {
hsl = keyVal.includes("rgb") ? rgbToHsl(toColorArray(keyVal)) : toColorArray(keyVal);
if (isColorsInv) {
const hslArray = toHSLArray(keyVal);
const invertedHex = hslToHex(hslArray[0], hslArray[1], hslArray[2]);
const invertedHex = hslToHex(hsl[0], hsl[1], hsl[2], hsl[3]);
styleobj[key] = invertColor(invertedHex);
hsl = rgbToHsl(hexToRgb(styleobj[key]));
} else {
hsl = toHSLArray(keyVal);
}
}

const h = (parseInt(hsl[0]) + parseInt(ohsl[0])) % 360;
const s = Math.min(Math.max(parseInt(hsl[1]) + parseInt(ohsl[1]), 0), 100);
const l = Math.min(Math.max(parseInt(hsl[2]) + parseInt(ohsl[2]), 0), 100);
const hex = hslToHex(h, s, l);
//console.log(hsl, el, key, keyVal, ohsl);

const h = ((Number(hsl[0]) || 0) + (Number(ohsl[0]) || 0)) % 360;
const s = Math.min(Math.max((Number(hsl[1]) || 0) + (Number(ohsl[1]) || 0), 0), 100);
const l = Math.min(Math.max((Number(hsl[2]) || 0) + (Number(ohsl[2]) || 0), 0), 100);
const a = Math.min(Math.max((Number(hsl[3]) || 1) + (Number(ohsl[3]) || 0), 0), 1);
const hex = hslToHex(h, s, l, a).slice(0, -2);

el.value = hex;

return `hsl(${h}deg ${s}% ${l}%)`;
return `hsla(${h}, ${s}%, ${l}%, ${a})`;
}

function offsetColorsHSV(ohsl) {
Expand Down Expand Up @@ -196,9 +208,13 @@ function updateTheme(vars) {
elem.forEach((el) => {
const inputType = el.type || 'text';
if (inputType === "color") {
if (val.includes("hsl")) {
const hsl = toHSLArray(val);
el.value = hslToHex(hsl[0], hsl[1], hsl[2]);
if (val.includes("hsl") || val.includes("rgb")) {
if (val.includes("rgb")) {
hsl = rgbToHsl(toColorArray(val));
} else {
hsl = toColorArray(val);
}
el.value = hslToHex(hsl[0], hsl[1], hsl[2], hsl[3]).slice(0, -2);
} else {
el.value = val;
}
Expand Down

0 comments on commit 83096f1

Please sign in to comment.