|
import { BasePostProcess } from './base.js';
|
|
|
|
|
|
|
|
|
|
export class HuePostProcess extends BasePostProcess {
|
|
constructor() {
|
|
super();
|
|
this.name = 'hue';
|
|
this.label = '色相';
|
|
this.ui = {
|
|
template: `
|
|
<div class="mb-2">
|
|
<label class="form-label">色相の変更</label>
|
|
<input type="range" class="form-range" min="0" max="359" value="0" id="hueRotate">
|
|
<div class="range-value"><span id="hueRotateValue">0</span>°</div>
|
|
</div>
|
|
`
|
|
};
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
rgbToHsl(r, g, b) {
|
|
r /= 255;
|
|
g /= 255;
|
|
b /= 255;
|
|
const max = Math.max(r, g, b);
|
|
const min = Math.min(r, g, b);
|
|
let h, s, l = (max + min) / 2;
|
|
|
|
if (max === min) {
|
|
h = s = 0;
|
|
} else {
|
|
const d = max - min;
|
|
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
|
switch (max) {
|
|
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
|
|
case g: h = (b - r) / d + 2; break;
|
|
case b: h = (r - g) / d + 4; break;
|
|
}
|
|
h /= 6;
|
|
}
|
|
|
|
return [h * 360, s * 100, l * 100];
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
hslToRgb(h, s, l) {
|
|
h /= 360;
|
|
s /= 100;
|
|
l /= 100;
|
|
let r, g, b;
|
|
|
|
if (s === 0) {
|
|
r = g = b = l;
|
|
} else {
|
|
const hue2rgb = (p, q, t) => {
|
|
if (t < 0) t += 1;
|
|
if (t > 1) t -= 1;
|
|
if (t < 1/6) return p + (q - p) * 6 * t;
|
|
if (t < 1/2) return q;
|
|
if (t < 2/3) return p + (q - p) * (2/3 - t) * 6;
|
|
return p;
|
|
};
|
|
|
|
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
|
const p = 2 * l - q;
|
|
r = hue2rgb(p, q, h + 1/3);
|
|
g = hue2rgb(p, q, h);
|
|
b = hue2rgb(p, q, h - 1/3);
|
|
}
|
|
|
|
return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async apply(canvas) {
|
|
|
|
const hueRotate = parseInt(document.getElementById('hueRotate').value);
|
|
if (hueRotate === 0) return canvas;
|
|
|
|
|
|
const newCanvas = document.createElement('canvas');
|
|
newCanvas.width = canvas.width;
|
|
newCanvas.height = canvas.height;
|
|
const ctx = newCanvas.getContext('2d');
|
|
|
|
|
|
ctx.drawImage(canvas, 0, 0);
|
|
|
|
|
|
const imageData = ctx.getImageData(0, 0, newCanvas.width, newCanvas.height);
|
|
const data = imageData.data;
|
|
|
|
|
|
for (let i = 0; i < data.length; i += 4) {
|
|
const r = data[i];
|
|
const g = data[i + 1];
|
|
const b = data[i + 2];
|
|
const a = data[i + 3];
|
|
|
|
|
|
if (a === 0) continue;
|
|
|
|
|
|
let [h, s, l] = this.rgbToHsl(r, g, b);
|
|
|
|
|
|
h = (h + hueRotate) % 360;
|
|
if (h < 0) h += 360;
|
|
|
|
|
|
const [newR, newG, newB] = this.hslToRgb(h, s, l);
|
|
|
|
|
|
data[i] = newR;
|
|
data[i + 1] = newG;
|
|
data[i + 2] = newB;
|
|
}
|
|
|
|
|
|
ctx.putImageData(imageData, 0, 0);
|
|
|
|
return newCanvas;
|
|
}
|
|
} |