File size: 4,062 Bytes
79a900a |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
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>
`
};
}
/**
* RGBからHSLに変換
* @private
*/
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];
}
/**
* HSLからRGBに変換
* @private
*/
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)];
}
/**
* 色相を変更する処理を適用
* @param {HTMLCanvasElement} canvas - 処理対象のcanvas
* @returns {HTMLCanvasElement} - 処理後のcanvas
*/
async apply(canvas) {
// 色相の値を取得
const hueRotate = parseInt(document.getElementById('hueRotate').value);
if (hueRotate === 0) return canvas;
// 新しいcanvasを作成
const newCanvas = document.createElement('canvas');
newCanvas.width = canvas.width;
newCanvas.height = canvas.height;
const ctx = newCanvas.getContext('2d');
// 元のcanvasを描画
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];
// アルファ値が0の場合はスキップ
if (a === 0) continue;
// RGBからHSLに変換
let [h, s, l] = this.rgbToHsl(r, g, b);
// 色相を回転
h = (h + hueRotate) % 360;
if (h < 0) h += 360;
// HSLからRGBに変換
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;
}
} |