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;
    }
}