diff --git a/html/css/main.css b/html/css/main.css index cfcd7b6..6369d06 100644 --- a/html/css/main.css +++ b/html/css/main.css @@ -202,6 +202,10 @@ code { align-items: center; } +.flex-group.right { + margin-left: auto; +} + #status { margin: 10px 0; } @@ -436,6 +440,10 @@ body.debug-mode select:disabled { min-width: 80px; } + .flex-group.right { + margin-left: 0; + } + .canvas-tools.flex-container { flex-direction: row; flex-wrap: wrap; diff --git a/html/index.html b/html/index.html index b63ab3f..2bc1aa5 100644 --- a/html/index.html +++ b/html/index.html @@ -3,13 +3,13 @@ - 电子墨水屏蓝牙控制器 - + 墨水屏日历 +
-

电子墨水屏蓝牙控制器

+

墨水屏日历

蓝牙连接
@@ -18,9 +18,9 @@
-
+
- @@ -33,28 +33,32 @@
-
+
+
+
+
+ 设备控制 +
+
-
+
-
-
-
- +
+
- 蓝牙传图 + 图片处理
- +
- - @@ -76,8 +80,8 @@
- - @@ -85,8 +89,8 @@
- - @@ -95,19 +99,21 @@
- - + + +
- - + + +
- + - +
@@ -129,7 +135,7 @@
- + - +
- + - +
@@ -197,9 +203,9 @@
- - - + + + \ No newline at end of file diff --git a/html/js/dithering.js b/html/js/dithering.js index e19f576..3fcc307 100644 --- a/html/js/dithering.js +++ b/html/js/dithering.js @@ -74,8 +74,7 @@ function labDistance(lab1, lab2) { return Math.sqrt(0.2 * dl * dl + 3 * da * da + 3 * db * db); } -function findClosestColor(r, g, b) { - const mode = document.getElementById('ditherMode').value; +function findClosestColor(r, g, b, mode) { let palette; if (mode === 'fourColor') { @@ -118,7 +117,7 @@ function findClosestColor(r, g, b) { return closestColor; } -function floydSteinbergDither(imageData, strength) { +function floydSteinbergDither(imageData, strength, mode) { const width = imageData.width; const height = imageData.height; const data = imageData.data; @@ -131,7 +130,7 @@ function floydSteinbergDither(imageData, strength) { const g = tempData[idx + 1]; const b = tempData[idx + 2]; - const closest = findClosestColor(r, g, b); + const closest = findClosestColor(r, g, b, mode); const errR = (r - closest.r) * strength; const errG = (g - closest.g) * strength; @@ -171,7 +170,7 @@ function floydSteinbergDither(imageData, strength) { const g = tempData[idx + 1]; const b = tempData[idx + 2]; - const closest = findClosestColor(r, g, b); + const closest = findClosestColor(r, g, b, mode); data[idx] = closest.r; data[idx + 1] = closest.g; data[idx + 2] = closest.b; @@ -181,7 +180,7 @@ function floydSteinbergDither(imageData, strength) { return imageData; } -function atkinsonDither(imageData, strength) { +function atkinsonDither(imageData, strength, mode) { const width = imageData.width; const height = imageData.height; const data = imageData.data; @@ -194,7 +193,7 @@ function atkinsonDither(imageData, strength) { const g = tempData[idx + 1]; const b = tempData[idx + 2]; - const closest = findClosestColor(r, g, b); + const closest = findClosestColor(r, g, b, mode); data[idx] = closest.r; data[idx + 1] = closest.g; @@ -248,7 +247,7 @@ function atkinsonDither(imageData, strength) { return imageData; } -function stuckiDither(imageData, strength) { +function stuckiDither(imageData, strength, mode) { // 执行Stucki错误扩散算法以处理图像 const width = imageData.width; const height = imageData.height; @@ -262,7 +261,7 @@ function stuckiDither(imageData, strength) { const g = tempData[idx + 1]; const b = tempData[idx + 2]; - const closest = findClosestColor(r, g, b); + const closest = findClosestColor(r, g, b, mode); const errR = (r - closest.r) * strength; const errG = (g - closest.g) * strength; @@ -352,7 +351,7 @@ function stuckiDither(imageData, strength) { const g = tempData[idx + 1]; const b = tempData[idx + 2]; - const closest = findClosestColor(r, g, b); + const closest = findClosestColor(r, g, b, mode); data[idx] = closest.r; data[idx + 1] = closest.g; data[idx + 2] = closest.b; @@ -362,7 +361,7 @@ function stuckiDither(imageData, strength) { return imageData; } -function jarvisDither(imageData, strength) { +function jarvisDither(imageData, strength, mode) { const width = imageData.width; const height = imageData.height; const data = imageData.data; @@ -375,7 +374,7 @@ function jarvisDither(imageData, strength) { const g = tempData[idx + 1]; const b = tempData[idx + 2]; - const closest = findClosestColor(r, g, b); + const closest = findClosestColor(r, g, b, mode); data[idx] = closest.r; data[idx + 1] = closest.g; @@ -465,7 +464,7 @@ function jarvisDither(imageData, strength) { return imageData; } -function bayerDither(imageData, strength) { +function bayerDither(imageData, strength, mode) { const width = imageData.width; const height = imageData.height; const data = imageData.data; @@ -508,7 +507,7 @@ function bayerDither(imageData, strength) { const clampedB = Math.min(255, Math.max(0, adjustedB)); // Find closest color in palette - const closest = findClosestColor(clampedR, clampedG, clampedB); + const closest = findClosestColor(clampedR, clampedG, clampedB, mode); data[idx] = closest.r; data[idx + 1] = closest.g; @@ -519,21 +518,18 @@ function bayerDither(imageData, strength) { return imageData; } -function ditherImage(imageData) { - const ditherType = document.getElementById('ditherType').value; - const ditherStrength = parseFloat(document.getElementById('ditherStrength').value); - - switch (ditherType) { +function ditherImage(imageData, alg, strength, mode) { + switch (alg) { case 'floydSteinberg': - return floydSteinbergDither(imageData, ditherStrength); + return floydSteinbergDither(imageData, strength, mode); case 'atkinson': - return atkinsonDither(imageData, ditherStrength); + return atkinsonDither(imageData, strength, mode); case 'stucki': - return stuckiDither(imageData, ditherStrength); + return stuckiDither(imageData, strength, mode); case 'jarvis': - return jarvisDither(imageData, ditherStrength); + return jarvisDither(imageData, strength, mode); case 'bayer': - return bayerDither(imageData, ditherStrength); + return bayerDither(imageData, strength, mode); default: return imageData; } @@ -620,11 +616,10 @@ function decodeProcessedData(processedData, width, height, mode) { return imageData; } -function processImageData(imageData) { +function processImageData(imageData, mode) { const width = imageData.width; const height = imageData.height; const data = imageData.data; - const mode = document.getElementById('ditherMode').value; let processedData; @@ -637,7 +632,7 @@ function processImageData(imageData) { const g = data[index + 1]; const b = data[index + 2]; - const closest = findClosestColor(r, g, b); + const closest = findClosestColor(r, g, b, mode); const newIndex = (x * height) + (height - 1 - y); processedData[newIndex] = closest.value; } @@ -650,7 +645,7 @@ function processImageData(imageData) { const r = data[index]; const g = data[index + 1]; const b = data[index + 2]; - const closest = findClosestColor(r, g, b); // 使用 fourColorPalette + const closest = findClosestColor(r, g, b, mode); // 使用 fourColorPalette const colorValue = closest.value; // 0x00 (黑), 0x01 (白), 0x02 (红), 0x03 (黄) const newIndex = (y * width + x) / 4 | 0; const shift = 6 - ((x % 4) * 2); diff --git a/html/js/main.js b/html/js/main.js index 506619a..503a06f 100644 --- a/html/js/main.js +++ b/html/js/main.js @@ -176,7 +176,7 @@ async function sendimg() { status.parentElement.style.display = "block"; const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); - const processedData = processImageData(imageData); + const processedData = processImageData(imageData, ditherMode); updateButtonStatus(true); @@ -207,9 +207,9 @@ async function sendimg() { } function downloadDataArray() { - const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); - const processedData = processImageData(imageData); const mode = document.getElementById('ditherMode').value; + const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); + const processedData = processImageData(imageData, mode); if (mode === 'sixColor' && processedData.length !== canvas.width * canvas.height) { console.log(`错误:预期${canvas.width * canvas.height}字节,但得到${processedData.length}字节`); @@ -440,13 +440,13 @@ function updateDitcherOptions() { } function updateImage(clear = false) { - const image_file = document.getElementById('image_file'); - if (image_file.files.length == 0) return; + const imageFile = document.getElementById('imageFile'); + if (imageFile.files.length == 0) return; + const file = imageFile.files[0]; if (clear) clearCanvas(); - const file = image_file.files[0]; - let image = new Image();; + let image = new Image(); image.src = URL.createObjectURL(file); image.onload = function (event) { URL.revokeObjectURL(this.src); @@ -472,7 +472,7 @@ function clearCanvas() { } function convertDithering() { - const contrast = parseFloat(document.getElementById('contrast').value); + const contrast = parseFloat(document.getElementById('ditherContrast').value); const currentImageData = ctx.getImageData(0, 0, canvas.width, canvas.height); const imageData = new ImageData( new Uint8ClampedArray(currentImageData.data), @@ -482,12 +482,30 @@ function convertDithering() { adjustContrast(imageData, contrast); + const alg = document.getElementById('ditherAlg').value; + const strength = parseFloat(document.getElementById('ditherStrength').value); const mode = document.getElementById('ditherMode').value; - const processedData = processImageData(ditherImage(imageData)); + const processedData = processImageData(ditherImage(imageData, alg, strength, mode), mode); const finalImageData = decodeProcessedData(processedData, canvas.width, canvas.height, mode); ctx.putImageData(finalImageData, 0, 0); } +function initEventHandlers() { + document.getElementById("epddriver").addEventListener("change", updateDitcherOptions); + document.getElementById("imageFile").addEventListener("change", function () { updateImage(true); }); + document.getElementById("ditherMode").addEventListener("change", function () { updateImage(false); }); + document.getElementById("ditherAlg").addEventListener("change", function () { updateImage(false); }); + document.getElementById("ditherStrength").addEventListener("input", function () { + updateImage(false); + document.getElementById("ditherStrengthValue").innerText = parseFloat(this.value).toFixed(1); + }); + document.getElementById("ditherContrast").addEventListener("input", function () { + updateImage(false); + document.getElementById("ditherContrastValue").innerText = parseFloat(this.value).toFixed(1); + }); + document.getElementById("canvasSize").addEventListener("change", updateCanvasSize); +} + function checkDebugMode() { const link = document.getElementById('debug-toggle'); const urlParams = new URLSearchParams(window.location.search); @@ -514,6 +532,7 @@ document.body.onload = () => { ctx.fillRect(0, 0, canvas.width, canvas.height); initPaintTools(); + initEventHandlers(); updateButtonStatus(); checkDebugMode(); } \ No newline at end of file diff --git a/html/js/paint.js b/html/js/paint.js index 2593d97..9f656d0 100644 --- a/html/js/paint.js +++ b/html/js/paint.js @@ -96,8 +96,10 @@ function updateToolUI() { // Show/hide brush tools document.querySelectorAll('.brush-tools').forEach(el => { - el.style.display = ['brush', 'text'].includes(currentTool) ? 'flex' : 'none'; + el.style.display = ['brush', 'eraser', 'text'].includes(currentTool) ? 'flex' : 'none'; }); + document.getElementById('brush-color').disabled = currentTool === 'eraser'; + document.getElementById('brush-size').disabled = currentTool === 'text'; // Show/hide text tools document.querySelectorAll('.text-tools').forEach(el => {