mirror of
https://github.com/jam422470459/EPD-nRF52-hema213.git
synced 2026-03-15 13:13:20 +08:00
add image crop support
This commit is contained in:
@@ -257,6 +257,11 @@ code {
|
|||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.canvas-container.crop #canvas {
|
||||||
|
border: 2px dashed var(--primary-color);
|
||||||
|
cursor: grab;
|
||||||
|
}
|
||||||
|
|
||||||
button {
|
button {
|
||||||
padding: 0.375rem 0.75rem;
|
padding: 0.375rem 0.75rem;
|
||||||
border: 1px solid var(--primary-color);
|
border: 1px solid var(--primary-color);
|
||||||
@@ -367,10 +372,21 @@ canvas.text-placement-mode {
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.text-tools {
|
.text-tools,
|
||||||
|
.crop-tools {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.canvas-container.crop .tool-buttons,
|
||||||
|
.canvas-container.crop .brush-buttons,
|
||||||
|
.canvas-container.crop .text-tools {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.canvas-container.crop .crop-tools {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
.tool-button {
|
.tool-button {
|
||||||
width: 36px;
|
width: 36px;
|
||||||
height: 36px;
|
height: 36px;
|
||||||
|
|||||||
@@ -51,7 +51,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>图片处理</legend>
|
<legend>蓝牙传图</legend>
|
||||||
<div class="flex-container">
|
<div class="flex-container">
|
||||||
<input type="file" id="imageFile" accept=".png,.jpg,.bmp,.webp,.jpeg">
|
<input type="file" id="imageFile" accept=".png,.jpg,.bmp,.webp,.jpeg">
|
||||||
</div>
|
</div>
|
||||||
@@ -120,8 +120,9 @@
|
|||||||
<div class="status-bar"><b>状态:</b><span id="status"></span></div>
|
<div class="status-bar"><b>状态:</b><span id="status"></span></div>
|
||||||
<div class="flex-container">
|
<div class="flex-container">
|
||||||
<div class="flex-group">
|
<div class="flex-group">
|
||||||
<button id="clearcanvasbutton" type="button" class="secondary" onclick="clearCanvas()">清除画布</button>
|
<button type="button" class="secondary debug" onclick="rotateCanvas()">旋转画布</button>
|
||||||
<button id="downloadArray" type="button" class="secondary debug" onclick="downloadDataArray()">下载数组</button>
|
<button type="button" class="secondary" onclick="clearCanvas()">清除画布</button>
|
||||||
|
<button type="button" class="secondary debug" onclick="downloadDataArray()">下载数组</button>
|
||||||
<button id="sendimgbutton" type="button" class="primary" onclick="sendimg()">发送图片</button>
|
<button id="sendimgbutton" type="button" class="primary" onclick="sendimg()">发送图片</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -129,7 +130,7 @@
|
|||||||
<div class="canvas-title"></div>
|
<div class="canvas-title"></div>
|
||||||
<canvas id="canvas" width="400" height="300"></canvas>
|
<canvas id="canvas" width="400" height="300"></canvas>
|
||||||
<div class="flex-container canvas-tools">
|
<div class="flex-container canvas-tools">
|
||||||
<div class="flex-group">
|
<div class="flex-group tool-buttons">
|
||||||
<button id="brush-mode" title="画笔" class="tool-button">✏️</button>
|
<button id="brush-mode" title="画笔" class="tool-button">✏️</button>
|
||||||
<button id="eraser-mode" title="橡皮擦" class="tool-button">🧽</button>
|
<button id="eraser-mode" title="橡皮擦" class="tool-button">🧽</button>
|
||||||
<button id="text-mode" title="添加文字" class="tool-button">T</button>
|
<button id="text-mode" title="添加文字" class="tool-button">T</button>
|
||||||
@@ -191,6 +192,15 @@
|
|||||||
<button id="text-italic" title="斜体">I</button>
|
<button id="text-italic" title="斜体">I</button>
|
||||||
<button id="add-text-btn" class="primary">添加文字</button>
|
<button id="add-text-btn" class="primary">添加文字</button>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="flex-group crop-tools">
|
||||||
|
<button id="crop-zoom-in" title="放大" class="secondary">+</button>
|
||||||
|
<button id="crop-zoom-out" title="缩小" class="secondary">-</button>
|
||||||
|
<button id="crop-move-left" title="左移">⇦</button>
|
||||||
|
<button id="crop-move-up" title="上移">⇧</button>
|
||||||
|
<button id="crop-move-down" title="下移">⇩</button>
|
||||||
|
<button id="crop-move-right" title="右移">⇨</button>
|
||||||
|
<button class="primary" onclick="finishCrop()">完成</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
@@ -205,6 +215,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<script type="text/javascript" src="js/dithering.js?v=20250731"></script>
|
<script type="text/javascript" src="js/dithering.js?v=20250731"></script>
|
||||||
<script type="text/javascript" src="js/paint.js?v=20250731"></script>
|
<script type="text/javascript" src="js/paint.js?v=20250731"></script>
|
||||||
|
<script type="text/javascript" src="js/crop.js?v=20250731"></script>
|
||||||
<script type="text/javascript" src="js/main.js?v=20250731"></script>
|
<script type="text/javascript" src="js/main.js?v=20250731"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
|||||||
211
html/js/crop.js
Normal file
211
html/js/crop.js
Normal file
@@ -0,0 +1,211 @@
|
|||||||
|
let backgroundZoom = 1;
|
||||||
|
let backgroundPanX = 0;
|
||||||
|
let backgroundPanY = 0;
|
||||||
|
let isPanning = false;
|
||||||
|
let lastPanX = 0;
|
||||||
|
let lastPanY = 0;
|
||||||
|
let lastTouchDistance = 0;
|
||||||
|
|
||||||
|
function resetCropStates() {
|
||||||
|
backgroundZoom = 1;
|
||||||
|
backgroundPanX = 0;
|
||||||
|
backgroundPanY = 0;
|
||||||
|
isPanning = false;
|
||||||
|
lastPanX = 0;
|
||||||
|
lastPanY = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeEventListeners() {
|
||||||
|
canvas.removeEventListener('wheel', handleBackgroundZoom);
|
||||||
|
canvas.removeEventListener('mousedown', handleBackgroundPanStart);
|
||||||
|
canvas.removeEventListener('mousemove', handleBackgroundPan);
|
||||||
|
canvas.removeEventListener('mouseup', handleBackgroundPanEnd);
|
||||||
|
canvas.removeEventListener('mouseleave', handleBackgroundPanEnd);
|
||||||
|
|
||||||
|
canvas.removeEventListener('touchstart', handleTouchStart);
|
||||||
|
canvas.removeEventListener('touchmove', handleTouchMove);
|
||||||
|
canvas.removeEventListener('touchend', handleBackgroundPanEnd);
|
||||||
|
canvas.removeEventListener('touchcancel', handleBackgroundPanEnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isCropMode() {
|
||||||
|
return canvas.parentNode.classList.contains('crop');
|
||||||
|
}
|
||||||
|
|
||||||
|
function exitCropMode() {
|
||||||
|
removeEventListeners();
|
||||||
|
canvas.parentNode.classList.remove('crop');
|
||||||
|
setCanvasTitle("");
|
||||||
|
}
|
||||||
|
|
||||||
|
function initializeCrop() {
|
||||||
|
const imageFile = document.getElementById('imageFile');
|
||||||
|
if (imageFile.files.length == 0) {
|
||||||
|
fillCanvas('white');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
resetCropStates();
|
||||||
|
removeEventListeners();
|
||||||
|
|
||||||
|
canvas.style.backgroundImage = `url(${URL.createObjectURL(imageFile.files[0])})`;
|
||||||
|
canvas.style.backgroundSize = '100%';
|
||||||
|
canvas.style.backgroundPosition = '';
|
||||||
|
canvas.style.backgroundRepeat = 'no-repeat';
|
||||||
|
|
||||||
|
// add event listeners for zoom and pan
|
||||||
|
canvas.addEventListener('wheel', handleBackgroundZoom);
|
||||||
|
canvas.addEventListener('mousedown', handleBackgroundPanStart);
|
||||||
|
canvas.addEventListener('mousemove', handleBackgroundPan);
|
||||||
|
canvas.addEventListener('mouseup', handleBackgroundPanEnd);
|
||||||
|
canvas.addEventListener('mouseleave', handleBackgroundPanEnd);
|
||||||
|
|
||||||
|
// Touch events for mobile devices
|
||||||
|
canvas.addEventListener('touchstart', handleTouchStart);
|
||||||
|
canvas.addEventListener('touchmove', handleTouchMove);
|
||||||
|
canvas.addEventListener('touchend', handleBackgroundPanEnd);
|
||||||
|
canvas.addEventListener('touchcancel', handleBackgroundPanEnd);
|
||||||
|
|
||||||
|
// Make the canvas transparent
|
||||||
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||||
|
|
||||||
|
setCanvasTitle("裁剪模式: 可用鼠标或触摸缩放移动图片");
|
||||||
|
canvas.parentNode.classList.add('crop');
|
||||||
|
}
|
||||||
|
|
||||||
|
function finishCrop() {
|
||||||
|
const imageFile = document.getElementById('imageFile');
|
||||||
|
if (imageFile.files.length == 0) return;
|
||||||
|
|
||||||
|
const image = new Image();
|
||||||
|
image.onload = function () {
|
||||||
|
URL.revokeObjectURL(this.src);
|
||||||
|
|
||||||
|
const fieldsetRect = canvas.getBoundingClientRect();
|
||||||
|
const scale = (image.width / fieldsetRect.width) / backgroundZoom;
|
||||||
|
|
||||||
|
const sx = -backgroundPanX * scale;
|
||||||
|
const sy = -backgroundPanY * scale;
|
||||||
|
const sWidth = fieldsetRect.width * scale;
|
||||||
|
const sHeight = fieldsetRect.height * scale;
|
||||||
|
|
||||||
|
fillCanvas('white');
|
||||||
|
ctx.drawImage(image, sx, sy, sWidth, sHeight, 0, 0, canvas.width, canvas.height);
|
||||||
|
|
||||||
|
redrawTextElements();
|
||||||
|
redrawLineSegments();
|
||||||
|
convertDithering();
|
||||||
|
|
||||||
|
exitCropMode();
|
||||||
|
};
|
||||||
|
image.src = URL.createObjectURL(imageFile.files[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleTouchStart(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
if (e.touches.length === 1) {
|
||||||
|
handleBackgroundPanStart(e.touches[0]);
|
||||||
|
} else if (e.touches.length === 2) {
|
||||||
|
isPanning = false; // Stop panning when zooming
|
||||||
|
lastTouchDistance = getTouchDistance(e.touches);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleTouchMove(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
if (isPanning && e.touches.length === 1) {
|
||||||
|
handleBackgroundPan(e.touches[0]);
|
||||||
|
} else if (e.touches.length === 2) {
|
||||||
|
const newDist = getTouchDistance(e.touches);
|
||||||
|
if (lastTouchDistance > 0) {
|
||||||
|
const zoomFactor = newDist / lastTouchDistance;
|
||||||
|
backgroundZoom *= zoomFactor;
|
||||||
|
backgroundZoom = Math.max(0.1, Math.min(5, backgroundZoom)); // Limit zoom range
|
||||||
|
updateBackgroundTransform();
|
||||||
|
}
|
||||||
|
lastTouchDistance = newDist;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleBackgroundZoom(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
const zoomFactor = e.deltaY > 0 ? 0.9 : 1.1;
|
||||||
|
backgroundZoom *= zoomFactor;
|
||||||
|
backgroundZoom = Math.max(0.1, Math.min(5, backgroundZoom)); // Limit zoom range
|
||||||
|
updateBackgroundTransform();
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleBackgroundPanStart(e) {
|
||||||
|
isPanning = true;
|
||||||
|
lastPanX = e.clientX;
|
||||||
|
lastPanY = e.clientY;
|
||||||
|
canvas.style.cursor = 'grabbing';
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleBackgroundPan(e) {
|
||||||
|
if (isPanning) {
|
||||||
|
const deltaX = e.clientX - lastPanX;
|
||||||
|
const deltaY = e.clientY - lastPanY;
|
||||||
|
backgroundPanX += deltaX;
|
||||||
|
backgroundPanY += deltaY;
|
||||||
|
lastPanX = e.clientX;
|
||||||
|
lastPanY = e.clientY;
|
||||||
|
updateBackgroundTransform();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleBackgroundPanEnd() {
|
||||||
|
isPanning = false;
|
||||||
|
lastTouchDistance = 0; // Reset touch distance
|
||||||
|
canvas.style.cursor = 'grab';
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateBackgroundTransform() {
|
||||||
|
canvas.style.backgroundSize = `${100 * backgroundZoom}%`;
|
||||||
|
canvas.style.backgroundPosition = `${backgroundPanX}px ${backgroundPanY}px`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTouchDistance(touches) {
|
||||||
|
const touch1 = touches[0];
|
||||||
|
const touch2 = touches[1];
|
||||||
|
return Math.sqrt(
|
||||||
|
Math.pow(touch2.clientX - touch1.clientX, 2) +
|
||||||
|
Math.pow(touch2.clientY - touch1.clientY, 2)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function initCropTools() {
|
||||||
|
document.getElementById('crop-zoom-in').addEventListener('click', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
handleBackgroundZoom({ preventDefault: () => {}, deltaY: -1 });
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById('crop-zoom-out').addEventListener('click', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
handleBackgroundZoom({ preventDefault: () => {}, deltaY: 1 });
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById('crop-move-left').addEventListener('click', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
backgroundPanX -= 10;
|
||||||
|
updateBackgroundTransform();
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById('crop-move-right').addEventListener('click', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
backgroundPanX += 10;
|
||||||
|
updateBackgroundTransform();
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById('crop-move-up').addEventListener('click', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
backgroundPanY -= 10;
|
||||||
|
updateBackgroundTransform();
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById('crop-move-down').addEventListener('click', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
backgroundPanY += 10;
|
||||||
|
updateBackgroundTransform();
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -159,6 +159,11 @@ async function sendcmd() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function sendimg() {
|
async function sendimg() {
|
||||||
|
if (isCropMode()) {
|
||||||
|
addLog("请先完成图片裁剪!发送已取消。");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const canvasSize = document.getElementById('canvasSize').value;
|
const canvasSize = document.getElementById('canvasSize').value;
|
||||||
const ditherMode = document.getElementById('ditherMode').value;
|
const ditherMode = document.getElementById('ditherMode').value;
|
||||||
const epdDriverSelect = document.getElementById('epddriver');
|
const epdDriverSelect = document.getElementById('epddriver');
|
||||||
@@ -207,6 +212,11 @@ async function sendimg() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function downloadDataArray() {
|
function downloadDataArray() {
|
||||||
|
if (isCropMode()) {
|
||||||
|
addLog("请先完成图片裁剪!下载已取消。");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const mode = document.getElementById('ditherMode').value;
|
const mode = document.getElementById('ditherMode').value;
|
||||||
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
||||||
const processedData = processImageData(imageData, mode);
|
const processedData = processImageData(imageData, mode);
|
||||||
@@ -417,6 +427,35 @@ function clearLog() {
|
|||||||
document.getElementById("log").innerHTML = '';
|
document.getElementById("log").innerHTML = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function fillCanvas(style) {
|
||||||
|
ctx.fillStyle = style;
|
||||||
|
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateImage() {
|
||||||
|
const imageFile = document.getElementById('imageFile');
|
||||||
|
if (imageFile.files.length == 0) {
|
||||||
|
fillCanvas('white');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const image = new Image();
|
||||||
|
image.onload = function () {
|
||||||
|
URL.revokeObjectURL(this.src);
|
||||||
|
if (image.width / image.height == canvas.width / canvas.height) {
|
||||||
|
if (isCropMode()) exitCropMode();
|
||||||
|
ctx.drawImage(image, 0, 0, image.width, image.height, 0, 0, canvas.width, canvas.height);
|
||||||
|
redrawTextElements();
|
||||||
|
redrawLineSegments();
|
||||||
|
convertDithering();
|
||||||
|
} else {
|
||||||
|
addLog("图片宽高比例与画布不匹配,已进入裁剪模式。");
|
||||||
|
initializeCrop();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
image.src = URL.createObjectURL(imageFile.files[0]);
|
||||||
|
}
|
||||||
|
|
||||||
function updateCanvasSize() {
|
function updateCanvasSize() {
|
||||||
const selectedSizeName = document.getElementById('canvasSize').value;
|
const selectedSizeName = document.getElementById('canvasSize').value;
|
||||||
const selectedSize = canvasSizes.find(size => size.name === selectedSizeName);
|
const selectedSize = canvasSizes.find(size => size.name === selectedSizeName);
|
||||||
@@ -424,7 +463,7 @@ function updateCanvasSize() {
|
|||||||
canvas.width = selectedSize.width;
|
canvas.width = selectedSize.width;
|
||||||
canvas.height = selectedSize.height;
|
canvas.height = selectedSize.height;
|
||||||
|
|
||||||
updateImage(false);
|
updateImage();
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateDitcherOptions() {
|
function updateDitcherOptions() {
|
||||||
@@ -439,33 +478,21 @@ function updateDitcherOptions() {
|
|||||||
updateCanvasSize(); // always update image
|
updateCanvasSize(); // always update image
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateImage(clear = false) {
|
function rotateCanvas() {
|
||||||
const imageFile = document.getElementById('imageFile');
|
const currentWidth = canvas.width;
|
||||||
if (imageFile.files.length == 0) return;
|
const currentHeight = canvas.height;
|
||||||
const file = imageFile.files[0];
|
canvas.width = currentHeight;
|
||||||
|
canvas.height = currentWidth;
|
||||||
if (clear) clearCanvas();
|
addLog(`画布已旋转: ${currentWidth}x${currentHeight} -> ${canvas.width}x${canvas.height}`);
|
||||||
|
updateImage();
|
||||||
let image = new Image();
|
|
||||||
image.src = URL.createObjectURL(file);
|
|
||||||
image.onload = function (event) {
|
|
||||||
URL.revokeObjectURL(this.src);
|
|
||||||
ctx.drawImage(image, 0, 0, image.width, image.height, 0, 0, canvas.width, canvas.height);
|
|
||||||
|
|
||||||
// Redraw text and lines
|
|
||||||
redrawTextElements();
|
|
||||||
redrawLineSegments();
|
|
||||||
|
|
||||||
convertDithering()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function clearCanvas() {
|
function clearCanvas() {
|
||||||
if (confirm('清除画布已有内容?')) {
|
if (confirm('清除画布内容?')) {
|
||||||
ctx.fillStyle = 'white';
|
fillCanvas('white');
|
||||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
||||||
textElements = []; // Clear stored text positions
|
textElements = []; // Clear stored text positions
|
||||||
lineSegments = []; // Clear stored line segments
|
lineSegments = []; // Clear stored line segments
|
||||||
|
if (isCropMode()) exitCropMode();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -492,15 +519,15 @@ function convertDithering() {
|
|||||||
|
|
||||||
function initEventHandlers() {
|
function initEventHandlers() {
|
||||||
document.getElementById("epddriver").addEventListener("change", updateDitcherOptions);
|
document.getElementById("epddriver").addEventListener("change", updateDitcherOptions);
|
||||||
document.getElementById("imageFile").addEventListener("change", function () { updateImage(true); });
|
document.getElementById("imageFile").addEventListener("change", updateImage);
|
||||||
document.getElementById("ditherMode").addEventListener("change", function () { updateImage(false); });
|
document.getElementById("ditherMode").addEventListener("change", finishCrop);
|
||||||
document.getElementById("ditherAlg").addEventListener("change", function () { updateImage(false); });
|
document.getElementById("ditherAlg").addEventListener("change", finishCrop);
|
||||||
document.getElementById("ditherStrength").addEventListener("input", function () {
|
document.getElementById("ditherStrength").addEventListener("input", function () {
|
||||||
updateImage(false);
|
finishCrop();
|
||||||
document.getElementById("ditherStrengthValue").innerText = parseFloat(this.value).toFixed(1);
|
document.getElementById("ditherStrengthValue").innerText = parseFloat(this.value).toFixed(1);
|
||||||
});
|
});
|
||||||
document.getElementById("ditherContrast").addEventListener("input", function () {
|
document.getElementById("ditherContrast").addEventListener("input", function () {
|
||||||
updateImage(false);
|
finishCrop();
|
||||||
document.getElementById("ditherContrastValue").innerText = parseFloat(this.value).toFixed(1);
|
document.getElementById("ditherContrastValue").innerText = parseFloat(this.value).toFixed(1);
|
||||||
});
|
});
|
||||||
document.getElementById("canvasSize").addEventListener("change", updateCanvasSize);
|
document.getElementById("canvasSize").addEventListener("change", updateCanvasSize);
|
||||||
@@ -532,6 +559,7 @@ document.body.onload = () => {
|
|||||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||||
|
|
||||||
initPaintTools();
|
initPaintTools();
|
||||||
|
initCropTools();
|
||||||
initEventHandlers();
|
initEventHandlers();
|
||||||
updateButtonStatus();
|
updateButtonStatus();
|
||||||
checkDebugMode();
|
checkDebugMode();
|
||||||
|
|||||||
Reference in New Issue
Block a user