From b649717e0d66871ce742005bf450913e62918005 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E5=BF=97=E9=B9=8F?= <2916022834@qq.com> Date: Thu, 25 Sep 2025 13:07:25 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E7=94=BB=E5=B8=83=E6=89=93?= =?UTF-8?q?=E5=BC=80=E5=9B=BE=E7=89=87=E5=AF=BC=E5=87=BA=E5=9B=BE=E7=89=87?= =?UTF-8?q?=E5=88=86=E8=BE=A8=E7=8E=87=E4=B8=8D=E5=80=BC=E4=B8=80=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/component/Canvas/CanvasEditor/index.vue | 23 ++++++++ .../CanvasEditor/managers/CanvasManager.js | 1 + .../CanvasEditor/managers/ExportManager.js | 53 ++++++++++++++----- .../CanvasEditor/utils/selectionToImage.js | 16 +++++- .../tools/deReconstruction/canvas/index.vue | 16 +++--- src/component/modules/generalMiniCanvas.vue | 18 ++++--- 6 files changed, 101 insertions(+), 26 deletions(-) diff --git a/src/component/Canvas/CanvasEditor/index.vue b/src/component/Canvas/CanvasEditor/index.vue index 503e83dd..a90a0ceb 100644 --- a/src/component/Canvas/CanvasEditor/index.vue +++ b/src/component/Canvas/CanvasEditor/index.vue @@ -457,6 +457,14 @@ onMounted(async () => { // 使用window的resize事件代替ResizeObserver // 只有当窗口大小变化时才更新画布尺寸 // window.addEventListener("resize", handleWindowResize); + + if(props.config.initZoom) { + const width = canvasManager.width; + const height = canvasManager.height; + const cwidth = props.config.width; + const cheight = props.config.height; + setZoom(Math.min(width/cwidth,height/cheight)); // 设置画布缩放 + } }); watchEffect(() => { @@ -521,7 +529,20 @@ function handleWindowResize() { function resetZoom() { canvasManager.resetZoom(); } +function setZoom(zoom) { + setTimeout(()=>{ + if (!canvasManager) return; + const newZoom = Math.max(zoom / 1.1, 0.1); // 减少10%,最小0.1倍 + // 使用画布中心作为缩放点 + const centerPoint = { + x: canvasManager.canvas.width / 2, + y: canvasManager.canvas.height / 2, + }; + + canvasManager.animateZoom(centerPoint, newZoom); + }) +} function zoomIn() { if (!canvasManager) return; @@ -889,6 +910,7 @@ defineExpose({ layerId = "", // 导出具体图层ID layerIdArray = [], // 导出多个图层ID数组 expPicType = "png", // 导出图片类型 JPG 或 PNG ,SVG + isEnhanceImg, // 是否是增强图片 } = {}) => { return canvasManager.exportImage({ isContainBg, @@ -897,6 +919,7 @@ defineExpose({ layerId, layerIdArray, expPicType, + isEnhanceImg, }); }, /** diff --git a/src/component/Canvas/CanvasEditor/managers/CanvasManager.js b/src/component/Canvas/CanvasEditor/managers/CanvasManager.js index 6c4083da..0070d03a 100644 --- a/src/component/Canvas/CanvasEditor/managers/CanvasManager.js +++ b/src/component/Canvas/CanvasEditor/managers/CanvasManager.js @@ -811,6 +811,7 @@ export class CanvasManager { * @param {Array} options.layerIdArray 导出多个图层ID数组 * @param {String} options.expPicType 导出图片类型 (png/jpg/svg) * @param {Boolean} options.restoreOpacityInRedGreen 红绿图模式下是否恢复透明度为1 + * @param {Boolean} options.isEnhanceImg 是否是增强图片 * @returns {String} 导出的图片数据URL */ async exportImage(options = {}) { diff --git a/src/component/Canvas/CanvasEditor/managers/ExportManager.js b/src/component/Canvas/CanvasEditor/managers/ExportManager.js index 41d1007d..d9107e26 100644 --- a/src/component/Canvas/CanvasEditor/managers/ExportManager.js +++ b/src/component/Canvas/CanvasEditor/managers/ExportManager.js @@ -18,10 +18,12 @@ export class ExportManager { * @param {Object} options 导出选项 * @param {Boolean} options.isContainBg 是否包含背景图层 * @param {Boolean} options.isContainFixed 是否包含固定图层 + * @param {Boolean} options.isCropByBg 是否使用背景大小裁剪 * @param {String} options.layerId 导出具体图层ID * @param {Array} options.layerIdArray 导出多个图层ID数组 * @param {String} options.expPicType 导出图片类型 (png/jpg/svg) * @param {Boolean} options.restoreOpacityInRedGreen 红绿图模式下是否恢复透明度为1 + * @param {Boolean} options.isEnhanceImg 是否是增强图片 * @returns {String} 导出的图片数据URL */ exportImage(options = {}) { @@ -33,6 +35,7 @@ export class ExportManager { layerIdArray = [], expPicType = "png", restoreOpacityInRedGreen = true, + isEnhanceImg, // 是否是增强图片 } = options; try { // 检查是否为红绿图模式 @@ -44,7 +47,8 @@ export class ExportManager { expPicType, isRedGreenMode, restoreOpacityInRedGreen, - isCropByBg + isCropByBg, + isEnhanceImg, ); } @@ -57,7 +61,8 @@ export class ExportManager { isContainFixed, isRedGreenMode, restoreOpacityInRedGreen, - isCropByBg + isCropByBg, + isEnhanceImg ); } @@ -68,7 +73,8 @@ export class ExportManager { isContainFixed, isRedGreenMode, restoreOpacityInRedGreen, - isCropByBg + isCropByBg, + isEnhanceImg ); } catch (error) { console.error("导出图片失败:", error); @@ -82,6 +88,8 @@ export class ExportManager { * @param {String} expPicType 导出类型 * @param {Boolean} isRedGreenMode 是否为红绿图模式 * @param {Boolean} restoreOpacityInRedGreen 红绿图模式下是否恢复透明度为1 + * @param {Boolean} isCropByBg 是否使用背景大小裁剪 + * @param {Boolean} isEnhanceImg 是否是增强图片 * @returns {String} 图片数据URL * @private */ @@ -89,7 +97,9 @@ export class ExportManager { layerId, expPicType, isRedGreenMode, - restoreOpacityInRedGreen + restoreOpacityInRedGreen, + isCropByBg, + isEnhanceImg, // 是否是增强图片 ) { if (!this.layerManager) { throw new Error("图层管理器未初始化"); @@ -125,7 +135,9 @@ export class ExportManager { return await this._exportWithCanvasSize( objectsToExport, expPicType, - restoreOpacityInRedGreen + restoreOpacityInRedGreen, + isCropByBg, // 是否使用背景大小裁剪 + isEnhanceImg, // 是否是增强图片 ); } @@ -137,6 +149,8 @@ export class ExportManager { * @param {Boolean} isContainFixed 是否包含固定图层 * @param {Boolean} isRedGreenMode 是否为红绿图模式 * @param {Boolean} restoreOpacityInRedGreen 红绿图模式下是否恢复透明度为1 + * @param {Boolean} isCropByBg 是否根据背景裁剪 + * @param {Boolean} isEnhanceImg 是否是增强图片 * @returns {String} 图片数据URL * @private */ @@ -147,7 +161,8 @@ export class ExportManager { isContainFixed, isRedGreenMode, restoreOpacityInRedGreen, - isCropByBg + isCropByBg, // 是否根据背景裁剪 + isEnhanceImg, // 是否是增强图片 ) { if (!this.layerManager) { throw new Error("图层管理器未初始化"); @@ -178,7 +193,9 @@ export class ExportManager { return await this._exportWithCanvasSize( objectsToExport, expPicType, - restoreOpacityInRedGreen + restoreOpacityInRedGreen, + isCropByBg, // 是否根据背景裁剪 + isEnhanceImg, // 是否是增强图片 ); } @@ -189,6 +206,8 @@ export class ExportManager { * @param {Boolean} isContainFixed 是否包含固定图层 * @param {Boolean} isRedGreenMode 是否为红绿图模式 * @param {Boolean} restoreOpacityInRedGreen 红绿图模式下是否恢复透明度为1 + * @param {Boolean} isCropByBg 是否根据背景裁剪 + * @param {Boolean} isEnhanceImg 是否是增强图片 * @returns {String} 图片数据URL * @private */ @@ -198,13 +217,14 @@ export class ExportManager { isContainFixed, isRedGreenMode, restoreOpacityInRedGreen, - isCropByBg + isCropByBg, + isEnhanceImg ) { // 按图层顺序收集对象(从底到顶) const objectsToExport = this._collectObjectsByLayerOrder( null, // 导出所有图层 isContainBg, - isContainFixed + isContainFixed, ); if (objectsToExport.length === 0) { @@ -251,7 +271,9 @@ export class ExportManager { objectsToExport, expPicType, restoreOpacityInRedGreen, - canvasClipPath + canvasClipPath, + isCropByBg, // 是否根据背景裁剪 + isEnhanceImg, // 是否是增强图片 ); } @@ -527,7 +549,7 @@ export class ExportManager { return await this._exportWithCanvasSize( objectsToExport, expPicType, - restoreOpacityInRedGreen + restoreOpacityInRedGreen, ); } @@ -603,6 +625,9 @@ export class ExportManager { * @param {Array} objectsToExport 要导出的对象数组 * @param {String} expPicType 导出类型 * @param {Boolean} restoreOpacityInRedGreen 是否恢复透明度为1 + * @param {Object} maskObject 裁剪对象 + * @param {Boolean} isCropByBg 是否使用背景大小裁剪 + * @param {Boolean} isEnhanceImg 是否是增强图片 * @returns {String} 图片数据URL * @private */ @@ -610,7 +635,9 @@ export class ExportManager { objectsToExport, expPicType, restoreOpacityInRedGreen, - maskObject + maskObject, + isCropByBg, // 是否使用背景大小裁剪 + isEnhanceImg, // 是否是增强图片 ) { // 使用当前画布尺寸 // const canvasWidth = @@ -629,6 +656,8 @@ export class ExportManager { trimWhitespace: true, // 裁剪空白 trimPadding: 0, // 裁剪边距 restoreOpacityInRedGreen, + isCropByBg, // 是否根据背景裁剪 + isEnhanceImg, // 是否是增强图片 }); console.log("导出图片数据URL:", dataURL); diff --git a/src/component/Canvas/CanvasEditor/utils/selectionToImage.js b/src/component/Canvas/CanvasEditor/utils/selectionToImage.js index 848f6916..70c6920f 100644 --- a/src/component/Canvas/CanvasEditor/utils/selectionToImage.js +++ b/src/component/Canvas/CanvasEditor/utils/selectionToImage.js @@ -21,6 +21,7 @@ export const createRasterizedImage = async ({ preserveOriginalQuality = true, // 是否保持原始质量(新增) selectionManager = null, // 选区管理器,用于获取羽化值等设置 restoreOpacityInRedGreen, // 是否在红绿图模式下恢复透明度 + isEnhanceImg, // 是否是增强图片 } = {}) => { try { console.log(`📊 开始栅格化 ${fabricObjects.length} 个对象`); @@ -41,6 +42,7 @@ export const createRasterizedImage = async ({ clippingObject, isReturenDataURL, selectionManager, // 传递选区管理器 + isEnhanceImg, // 是否是增强图片 }); } @@ -81,6 +83,7 @@ const createClippedObjects = async ({ clippingObject, isReturenDataURL, selectionManager = null, // 新增选区管理器参数 + isEnhanceImg, // 是否是增强图片 }) => { try { console.log("🎯 使用新的图像遮罩裁剪方法创建对象"); @@ -110,6 +113,7 @@ const createClippedObjects = async ({ clippingObject, selectionBounds: optimizedBounds, // 使用优化后的边界框 featherAmount, + isEnhanceImg, // 是否是增强图片 }); } @@ -120,6 +124,7 @@ const createClippedObjects = async ({ clippingObject, selectionBounds: optimizedBounds, // 使用优化后的边界框 featherAmount, + isEnhanceImg, // 是否是增强图片 }); // 将DataURL转换为fabric.Image对象 @@ -173,6 +178,7 @@ const createClippedDataURLByCanvas = async ({ clippingObject, selectionBounds, featherAmount = 0, + isEnhanceImg = false, // 是否是增强图片 }) => { try { console.log("🖼️ 使用图像遮罩裁剪方法生成DataURL"); @@ -185,7 +191,9 @@ const createClippedDataURLByCanvas = async ({ // 使用高分辨率以保证质量 const pixelRatio = window.devicePixelRatio || 1; - const qualityMultiplier = Math.max(2, pixelRatio); + const qualityMultiplier = !!isEnhanceImg ? Math.max(2, pixelRatio) : 1; + + console.log("使用高分辨率以保证质量:" + isEnhanceImg, optimizedBounds); const canvasWidth = Math.ceil(optimizedBounds.width * qualityMultiplier); const canvasHeight = Math.ceil(optimizedBounds.height * qualityMultiplier); @@ -455,6 +463,8 @@ const createLegacyRasterization = async ({ quality, format, isReturenDataURL, + isCropByBg, // 是否根据背景裁剪 + isEnhanceImg, // 是否是增强图片 }) => { console.log("⚠️ 使用兼容的离屏渲染方法"); @@ -481,6 +491,8 @@ const createLegacyRasterization = async ({ format, currentZoom, isReturenDataURL, + isCropByBg, // 是否根据背景裁剪 + isEnhanceImg, // 是否是增强图片 }); }; @@ -571,6 +583,8 @@ const createOffscreenRasterization = async ({ format, currentZoom, isReturenDataURL, + isCropByBg, // 是否根据背景裁剪 + isEnhanceImg, // 是否是增强图片 }) => { try { // 创建离屏画布,使用绝对尺寸以保证高质量 diff --git a/src/component/home/tools/deReconstruction/canvas/index.vue b/src/component/home/tools/deReconstruction/canvas/index.vue index 6b8e698d..e22594f0 100644 --- a/src/component/home/tools/deReconstruction/canvas/index.vue +++ b/src/component/home/tools/deReconstruction/canvas/index.vue @@ -113,12 +113,16 @@ export default defineComponent({ return new Promise((res,rev)=>{ let img = new Image() img.onload = ()=>{ - let wH = [1,1] - let domHeight = dataDom.canvasBox.offsetHeight - 200 - let imgHeight = img.height - wH = [1,domHeight/imgHeight] - data.canvasConfig.width = img.width * wH[1] - data.canvasConfig.height = domHeight + // let wH = [1,1] + // let domHeight = dataDom.canvasBox.offsetHeight - 200 + // let imgHeight = img.height + // wH = [1,domHeight/imgHeight] + // data.canvasConfig.width = img.width * wH[1] + // data.canvasConfig.height = domHeight + data.canvasConfig.height = img.height + data.canvasConfig.width = img.width + data.canvasConfig.initZoom = true + data.canvasLoad = true res('') } diff --git a/src/component/modules/generalMiniCanvas.vue b/src/component/modules/generalMiniCanvas.vue index e9463578..eaf2be3d 100644 --- a/src/component/modules/generalMiniCanvas.vue +++ b/src/component/modules/generalMiniCanvas.vue @@ -87,7 +87,7 @@ export default defineComponent({ // dataDom.editCanvas.exportImage({isContainBg:props.source == 'detail',isContainFixed:true}).then((rv)=>{ // emit('submitBase64Data',rv) // }) - dataDom.editCanvas.exportImage({isContainBg:true,isContainFixed:true}).then((rv)=>{ + dataDom.editCanvas.exportImage({isContainBg:true,isContainFixed:true,isCropByBg:true}).then((rv)=>{ emit('submitBase64Data',rv) }) } @@ -135,12 +135,16 @@ export default defineComponent({ if(props.imgUrl){ let img = new Image() img.onload = ()=>{ - let wH = [1,1] - let domHeight = dataDom.canvasBox.offsetHeight - 200 - let imgHeight = img.height - wH = [1,domHeight/imgHeight] - data.canvasConfig.height = domHeight - data.canvasConfig.width = wH[1] * img.width + // let wH = [1,1] + // let domHeight = dataDom.canvasBox.offsetHeight - 200 + // let imgHeight = img.height + // wH = [1,domHeight/imgHeight] + // data.canvasConfig.height = domHeight + // data.canvasConfig.width = wH[1] * img.width + data.canvasConfig.height = img.height + data.canvasConfig.width = img.width + data.canvasConfig.initZoom = true + data.canvasLoad = true // setTimeout(()=>{ // canvasLoadAddImg()