| 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="180" id="hueRotate">
|
| <div class="range-value"><span id="hueRotateValue">180</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;
|
| }
|
| } |