diff --git a/html/index.html b/html/index.html index 60631a8..7610345 100644 --- a/html/index.html +++ b/html/index.html @@ -22,7 +22,7 @@
- @@ -62,12 +62,12 @@
蓝牙传图
- +
- @@ -94,7 +94,7 @@
- @@ -103,7 +103,7 @@
- @@ -217,7 +217,7 @@ - +
diff --git a/html/js/crop.js b/html/js/crop.js index e0d3a1a..dd9a4af 100644 --- a/html/js/crop.js +++ b/html/js/crop.js @@ -1,8 +1,7 @@ class CropManager { - constructor(canvas, ctx, paintManager) { + constructor(canvas, ctx) { this.canvas = canvas; this.ctx = ctx; - this.paintManager = paintManager; this.backgroundZoom = 1; this.backgroundPanX = 0; this.backgroundPanY = 0; @@ -84,7 +83,7 @@ class CropManager { this.canvas.parentNode.classList.add('crop-mode'); } - finishCrop() { + finishCrop(callback) { const imageFile = document.getElementById('imageFile'); if (imageFile.files.length == 0) return; @@ -103,12 +102,8 @@ class CropManager { fillCanvas('white'); this.ctx.drawImage(image, sx, sy, sWidth, sHeight, 0, 0, this.canvas.width, this.canvas.height); - this.paintManager.redrawTextElements(); - this.paintManager.redrawLineSegments(); - convertDithering(); - this.exitCropMode(); - this.paintManager.saveToHistory(); // Save after finishing crop + if (callback) callback(); }; image.src = URL.createObjectURL(imageFile.files[0]); } diff --git a/html/js/main.js b/html/js/main.js index 36a4911..a3118b8 100644 --- a/html/js/main.js +++ b/html/js/main.js @@ -492,10 +492,7 @@ function updateImage() { if (image.width / image.height == canvas.width / canvas.height) { if (cropManager.isCropMode()) cropManager.exitCropMode(); ctx.drawImage(image, 0, 0, image.width, image.height, 0, 0, canvas.width, canvas.height); - paintManager.redrawTextElements(); - paintManager.redrawLineSegments(); convertDithering(); - paintManager.saveToHistory(); // Save after loading image } else { alert(`图片宽高比例与画布不匹配,将进入裁剪模式。\n请放大图片后移动图片使其充满画布, 再点击"完成"按钮。`); paintManager.setActiveTool(null, ''); @@ -548,6 +545,9 @@ function clearCanvas() { } function convertDithering() { + paintManager.redrawTextElements(); + paintManager.redrawLineSegments(); + const contrast = parseFloat(document.getElementById('ditherContrast').value); const currentImageData = ctx.getImageData(0, 0, canvas.width, canvas.height); const imageData = new ImageData( @@ -564,22 +564,23 @@ function convertDithering() { const processedData = processImageData(ditherImage(imageData, alg, strength, mode), mode); const finalImageData = decodeProcessedData(processedData, canvas.width, canvas.height, mode); ctx.putImageData(finalImageData, 0, 0); + + paintManager.saveToHistory(); // Save dithered image to history +} + +function applyDither() { + cropManager.finishCrop(() => convertDithering()); } function initEventHandlers() { - document.getElementById("epddriver").addEventListener("change", updateDitcherOptions); - document.getElementById("imageFile").addEventListener("change", updateImage); - document.getElementById("ditherMode").addEventListener("change", () => cropManager.finishCrop()); - document.getElementById("ditherAlg").addEventListener("change", () => cropManager.finishCrop()); - document.getElementById("ditherStrength").addEventListener("input", function () { - cropManager.finishCrop(); - document.getElementById("ditherStrengthValue").innerText = parseFloat(this.value).toFixed(1); + document.getElementById("ditherStrength").addEventListener("input", (e) => { + document.getElementById("ditherStrengthValue").innerText = parseFloat(e.target.value).toFixed(1); + applyDither(); }); - document.getElementById("ditherContrast").addEventListener("input", function () { - cropManager.finishCrop(); - document.getElementById("ditherContrastValue").innerText = parseFloat(this.value).toFixed(1); + document.getElementById("ditherContrast").addEventListener("input", (e) => { + document.getElementById("ditherContrastValue").innerText = parseFloat(e.target.value).toFixed(1); + applyDither(); }); - document.getElementById("canvasSize").addEventListener("change", updateCanvasSize); } function checkDebugMode() { diff --git a/html/js/paint.js b/html/js/paint.js index 1a8f2e4..7c17d72 100644 --- a/html/js/paint.js +++ b/html/js/paint.js @@ -174,9 +174,8 @@ class PaintManager { document.addEventListener('keydown', this.handleKeyboard); // Mouse move for brush cursor - this.canvas.addEventListener('mousemove', this.updateBrushCursor); this.canvas.addEventListener('mouseenter', this.updateBrushCursor); - this.canvas.addEventListener('mouseleave', this.hideBrushCursor); + this.canvas.addEventListener('mousemove', this.updateBrushCursor); // Create brush cursor element this.createBrushCursor(); @@ -218,9 +217,6 @@ class PaintManager { // Cancel any pending text placement this.cancelTextPlacement(); - - // Update brush cursor visibility - this.updateBrushCursorVisibility(); } createBrushCursor() { @@ -259,54 +255,54 @@ class PaintManager { this.brushCursor.style.height = size + 'px'; } - updateBrushCursorVisibility() { - if (!this.brushCursor) return; - - if (this.currentTool === 'brush' || this.currentTool === 'eraser') { - this.brushCursor.style.display = 'block'; - this.canvas.style.cursor = 'none'; - } else { - this.brushCursor.style.display = 'none'; - this.canvas.style.cursor = 'default'; - } - } - updateBrushCursor(e) { if (!this.brushCursor) return; if (this.currentTool === 'brush' || this.currentTool === 'eraser') { - this.brushCursor.style.display = 'block'; - this.canvas.style.cursor = 'none'; + // Check if mouse is within canvas bounds + const rect = this.canvas.getBoundingClientRect(); + const isInCanvas = e.clientX >= rect.left && + e.clientX <= rect.right && + e.clientY >= rect.top && + e.clientY <= rect.bottom; - // Store the pending position - this.pendingCursorX = e.clientX; - this.pendingCursorY = e.clientY; + if (isInCanvas) { + this.brushCursor.style.display = 'block'; + this.canvas.style.cursor = 'none'; - // Schedule update using requestAnimationFrame for smooth movement - if (!this.cursorUpdateScheduled) { - this.cursorUpdateScheduled = true; - requestAnimationFrame(() => { - this.brushCursor.style.transform = `translate(${this.pendingCursorX}px, ${this.pendingCursorY}px) translate(-50%, -50%)`; - this.cursorUpdateScheduled = false; - }); - } + // Store the pending position + this.pendingCursorX = e.clientX; + this.pendingCursorY = e.clientY; - // Update color to match brush or show white for eraser (only needs to happen once or when tool changes) - if (this.currentTool === 'eraser') { - if (this.brushCursor.getAttribute('data-tool') !== 'eraser') { - this.brushCursor.style.border = '2px solid rgba(255, 0, 0, 0.7)'; - this.brushCursor.style.backgroundColor = 'rgba(255, 255, 255, 0.2)'; - this.brushCursor.style.boxShadow = 'none'; - this.brushCursor.setAttribute('data-tool', 'eraser'); + // Schedule update using requestAnimationFrame for smooth movement + if (!this.cursorUpdateScheduled) { + this.cursorUpdateScheduled = true; + requestAnimationFrame(() => { + this.brushCursor.style.transform = `translate(${this.pendingCursorX}px, ${this.pendingCursorY}px) translate(-50%, -50%)`; + this.cursorUpdateScheduled = false; + }); + } + + // Update color to match brush or show white for eraser (only needs to happen once or when tool changes) + if (this.currentTool === 'eraser') { + if (this.brushCursor.getAttribute('data-tool') !== 'eraser') { + this.brushCursor.style.border = '2px solid rgba(255, 0, 0, 0.7)'; + this.brushCursor.style.backgroundColor = 'rgba(255, 255, 255, 0.2)'; + this.brushCursor.style.boxShadow = 'none'; + this.brushCursor.setAttribute('data-tool', 'eraser'); + } + } else { + if (this.brushCursor.getAttribute('data-tool') !== 'brush') { + // Use a contrasting border - white with black outline for visibility + this.brushCursor.style.border = '1px solid white'; + this.brushCursor.style.boxShadow = '0 0 0 1px black, inset 0 0 0 1px black'; + this.brushCursor.style.backgroundColor = 'transparent'; + this.brushCursor.setAttribute('data-tool', 'brush'); + } } } else { - if (this.brushCursor.getAttribute('data-tool') !== 'brush') { - // Use a contrasting border - white with black outline for visibility - this.brushCursor.style.border = '1px solid white'; - this.brushCursor.style.boxShadow = '0 0 0 1px black, inset 0 0 0 1px black'; - this.brushCursor.style.backgroundColor = 'transparent'; - this.brushCursor.setAttribute('data-tool', 'brush'); - } + // Hide cursor when outside canvas + this.brushCursor.style.display = 'none'; } } } @@ -353,6 +349,8 @@ class PaintManager { this.isDraggingText = false; this.lastX = 0; this.lastY = 0; + + this.hideBrushCursor(); } paint(e) {