soiz1 commited on
Commit
1a4d940
·
verified ·
1 Parent(s): 775036b

Update script.js

Browse files
Files changed (1) hide show
  1. script.js +247 -301
script.js CHANGED
@@ -31,122 +31,115 @@ document.addEventListener('DOMContentLoaded', function() {
31
 
32
  let camanInstance = null;
33
  let originalImageData = null;
34
-
35
- // 画像アップロードの処理
36
- imageUpload.addEventListener('change', function(e) {
37
- const file = e.target.files[0];
38
- if (!file) return;
39
 
40
- showLoading();
 
 
 
41
 
42
- const reader = new FileReader();
43
- reader.onload = function(event) {
44
- const img = new Image();
45
- img.onload = function() {
46
- // キャンバスのサイズを画像に合わせる
47
- const maxWidth = 800;
48
- const maxHeight = 600;
49
- let width = img.width;
50
- let height = img.height;
51
-
52
- if (width > maxWidth) {
53
- height = (maxWidth / width) * height;
54
- width = maxWidth;
55
- }
56
-
57
- if (height > maxHeight) {
58
- width = (maxHeight / height) * width;
59
- height = maxHeight;
60
- }
61
-
62
- imageCanvas.width = width;
63
- imageCanvas.height = height;
64
-
65
- // CamanJSで画像を読み込む
66
- Caman(imageCanvas, function() {
67
- this.revert(false);
68
- this.render();
69
- camanInstance = this;
70
- originalImageData = this.canvas.toDataURL();
71
-
72
- // カーブを初期化
73
- initCurves();
74
- hideLoading();
75
- });
76
-
77
- const ctx = imageCanvas.getContext('2d');
78
- ctx.drawImage(img, 0, 0, width, height);
79
- };
80
- img.src = event.target.result;
81
- };
82
- reader.readAsDataURL(file);
83
- });
84
-
85
- // スライダーイベントの設定
86
- function setupSlider(slider, valueElement) {
87
- slider.addEventListener('input', function() {
88
- valueElement.textContent = this.value;
89
  });
90
- }
91
-
92
- setupSlider(brightnessSlider, brightnessValue);
93
- setupSlider(contrastSlider, contrastValue);
94
- setupSlider(saturationSlider, saturationValue);
95
- setupSlider(shadowsSlider, shadowsValue);
96
- setupSlider(highlightsSlider, highlightsValue);
97
-
98
- // 適用ボタンのイベントリスナー
99
- applyBtn.addEventListener('click', function() {
100
- if (!camanInstance) return;
101
- showLoading();
102
-
103
- // 非同期で処理を行う
104
- setTimeout(function() {
105
- applyFilters();
106
- hideLoading();
107
- }, 100);
108
- });
109
-
110
- // フィルターを適用する関数
111
- function applyFilters() {
112
  if (!camanInstance) return;
113
 
114
- camanInstance.revert(false);
 
 
115
 
116
- // 基本調整
117
- camanInstance.brightness(parseInt(brightnessSlider.value));
118
- camanInstance.contrast(parseInt(contrastSlider.value) * 1.5); // コントラスト強化
119
- camanInstance.saturation(parseInt(saturationSlider.value));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
120
 
121
- // RGBカーブを適用
122
- applyRgbCurves();
 
 
 
 
 
 
 
 
 
 
 
 
123
 
124
- // 輝度カーブを適用(シャドウ/ハイライト調整)
125
- applyLuminanceCurve();
 
 
 
 
126
 
127
- camanInstance.render();
128
- }
129
-
130
- // RGBカーブを初期化
131
- function initCurves() {
132
- drawCurve(redCurveCanvas, redCurvePoints, 'red');
133
- drawCurve(greenCurveCanvas, greenCurvePoints, 'green');
134
- drawCurve(blueCurveCanvas, blueCurvePoints, 'blue');
135
- drawCurve(luminanceCurveCanvas, luminanceCurvePoints, '#888');
136
 
137
- setupCurveInteraction(redCurveCanvas, redCurvePoints, 'red');
138
- setupCurveInteraction(greenCurveCanvas, greenCurvePoints, 'green');
139
- setupCurveInteraction(blueCurveCanvas, blueCurvePoints, 'blue');
140
- setupCurveInteraction(luminanceCurveCanvas, luminanceCurvePoints, '#888');
141
- }
142
-
143
- // カーブを描画
144
- function drawCurve(canvas, points, color) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
145
  const ctx = canvas.getContext('2d');
146
  const width = canvas.width;
147
  const height = canvas.height;
148
 
149
- // クリア
150
  ctx.clearRect(0, 0, width, height);
151
 
152
  // グリッドを描画
@@ -181,14 +174,11 @@ document.addEventListener('DOMContentLoaded', function() {
181
  ctx.lineWidth = 2;
182
  ctx.beginPath();
183
 
184
- // 点をソート
185
  points.sort((a, b) => a.x - b.x);
186
 
187
- // 最初の点
188
  const firstPoint = points[0];
189
  ctx.moveTo(firstPoint.x / 255 * width, (255 - firstPoint.y) / 255 * height);
190
 
191
- // 中間の点
192
  for (let i = 1; i < points.length; i++) {
193
  const point = points[i];
194
  ctx.lineTo(point.x / 255 * width, (255 - point.y) / 255 * height);
@@ -205,211 +195,182 @@ document.addEventListener('DOMContentLoaded', function() {
205
  ctx.arc(x, y, 5, 0, Math.PI * 2);
206
  ctx.fill();
207
  });
208
- }
209
-
210
- // カーブのインタラクションを設定
211
- function setupCurveInteraction(canvas, points, color) {
212
- let isDragging = false;
213
- let draggedPoint = null;
214
- let needsUpdate = false;
215
- let updateTimeout = null;
216
 
217
- canvas.addEventListener('mousedown', function(e) {
218
- const rect = canvas.getBoundingClientRect();
219
- const x = (e.clientX - rect.left) / rect.width * 255;
220
- const y = 255 - (e.clientY - rect.top) / rect.height * 255;
221
-
222
- // 既存の点をチェック
223
- for (let i = 0; i < points.length; i++) {
224
- const point = points[i];
225
- const distance = Math.sqrt(Math.pow(point.x - x, 2) + Math.pow(point.y - y, 2));
226
-
227
- if (distance < 15) {
228
- isDragging = true;
229
- draggedPoint = point;
230
- return;
231
- }
232
- }
233
-
234
- // 新しい点を追加
235
- if (x > 0 && x < 255 && y > 0 && y < 255) {
236
- points.push({x, y});
237
- points.sort((a, b) => a.x - b.x);
238
- isDragging = true;
239
- draggedPoint = {x, y};
240
- }
241
-
242
- drawCurve(canvas, points, color);
243
- needsUpdate = true;
244
- });
245
-
246
- canvas.addEventListener('mousemove', function(e) {
247
- if (!isDragging || !draggedPoint) return;
248
-
249
- const rect = canvas.getBoundingClientRect();
250
- let x = (e.clientX - rect.left) / rect.width * 255;
251
- let y = 255 - (e.clientY - rect.top) / rect.height * 255;
252
-
253
- // 境界チェック
254
- x = Math.max(0, Math.min(255, x));
255
- y = Math.max(0, Math.min(255, y));
256
-
257
- // 最初と最後の点はx座標を固定
258
- if (points.indexOf(draggedPoint) === 0) {
259
- x = 0;
260
- } else if (points.indexOf(draggedPoint) === points.length - 1) {
261
- x = 255;
262
- }
263
-
264
- draggedPoint.x = x;
265
- draggedPoint.y = y;
266
-
267
- drawCurve(canvas, points, color);
268
- needsUpdate = true;
269
-
270
- // リアルタイムプレビュー更新(デバウンス付き)
271
- if (updateTimeout) clearTimeout(updateTimeout);
272
- updateTimeout = setTimeout(() => {
273
- if (needsUpdate) {
274
  applyFilters();
275
- needsUpdate = false;
276
  }
277
- }, 200);
278
- });
279
-
280
- canvas.addEventListener('mouseup', function() {
281
- isDragging = false;
282
- draggedPoint = null;
283
- if (needsUpdate) {
284
- applyFilters();
285
- needsUpdate = false;
286
- }
287
- });
288
-
289
- canvas.addEventListener('mouseleave', function() {
290
- isDragging = false;
291
- draggedPoint = null;
292
- if (needsUpdate) {
293
- applyFilters();
294
- needsUpdate = false;
295
- }
296
- });
297
-
298
- // ポイントを削除するダブルクリック
299
- canvas.addEventListener('dblclick', function(e) {
300
- if (points.length <= 2) return;
301
-
302
- const rect = canvas.getBoundingClientRect();
303
- const x = (e.clientX - rect.left) / rect.width * 255;
304
- const y = 255 - (e.clientY - rect.top) / rect.height * 255;
305
 
306
- for (let i = 1; i < points.length - 1; i++) {
307
- const point = points[i];
308
- const distance = Math.sqrt(Math.pow(point.x - x, 2) + Math.pow(point.y - y, 2));
 
309
 
310
- if (distance < 15) {
311
- points.splice(i, 1);
312
- drawCurve(canvas, points, color);
313
- applyFilters();
314
- return;
 
 
 
 
315
  }
316
- }
317
- });
318
- }
319
-
320
- function applyFilters() {
321
- if (!camanInstance) return;
322
-
323
- // ローディング表示なしで直接適用
324
- camanInstance.revert(false);
325
-
326
- // 基本調整
327
- camanInstance.brightness(parseInt(brightnessSlider.value));
328
- camanInstance.contrast(parseInt(contrastSlider.value) * 1.5);
329
- camanInstance.saturation(parseInt(saturationSlider.value));
330
-
331
- // RGBカーブを適用
332
- applyRgbCurves();
333
-
334
- // 輝度カーブを適用
335
- applyLuminanceCurve();
336
-
337
- camanInstance.render();
338
- }
339
-
340
- // 輝度カーブを適用(連続的なシャドウ/ハイライト調整)
341
- function applyLuminanceCurve() {
342
- if (!camanInstance) return;
343
-
344
- const luminanceCurve = createCurveData(luminanceCurvePoints);
345
- const shadowAmount = parseInt(shadowsSlider.value) / 100 * 50; // -50から50の範囲に調整
346
- const highlightAmount = parseInt(highlightsSlider.value) / 100 * 50;
347
-
348
- camanInstance.process("luminanceAdjustment", function(rgba) {
349
- // ピクセルの輝度を計算
350
- const luminance = 0.299 * rgba.r + 0.587 * rgba.g + 0.114 * rgba.b;
351
 
352
- // 輝度カーブから調整値を取得
353
- const curveAdjustment = (luminanceCurve[luminance] - luminance) / 255 * 100;
 
 
 
 
354
 
355
- // シャドウ/ハイライト調整を適用
356
- let adjustment = 0;
 
 
 
357
 
358
- // シャドウ調整(低輝度ほど強く適用)
359
- if (shadowAmount !== 0) {
360
- const shadowFactor = 1 - (luminance / 255); // 0(明るい)~1(暗い)
361
- adjustment += shadowAmount * shadowFactor;
362
- }
363
 
364
- // ハイライト調整(高輝度ほど強く適用)
365
- if (highlightAmount !== 0) {
366
- const highlightFactor = luminance / 255; // 0(暗い)~1(明るい)
367
- adjustment += highlightAmount * highlightFactor;
 
 
 
368
  }
369
 
370
- // 輝度カーブの調整を追加
371
- adjustment += curveAdjustment;
372
 
373
- // 調整を適用
374
- rgba.r = Math.min(255, Math.max(0, rgba.r + adjustment));
375
- rgba.g = Math.min(255, Math.max(0, rgba.g + adjustment));
376
- rgba.b = Math.min(255, Math.max(0, rgba.b + adjustment));
377
-
378
- return rgba;
379
  });
380
- }
381
-
382
- // カーブデータを作成
383
- function createCurveData(points) {
384
- points.sort((a, b) => a.x - b.x);
385
- const curve = new Array(256);
386
 
387
- for (let i = 0; i < points.length - 1; i++) {
388
- const start = points[i];
389
- const end = points[i + 1];
 
 
 
 
 
 
 
 
 
 
 
 
 
390
 
391
- const x1 = Math.round(start.x);
392
- const y1 = Math.round(start.y);
393
- const x2 = Math.round(end.x);
394
- const y2 = Math.round(end.y);
395
 
396
- // 線形補間
397
- for (let x = x1; x <= x2; x++) {
398
- const t = (x - x1) / (x2 - x1);
399
- curve[x] = Math.round(y1 + t * (y2 - y1));
 
 
 
 
 
 
400
  }
401
- }
 
 
 
 
 
 
 
 
402
 
403
- return curve;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
404
  }
405
 
 
 
 
 
 
 
 
 
 
406
  // リセットボタン
407
  resetBtn.addEventListener('click', function() {
408
  if (!camanInstance) return;
409
 
410
- showLoading();
411
-
412
- // スライダーをリセット
413
  brightnessSlider.value = 0;
414
  contrastSlider.value = 0;
415
  saturationSlider.value = 0;
@@ -422,18 +383,13 @@ function applyFilters() {
422
  shadowsValue.textContent = '0';
423
  highlightsValue.textContent = '0';
424
 
425
- // カーブをリセット
426
  redCurvePoints = [{x: 0, y: 0}, {x: 255, y: 255}];
427
  greenCurvePoints = [{x: 0, y: 0}, {x: 255, y: 255}];
428
  blueCurvePoints = [{x: 0, y: 0}, {x: 255, y: 255}];
429
  luminanceCurvePoints = [{x: 0, y: 0}, {x: 255, y: 255}];
430
 
431
- drawCurve(redCurveCanvas, redCurvePoints, 'red');
432
- drawCurve(greenCurveCanvas, greenCurvePoints, 'green');
433
- drawCurve(blueCurveCanvas, blueCurvePoints, 'blue');
434
- drawCurve(luminanceCurveCanvas, luminanceCurvePoints, '#888');
435
 
436
- // 画像をリセット
437
  const img = new Image();
438
  img.onload = function() {
439
  const ctx = imageCanvas.getContext('2d');
@@ -443,7 +399,6 @@ function applyFilters() {
443
  this.revert(false);
444
  this.render();
445
  camanInstance = this;
446
- hideLoading();
447
  });
448
  };
449
  img.src = originalImageData;
@@ -458,13 +413,4 @@ function applyFilters() {
458
  link.href = imageCanvas.toDataURL('image/png');
459
  link.click();
460
  });
461
-
462
- // 読み込み表示を制御する関数
463
- function showLoading() {
464
- loadingOverlay.style.display = 'flex';
465
- }
466
-
467
- function hideLoading() {
468
- loadingOverlay.style.display = 'none';
469
- }
470
  });
 
31
 
32
  let camanInstance = null;
33
  let originalImageData = null;
34
+ let isApplyingFilters = false;
35
+
36
+ // RGBカーブを適用する関数
37
+ const applyRgbCurves = function() {
38
+ if (!camanInstance) return;
39
 
40
+ // カーブデータを準備
41
+ const redCurve = createCurveData(redCurvePoints);
42
+ const greenCurve = createCurveData(greenCurvePoints);
43
+ const blueCurve = createCurveData(blueCurvePoints);
44
 
45
+ // カーブを適用
46
+ this.process("rgbCurve", function(rgba) {
47
+ rgba.r = redCurve[rgba.r];
48
+ rgba.g = greenCurve[rgba.g];
49
+ rgba.b = blueCurve[rgba.b];
50
+ return rgba;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
  });
52
+ };
53
+
54
+ // 輝度カーブを適用する関数
55
+ const applyLuminanceCurve = function() {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56
  if (!camanInstance) return;
57
 
58
+ const luminanceCurve = createCurveData(luminanceCurvePoints);
59
+ const shadowAmount = parseInt(shadowsSlider.value) / 100 * 50;
60
+ const highlightAmount = parseInt(highlightsSlider.value) / 100 * 50;
61
 
62
+ this.process("luminanceAdjustment", function(rgba) {
63
+ const luminance = 0.299 * rgba.r + 0.587 * rgba.g + 0.114 * rgba.b;
64
+ const curveAdjustment = (luminanceCurve[luminance] - luminance) / 255 * 100;
65
+
66
+ let adjustment = 0;
67
+
68
+ if (shadowAmount !== 0) {
69
+ const shadowFactor = 1 - (luminance / 255);
70
+ adjustment += shadowAmount * shadowFactor;
71
+ }
72
+
73
+ if (highlightAmount !== 0) {
74
+ const highlightFactor = luminance / 255;
75
+ adjustment += highlightAmount * highlightFactor;
76
+ }
77
+
78
+ adjustment += curveAdjustment;
79
+
80
+ rgba.r = Math.min(255, Math.max(0, rgba.r + adjustment));
81
+ rgba.g = Math.min(255, Math.max(0, rgba.g + adjustment));
82
+ rgba.b = Math.min(255, Math.max(0, rgba.b + adjustment));
83
+
84
+ return rgba;
85
+ });
86
+ };
87
+
88
+ // カーブデータを作成する関数
89
+ const createCurveData = function(points) {
90
+ points.sort((a, b) => a.x - b.x);
91
+ const curve = new Array(256);
92
 
93
+ for (let i = 0; i < points.length - 1; i++) {
94
+ const start = points[i];
95
+ const end = points[i + 1];
96
+
97
+ const x1 = Math.round(start.x);
98
+ const y1 = Math.round(start.y);
99
+ const x2 = Math.round(end.x);
100
+ const y2 = Math.round(end.y);
101
+
102
+ for (let x = x1; x <= x2; x++) {
103
+ const t = (x - x1) / (x2 - x1);
104
+ curve[x] = Math.round(y1 + t * (y2 - y1));
105
+ }
106
+ }
107
 
108
+ return curve;
109
+ };
110
+
111
+ // フィルターを適用する関数
112
+ const applyFilters = function() {
113
+ if (!camanInstance || isApplyingFilters) return;
114
 
115
+ isApplyingFilters = true;
 
 
 
 
 
 
 
 
116
 
117
+ try {
118
+ camanInstance.revert(false);
119
+
120
+ camanInstance.newLayer(function() {
121
+ this.brightness(parseInt(brightnessSlider.value));
122
+ this.contrast(parseInt(contrastSlider.value) * 1.5);
123
+ this.saturation(parseInt(saturationSlider.value));
124
+
125
+ applyRgbCurves.call(this);
126
+ applyLuminanceCurve.call(this);
127
+ });
128
+
129
+ camanInstance.render();
130
+ } catch (e) {
131
+ console.error("Error applying filters:", e);
132
+ } finally {
133
+ isApplyingFilters = false;
134
+ }
135
+ };
136
+
137
+ // カーブを描画する関数
138
+ const drawCurve = function(canvas, points, color) {
139
  const ctx = canvas.getContext('2d');
140
  const width = canvas.width;
141
  const height = canvas.height;
142
 
 
143
  ctx.clearRect(0, 0, width, height);
144
 
145
  // グリッドを描画
 
174
  ctx.lineWidth = 2;
175
  ctx.beginPath();
176
 
 
177
  points.sort((a, b) => a.x - b.x);
178
 
 
179
  const firstPoint = points[0];
180
  ctx.moveTo(firstPoint.x / 255 * width, (255 - firstPoint.y) / 255 * height);
181
 
 
182
  for (let i = 1; i < points.length; i++) {
183
  const point = points[i];
184
  ctx.lineTo(point.x / 255 * width, (255 - point.y) / 255 * height);
 
195
  ctx.arc(x, y, 5, 0, Math.PI * 2);
196
  ctx.fill();
197
  });
198
+ };
 
 
 
 
 
 
 
199
 
200
+ // カーブのインタラクションを設定
201
+ const setupCurveInteraction = function(canvas, points, color) {
202
+ let isDragging = false;
203
+ let draggedPoint = null;
204
+ let lastUpdateTime = 0;
205
+
206
+ const handleUpdate = function() {
207
+ drawCurve(canvas, points, color);
208
+ const now = Date.now();
209
+ if (now - lastUpdateTime > 200) { // 200msごとに更新
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
210
  applyFilters();
211
+ lastUpdateTime = now;
212
  }
213
+ };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
214
 
215
+ canvas.addEventListener('mousedown', function(e) {
216
+ const rect = canvas.getBoundingClientRect();
217
+ const x = (e.clientX - rect.left) / rect.width * 255;
218
+ const y = 255 - (e.clientY - rect.top) / rect.height * 255;
219
 
220
+ for (let i = 0; i < points.length; i++) {
221
+ const point = points[i];
222
+ const distance = Math.sqrt(Math.pow(point.x - x, 2) + Math.pow(point.y - y, 2));
223
+
224
+ if (distance < 15) {
225
+ isDragging = true;
226
+ draggedPoint = point;
227
+ break;
228
+ }
229
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
230
 
231
+ if (!isDragging && x > 0 && x < 255 && y > 0 && y < 255) {
232
+ points.push({x, y});
233
+ points.sort((a, b) => a.x - b.x);
234
+ isDragging = true;
235
+ draggedPoint = points.find(p => p.x === x && p.y === y);
236
+ }
237
 
238
+ handleUpdate();
239
+ });
240
+
241
+ canvas.addEventListener('mousemove', function(e) {
242
+ if (!isDragging || !draggedPoint) return;
243
 
244
+ const rect = canvas.getBoundingClientRect();
245
+ let x = (e.clientX - rect.left) / rect.width * 255;
246
+ let y = 255 - (e.clientY - rect.top) / rect.height * 255;
 
 
247
 
248
+ x = Math.max(0, Math.min(255, x));
249
+ y = Math.max(0, Math.min(255, y));
250
+
251
+ if (points.indexOf(draggedPoint) === 0) {
252
+ x = 0;
253
+ } else if (points.indexOf(draggedPoint) === points.length - 1) {
254
+ x = 255;
255
  }
256
 
257
+ draggedPoint.x = x;
258
+ draggedPoint.y = y;
259
 
260
+ handleUpdate();
 
 
 
 
 
261
  });
 
 
 
 
 
 
262
 
263
+ canvas.addEventListener('mouseup', function() {
264
+ if (isDragging) {
265
+ isDragging = false;
266
+ applyFilters(); // 最後に確実に適用
267
+ }
268
+ });
269
+
270
+ canvas.addEventListener('mouseleave', function() {
271
+ if (isDragging) {
272
+ isDragging = false;
273
+ applyFilters(); // 最後に確実に適用
274
+ }
275
+ });
276
+
277
+ canvas.addEventListener('dblclick', function(e) {
278
+ if (points.length <= 2) return;
279
 
280
+ const rect = canvas.getBoundingClientRect();
281
+ const x = (e.clientX - rect.left) / rect.width * 255;
282
+ const y = 255 - (e.clientY - rect.top) / rect.height * 255;
 
283
 
284
+ for (let i = 1; i < points.length - 1; i++) {
285
+ const point = points[i];
286
+ const distance = Math.sqrt(Math.pow(point.x - x, 2) + Math.pow(point.y - y, 2));
287
+
288
+ if (distance < 15) {
289
+ points.splice(i, 1);
290
+ drawCurve(canvas, points, color);
291
+ applyFilters();
292
+ break;
293
+ }
294
  }
295
+ });
296
+ };
297
+
298
+ // 初期化関数
299
+ const initCurves = function() {
300
+ drawCurve(redCurveCanvas, redCurvePoints, 'red');
301
+ drawCurve(greenCurveCanvas, greenCurvePoints, 'green');
302
+ drawCurve(blueCurveCanvas, blueCurvePoints, 'blue');
303
+ drawCurve(luminanceCurveCanvas, luminanceCurvePoints, '#888');
304
 
305
+ setupCurveInteraction(redCurveCanvas, redCurvePoints, 'red');
306
+ setupCurveInteraction(greenCurveCanvas, greenCurvePoints, 'green');
307
+ setupCurveInteraction(blueCurveCanvas, blueCurvePoints, 'blue');
308
+ setupCurveInteraction(luminanceCurveCanvas, luminanceCurvePoints, '#888');
309
+ };
310
+
311
+ // 画像アップロードの処理
312
+ imageUpload.addEventListener('change', function(e) {
313
+ const file = e.target.files[0];
314
+ if (!file) return;
315
+
316
+ const reader = new FileReader();
317
+ reader.onload = function(event) {
318
+ const img = new Image();
319
+ img.onload = function() {
320
+ const maxWidth = 800;
321
+ const maxHeight = 600;
322
+ let width = img.width;
323
+ let height = img.height;
324
+
325
+ if (width > maxWidth) {
326
+ height = (maxWidth / width) * height;
327
+ width = maxWidth;
328
+ }
329
+
330
+ if (height > maxHeight) {
331
+ width = (maxHeight / height) * width;
332
+ height = maxHeight;
333
+ }
334
+
335
+ imageCanvas.width = width;
336
+ imageCanvas.height = height;
337
+
338
+ Caman(imageCanvas, function() {
339
+ this.revert(false);
340
+ this.render();
341
+ camanInstance = this;
342
+ originalImageData = this.canvas.toDataURL();
343
+ initCurves();
344
+ });
345
+
346
+ const ctx = imageCanvas.getContext('2d');
347
+ ctx.drawImage(img, 0, 0, width, height);
348
+ };
349
+ img.src = event.target.result;
350
+ };
351
+ reader.readAsDataURL(file);
352
+ });
353
+
354
+ // スライダーイベントの設定
355
+ function setupSlider(slider, valueElement) {
356
+ slider.addEventListener('input', function() {
357
+ valueElement.textContent = this.value;
358
+ });
359
  }
360
 
361
+ setupSlider(brightnessSlider, brightnessValue);
362
+ setupSlider(contrastSlider, contrastValue);
363
+ setupSlider(saturationSlider, saturationValue);
364
+ setupSlider(shadowsSlider, shadowsValue);
365
+ setupSlider(highlightsSlider, highlightsValue);
366
+
367
+ // 適用ボタン
368
+ applyBtn.addEventListener('click', applyFilters);
369
+
370
  // リセットボタン
371
  resetBtn.addEventListener('click', function() {
372
  if (!camanInstance) return;
373
 
 
 
 
374
  brightnessSlider.value = 0;
375
  contrastSlider.value = 0;
376
  saturationSlider.value = 0;
 
383
  shadowsValue.textContent = '0';
384
  highlightsValue.textContent = '0';
385
 
 
386
  redCurvePoints = [{x: 0, y: 0}, {x: 255, y: 255}];
387
  greenCurvePoints = [{x: 0, y: 0}, {x: 255, y: 255}];
388
  blueCurvePoints = [{x: 0, y: 0}, {x: 255, y: 255}];
389
  luminanceCurvePoints = [{x: 0, y: 0}, {x: 255, y: 255}];
390
 
391
+ initCurves();
 
 
 
392
 
 
393
  const img = new Image();
394
  img.onload = function() {
395
  const ctx = imageCanvas.getContext('2d');
 
399
  this.revert(false);
400
  this.render();
401
  camanInstance = this;
 
402
  });
403
  };
404
  img.src = originalImageData;
 
413
  link.href = imageCanvas.toDataURL('image/png');
414
  link.click();
415
  });
 
 
 
 
 
 
 
 
 
416
  });