soiz1 commited on
Commit
f08a4ef
·
verified ·
1 Parent(s): fc33e28

Update script.js

Browse files
Files changed (1) hide show
  1. script.js +142 -31
script.js CHANGED
@@ -16,7 +16,9 @@ document.addEventListener('DOMContentLoaded', function() {
16
  const shadowsValue = document.getElementById('shadows-value');
17
  const highlightsValue = document.getElementById('highlights-value');
18
  const resetBtn = document.getElementById('reset-btn');
 
19
  const downloadBtn = document.getElementById('download-btn');
 
20
 
21
  // RGBカーブ用のキャンバス
22
  const redCurveCanvas = document.getElementById('red-curve');
@@ -30,12 +32,15 @@ document.addEventListener('DOMContentLoaded', function() {
30
 
31
  let camanInstance = null;
32
  let originalImageData = null;
 
33
 
34
  // 画像アップロードの処理
35
  imageUpload.addEventListener('change', function(e) {
36
  const file = e.target.files[0];
37
  if (!file) return;
38
 
 
 
39
  const reader = new FileReader();
40
  reader.onload = function(event) {
41
  const img = new Image();
@@ -68,6 +73,7 @@ document.addEventListener('DOMContentLoaded', function() {
68
 
69
  // RGBカーブを初期化
70
  initCurves();
 
71
  });
72
 
73
  const ctx = imageCanvas.getContext('2d');
@@ -79,50 +85,94 @@ document.addEventListener('DOMContentLoaded', function() {
79
  });
80
 
81
  // スライダーイベントの設定
82
- function setupSlider(slider, valueElement, filterName, callback) {
83
  slider.addEventListener('input', function() {
84
  valueElement.textContent = this.value;
85
- if (camanInstance) {
86
- applyFilters();
87
- if (callback) callback();
88
- }
89
  });
90
  }
91
 
92
- setupSlider(brightnessSlider, brightnessValue, 'brightness');
93
- setupSlider(contrastSlider, contrastValue, 'contrast');
94
- setupSlider(saturationSlider, saturationValue, 'saturation');
95
- setupSlider(shadowsSlider, shadowsValue, 'shadows');
96
- setupSlider(highlightsSlider, highlightsValue, 'highlights');
97
 
98
- // HSLスライダーの設定
99
- hueRedSlider.addEventListener('input', applyFilters);
100
- hueGreenSlider.addEventListener('input', applyFilters);
101
- hueBlueSlider.addEventListener('input', applyFilters);
 
 
 
 
 
 
 
102
 
103
- // フィルターを適用する関数
104
  function applyFilters() {
105
  if (!camanInstance) return;
106
 
107
  camanInstance.revert(false);
108
 
109
- // 基本調整
110
- camanInstance.brightness(parseInt(brightnessSlider.value));
111
- camanInstance.contrast(parseInt(contrastSlider.value));
112
- camanInstance.saturation(parseInt(saturationSlider.value));
 
 
 
 
 
 
 
 
 
 
 
 
 
113
 
114
- // トーン調整
115
- camanInstance.exposure(parseInt(shadowsSlider.value) / 10);
116
- camanInstance.exposure(parseInt(highlightsSlider.value) / 10);
 
 
 
 
 
 
 
 
 
 
 
 
 
117
 
118
  // HSL調整
119
- camanInstance.hue(parseInt(hueRedSlider.value) / 2);
120
- camanInstance.hue(parseInt(hueGreenSlider.value) / 2);
121
- camanInstance.hue(parseInt(hueBlueSlider.value) / 2);
122
 
123
  // RGBカーブを適用
124
  applyRgbCurves();
125
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
126
  camanInstance.render();
127
  }
128
 
@@ -219,7 +269,7 @@ document.addEventListener('DOMContentLoaded', function() {
219
  const point = points[i];
220
  const distance = Math.sqrt(Math.pow(point.x - x, 2) + Math.pow(point.y - y, 2));
221
 
222
- if (distance < 15) { // ヒット半径
223
  isDragging = true;
224
  draggedPoint = point;
225
  return;
@@ -235,7 +285,6 @@ document.addEventListener('DOMContentLoaded', function() {
235
  }
236
 
237
  drawCurve(canvas, points, color);
238
- applyFilters();
239
  });
240
 
241
  canvas.addEventListener('mousemove', function(e) {
@@ -260,7 +309,6 @@ document.addEventListener('DOMContentLoaded', function() {
260
  draggedPoint.y = y;
261
 
262
  drawCurve(canvas, points, color);
263
- applyFilters();
264
  });
265
 
266
  canvas.addEventListener('mouseup', function() {
@@ -275,20 +323,19 @@ document.addEventListener('DOMContentLoaded', function() {
275
 
276
  // ポイントを削除するダブルクリック
277
  canvas.addEventListener('dblclick', function(e) {
278
- if (points.length <= 2) return; // 最低2点は必要
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
  return;
293
  }
294
  }
@@ -341,6 +388,8 @@ document.addEventListener('DOMContentLoaded', function() {
341
  resetBtn.addEventListener('click', function() {
342
  if (!camanInstance) return;
343
 
 
 
344
  // スライダーをリセット
345
  brightnessSlider.value = 0;
346
  contrastSlider.value = 0;
@@ -376,9 +425,13 @@ document.addEventListener('DOMContentLoaded', function() {
376
  this.revert(false);
377
  this.render();
378
  camanInstance = this;
 
379
  });
380
  };
381
  img.src = originalImageData;
 
 
 
382
  });
383
 
384
  // ダウンロードボタン
@@ -390,4 +443,62 @@ document.addEventListener('DOMContentLoaded', function() {
390
  link.href = imageCanvas.toDataURL('image/png');
391
  link.click();
392
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
393
  });
 
16
  const shadowsValue = document.getElementById('shadows-value');
17
  const highlightsValue = document.getElementById('highlights-value');
18
  const resetBtn = document.getElementById('reset-btn');
19
+ const applyBtn = document.getElementById('apply-btn');
20
  const downloadBtn = document.getElementById('download-btn');
21
+ const loadingOverlay = document.getElementById('loading-overlay');
22
 
23
  // RGBカーブ用のキャンバス
24
  const redCurveCanvas = document.getElementById('red-curve');
 
32
 
33
  let camanInstance = null;
34
  let originalImageData = null;
35
+ let currentFilters = {};
36
 
37
  // 画像アップロードの処理
38
  imageUpload.addEventListener('change', function(e) {
39
  const file = e.target.files[0];
40
  if (!file) return;
41
 
42
+ showLoading();
43
+
44
  const reader = new FileReader();
45
  reader.onload = function(event) {
46
  const img = new Image();
 
73
 
74
  // RGBカーブを初期化
75
  initCurves();
76
+ hideLoading();
77
  });
78
 
79
  const ctx = imageCanvas.getContext('2d');
 
85
  });
86
 
87
  // スライダーイベントの設定
88
+ function setupSlider(slider, valueElement) {
89
  slider.addEventListener('input', function() {
90
  valueElement.textContent = this.value;
 
 
 
 
91
  });
92
  }
93
 
94
+ setupSlider(brightnessSlider, brightnessValue);
95
+ setupSlider(contrastSlider, contrastValue);
96
+ setupSlider(saturationSlider, saturationValue);
97
+ setupSlider(shadowsSlider, shadowsValue);
98
+ setupSlider(highlightsSlider, highlightsValue);
99
 
100
+ // 適用ボタンのイベントリスナー
101
+ applyBtn.addEventListener('click', function() {
102
+ if (!camanInstance) return;
103
+ showLoading();
104
+
105
+ // 非同期で処理を行う
106
+ setTimeout(function() {
107
+ applyFilters();
108
+ hideLoading();
109
+ }, 100);
110
+ });
111
 
112
+ // フィルターを適用する関数(強化版)
113
  function applyFilters() {
114
  if (!camanInstance) return;
115
 
116
  camanInstance.revert(false);
117
 
118
+ // 現在のフィルター設定を保存
119
+ currentFilters = {
120
+ brightness: parseInt(brightnessSlider.value),
121
+ contrast: parseInt(contrastSlider.value),
122
+ saturation: parseInt(saturationSlider.value),
123
+ shadows: parseInt(shadowsSlider.value),
124
+ highlights: parseInt(highlightsSlider.value),
125
+ hueRed: parseInt(hueRedSlider.value),
126
+ hueGreen: parseInt(hueGreenSlider.value),
127
+ hueBlue: parseInt(hueBlueSlider.value)
128
+ };
129
+
130
+ // 明るさ(範囲拡大: -100 to 100 → -150 to 150)
131
+ camanInstance.brightness(currentFilters.brightness * 1.5);
132
+
133
+ // コントラスト(効果を強化)
134
+ camanInstance.contrast(currentFilters.contrast * 1.5);
135
 
136
+ // 彩度
137
+ camanInstance.saturation(currentFilters.saturation);
138
+
139
+ // シャドウ(効果を強化、範囲拡大)
140
+ if (currentFilters.shadows > 0) {
141
+ camanInstance.shadows(currentFilters.shadows * 2);
142
+ } else {
143
+ camanInstance.exposure(currentFilters.shadows / 5);
144
+ }
145
+
146
+ // ハイライト(効果を強化、範囲拡大)
147
+ if (currentFilters.highlights > 0) {
148
+ camanInstance.highlights(currentFilters.highlights * 2);
149
+ } else {
150
+ camanInstance.exposure(currentFilters.highlights / 5);
151
+ }
152
 
153
  // HSL調整
154
+ camanInstance.hue(currentFilters.hueRed / 2);
155
+ camanInstance.hue(currentFilters.hueGreen / 2);
156
+ camanInstance.hue(currentFilters.hueBlue / 2);
157
 
158
  // RGBカーブを適用
159
  applyRgbCurves();
160
 
161
+ // 追加フィルター: シャープネス
162
+ if (currentFilters.sharpness) {
163
+ camanInstance.sharpen(currentFilters.sharpness);
164
+ }
165
+
166
+ // 追加フィルター: ノイズ
167
+ if (currentFilters.noise) {
168
+ camanInstance.noise(currentFilters.noise);
169
+ }
170
+
171
+ // 追加フィルター: ビネット
172
+ if (currentFilters.vignette) {
173
+ camanInstance.vignette("10%", currentFilters.vignette * 2);
174
+ }
175
+
176
  camanInstance.render();
177
  }
178
 
 
269
  const point = points[i];
270
  const distance = Math.sqrt(Math.pow(point.x - x, 2) + Math.pow(point.y - y, 2));
271
 
272
+ if (distance < 15) {
273
  isDragging = true;
274
  draggedPoint = point;
275
  return;
 
285
  }
286
 
287
  drawCurve(canvas, points, color);
 
288
  });
289
 
290
  canvas.addEventListener('mousemove', function(e) {
 
309
  draggedPoint.y = y;
310
 
311
  drawCurve(canvas, points, color);
 
312
  });
313
 
314
  canvas.addEventListener('mouseup', function() {
 
323
 
324
  // ポイントを削除するダブルクリック
325
  canvas.addEventListener('dblclick', function(e) {
326
+ if (points.length <= 2) return;
327
 
328
  const rect = canvas.getBoundingClientRect();
329
  const x = (e.clientX - rect.left) / rect.width * 255;
330
  const y = 255 - (e.clientY - rect.top) / rect.height * 255;
331
 
332
+ for (let i = 1; i < points.length - 1; i++) {
333
  const point = points[i];
334
  const distance = Math.sqrt(Math.pow(point.x - x, 2) + Math.pow(point.y - y, 2));
335
 
336
  if (distance < 15) {
337
  points.splice(i, 1);
338
  drawCurve(canvas, points, color);
 
339
  return;
340
  }
341
  }
 
388
  resetBtn.addEventListener('click', function() {
389
  if (!camanInstance) return;
390
 
391
+ showLoading();
392
+
393
  // スライダーをリセット
394
  brightnessSlider.value = 0;
395
  contrastSlider.value = 0;
 
425
  this.revert(false);
426
  this.render();
427
  camanInstance = this;
428
+ hideLoading();
429
  });
430
  };
431
  img.src = originalImageData;
432
+
433
+ // フィルター設定をリセット
434
+ currentFilters = {};
435
  });
436
 
437
  // ダウンロードボタン
 
443
  link.href = imageCanvas.toDataURL('image/png');
444
  link.click();
445
  });
446
+
447
+ // 読み込み表示を制御する関数
448
+ function showLoading() {
449
+ loadingOverlay.style.display = 'flex';
450
+ }
451
+
452
+ function hideLoading() {
453
+ loadingOverlay.style.display = 'none';
454
+ }
455
+
456
+ // 追加機能: キーボードショートカット
457
+ document.addEventListener('keydown', function(e) {
458
+ if (e.ctrlKey && e.key === 'z') {
459
+ resetBtn.click();
460
+ } else if (e.ctrlKey && e.key === 's') {
461
+ downloadBtn.click();
462
+ e.preventDefault();
463
+ } else if (e.key === 'Enter') {
464
+ applyBtn.click();
465
+ }
466
+ });
467
+
468
+ // 追加機能: プリセットフィルター
469
+ function applyPreset(presetName) {
470
+ switch(presetName) {
471
+ case 'vintage':
472
+ brightnessSlider.value = 10;
473
+ contrastSlider.value = 20;
474
+ saturationSlider.value = -30;
475
+ shadowsSlider.value = 15;
476
+ highlightsSlider.value = -10;
477
+ hueRedSlider.value = 10;
478
+ break;
479
+ case 'dramatic':
480
+ brightnessSlider.value = -10;
481
+ contrastSlider.value = 50;
482
+ saturationSlider.value = -20;
483
+ shadowsSlider.value = 30;
484
+ highlightsSlider.value = -20;
485
+ break;
486
+ case 'bright':
487
+ brightnessSlider.value = 30;
488
+ contrastSlider.value = 20;
489
+ saturationSlider.value = 40;
490
+ shadowsSlider.value = 20;
491
+ highlightsSlider.value = 10;
492
+ break;
493
+ }
494
+
495
+ // スライダー値を更新
496
+ brightnessValue.textContent = brightnessSlider.value;
497
+ contrastValue.textContent = contrastSlider.value;
498
+ saturationValue.textContent = saturationSlider.value;
499
+ shadowsValue.textContent = shadowsSlider.value;
500
+ highlightsValue.textContent = highlightsSlider.value;
501
+
502
+ applyBtn.click();
503
+ }
504
  });