From 1b1152339789014123fdc218b8046ec8f8fc1f59 Mon Sep 17 00:00:00 2001 From: Zhukj <3262118957> Date: Mon, 20 Apr 2026 16:37:06 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BC=98=E5=8C=96=E9=82=80=E8=AF=B7?= =?UTF-8?q?=E5=87=BD=E7=94=BB=E5=B8=83=E5=AF=BC=E5=87=BA=E5=88=86=E8=BE=A8?= =?UTF-8?q?=E7=8E=87=EF=BC=8C=E6=8F=90=E5=8D=87=E5=9B=BE=E7=89=87=E4=B8=8E?= =?UTF-8?q?=E6=96=87=E5=AD=97=E6=B8=85=E6=99=B0=E5=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/script.js | 138 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 133 insertions(+), 5 deletions(-) diff --git a/js/script.js b/js/script.js index 78eaff3..2f284e6 100644 --- a/js/script.js +++ b/js/script.js @@ -1958,24 +1958,40 @@ const ctx = canvas.getContext('2d'); const container = imageContainer; - const width = container.clientWidth; - const height = container.clientHeight; + // 高清渲染倍数 + const scaleFactor = 2; + + // 显示尺寸 + const displayWidth = container.clientWidth; + const displayHeight = container.clientHeight; + + // 高清画布尺寸(2倍) + const width = displayWidth * scaleFactor; + const height = displayHeight * scaleFactor; canvas.width = width; canvas.height = height; + // 启用高清渲染 + ctx.imageSmoothingEnabled = true; + ctx.imageSmoothingQuality = 'high'; + ctx.fillStyle = '#fff'; ctx.fillRect(0, 0, width, height); + // 计算缩放比例 + const scaleX = width / displayWidth; + const scaleY = height / displayHeight; + if (currentImage) { - drawBgImageOnCanvas(ctx, currentImage, width, height); + drawBgImageOnCanvasHD(ctx, currentImage, width, height, scaleX, scaleY); } - await drawOverlayImages(ctx); + await drawOverlayImagesHD(ctx, scaleX, scaleY); const textInputs = container.querySelectorAll('.preview-input-layer .text-input'); textInputs.forEach(textInput => { - drawTextOnCanvas(ctx, textInput); + drawTextOnCanvasHD(ctx, textInput, scaleX, scaleY); }); return canvas; @@ -2013,6 +2029,39 @@ ctx.globalAlpha = 1; } + // 绘制背景图(高清版本) + function drawBgImageOnCanvasHD(ctx, img, canvasWidth, canvasHeight, scaleX, scaleY) { + // 使用原始图片尺寸进行高清渲染 + const containerWidth = canvasWidth; + const containerHeight = canvasHeight; + const imgRatio = img.naturalWidth / img.naturalHeight; + const containerRatio = containerWidth / containerHeight; + + let imgWidth, imgHeight; + + if (imgRatio > containerRatio) { + imgHeight = containerHeight; + imgWidth = imgHeight * imgRatio; + } else { + imgWidth = containerWidth; + imgHeight = imgWidth / imgRatio; + } + + // 应用缩放 + const scaledWidth = imgWidth * bgImageScale; + const scaledHeight = imgHeight * bgImageScale; + + // 计算位置(考虑高清缩放) + const baseLeft = (containerWidth - scaledWidth) / 2; + const drawX = baseLeft + (imageOffsetX * scaleX); + const drawY = (containerHeight - scaledHeight) / 2; + + ctx.globalAlpha = bgImageOpacity; + // 使用原始图片绘制,获得最佳清晰度 + ctx.drawImage(img, drawX, drawY, scaledWidth, scaledHeight); + ctx.globalAlpha = 1; + } + // 绘制层叠图 function drawOverlayImages(ctx) { return new Promise((resolve) => { @@ -2059,6 +2108,56 @@ }); } + // 绘制层叠图(高清版本) + function drawOverlayImagesHD(ctx, scaleX, scaleY) { + return new Promise((resolve) => { + const overlayImages = overlayLayer.querySelectorAll('.overlay-image'); + if (overlayImages.length === 0) { + resolve(); + return; + } + + let loadedCount = 0; + const totalImages = overlayImages.length; + + function checkComplete() { + loadedCount++; + if (loadedCount >= totalImages) { + resolve(); + } + } + + overlayImages.forEach(overlayEl => { + const imgEl = overlayEl.querySelector('img'); + if (!imgEl) { + checkComplete(); + return; + } + + // 使用 offsetLeft/offsetTop 获取相对于 overlayLayer 的位置,并应用高清缩放 + const left = overlayEl.offsetLeft * scaleX; + const top = overlayEl.offsetTop * scaleY; + const width = overlayEl.offsetWidth * scaleX; + const height = overlayEl.offsetHeight * scaleY; + + ctx.globalAlpha = overlayEl.style.opacity || 1; + + const img = new Image(); + img.crossOrigin = 'anonymous'; + img.onload = () => { + ctx.drawImage(img, left, top, width, height); + ctx.globalAlpha = 1; + checkComplete(); + }; + img.onerror = () => { + ctx.globalAlpha = 1; + checkComplete(); + }; + img.src = imgEl.src; + }); + }); + } + // 在画布上绘制文字 function drawTextOnCanvas(ctx, inputElement) { const deleteBtn = inputElement.querySelector('.text-delete-btn'); @@ -2088,6 +2187,35 @@ ctx.fillText(text, inputLeft, inputTop + textOffsetY); } + // 在画布上绘制文字(高清版本) + function drawTextOnCanvasHD(ctx, inputElement, scaleX, scaleY) { + const deleteBtn = inputElement.querySelector('.text-delete-btn'); + let text = inputElement.textContent; + if (deleteBtn) { + text = text.replace(deleteBtn.textContent, ''); + } + if (!text.trim()) return; + + // 使用 offsetLeft/offsetTop 获取相对于 preview-input-layer 的位置,并应用高清缩放 + const inputLeft = inputElement.offsetLeft * scaleX; + const inputTop = inputElement.offsetTop * scaleY; + + const style = window.getComputedStyle(inputElement); + const fontSize = parseInt(style.fontSize) * scaleX; // 字体大小也按比例缩放 + const lineHeight = parseFloat(style.lineHeight); + + // 使用高清字体渲染 + ctx.font = `${style.fontWeight} ${fontSize}px ${style.fontFamily}`; + ctx.fillStyle = style.color; + ctx.textBaseline = 'alphabetic'; + + // 计算文本垂直偏移量,使其与 DOM 渲染一致 + const actualLineHeight = (lineHeight || fontSize * 1.4) * scaleY; + const textOffsetY = (actualLineHeight - fontSize) / 2 + fontSize * 0.85; + + ctx.fillText(text, inputLeft, inputTop + textOffsetY); + } + // 保存图片 async function saveImage() { if (!currentImage) {