1
0
tangning 2 дней назад
Родитель
Сommit
5030994e1d
1 измененных файлов с 325 добавлено и 170 удалено
  1. 325 170
      src/view/case/photos/canvas-photo-editor.js

+ 325 - 170
src/view/case/photos/canvas-photo-editor.js

@@ -1555,116 +1555,130 @@ resizePageAndReflow(pages, pageIndex, itemValue) {
       const pdf = new jsPDF({ orientation: orient, unit: "mm", format });
       const pdfW = pdf.internal.pageSize.getWidth();
       const pdfH = pdf.internal.pageSize.getHeight();
-      const groups = [];
-      for (let i = 0; i < this.pages.length; i += perSheet) {
-        groups.push(this.pages.slice(i, i + perSheet));
-      }
-
-      groups.forEach((group, sheetIndex) => {
-        if (sheetIndex > 0) pdf.addPage();
-
-        group.forEach((_, idxInSheet) => {
-          const pageIndex = sheetIndex * perSheet + idxInSheet;
-          const page = this.pages[pageIndex];
-
-          // 离屏画布
-          const pageCanvas = document.createElement("canvas");
-          pageCanvas.width = this.pageWidth * DPR;
-          pageCanvas.height = this.pageHeight * DPR;
-          const ctx = pageCanvas.getContext("2d");
-          ctx.scale(DPR, DPR);
-
-          // 背景
-          ctx.fillStyle = "#fff";
-          ctx.fillRect(0, 0, this.pageWidth, this.pageHeight);
-
-          const layout = this.getItemSize(page.layoutMode);
-          const coords = this.getCoordinate(0, layout);
-
-          coords.forEach((coord, q) => {
-            const photoId = page.list[q];
-            let imgItem = this.photos.find(p => p.id === photoId)
-            const photo = {
-              ...imgItem,
-              ...page.item[q],
-            }
-
-            // 相框底板
-            ctx.fillStyle = photoId?'#fff':"#D9D9D9";
-            ctx.fillRect(coord.x, coord.y, coord.width, coord.height);
-            // ctx.strokeStyle = "#eee";
-            // ctx.strokeRect(coord.x, coord.y, coord.width, coord.height);
-
-            if (photo) {
-              const img = this.imgCache.get(photo.id);
-              if (img && img.complete) {
-                // 图片裁切(不超出相框)
-                ctx.save();
-                ctx.beginPath();
-                ctx.rect(coord.x, coord.y, coord.width, coord.height);
-                ctx.clip();
-
-                const s = Math.min(coord.width / img.width, coord.height / img.height);
-                let w = img.width * s;
-                const h = img.height * s;
-                let x = coord.x + (coord.width - w) / 2;
-                const y = coord.y + (coord.height - h) / 2;
-                // if (paperType == 'four') {
-                //   w = w / (724 / 840)
-                //   x = x * (724 / 840)
-                // }
-                ctx.drawImage(img, x, y, w, h);
-
-                ctx.restore();
-              }
-
-              // 文字
-              ctx.fillStyle = "#000";
-              const text = photo.id?photo.name:"说明文字";
-              this.drawCenteredTextWithEllipsis(
-                ctx, text,
-                coord.x + coord.width / 2,
-                coord.y + coord.height + 40,
-                24, 2
-              );
-
-              // 虚线框
-              // ctx.setLineDash([1, 1]);
-              // ctx.strokeRect(coord.x, coord.y + coord.height + this.imgMargin, coord.width, this.titleHieght);
-              // ctx.setLineDash([]);
-            }
-          });
-          // 页码
-          ctx.fillStyle = '#666666'
-          ctx.font = `${16}px sans-serif`
-          ctx.textAlign = 'right'
-          ctx.fillText(
-            `第 ${pageIndex + 1 + this.pageCount} 页`,
-            this.pageWidth - (75),
-            this.pageHeight - (50)
-          )
-          // ==========================================
-          // 🔥 1:1 还原你原 drawGuideLine 标引逻辑
-          // ==========================================
-          this.renderIndexList(ctx, pageIndex, true)
-
-          const imgData = pageCanvas.toDataURL("image/png", 1.0);
+      // const groups = [];
+      // for (let i = 0; i < this.pages.length; i += perSheet) {
+      //   groups.push(this.pages.slice(i, i + perSheet));
+      // }
 
-          // PDF 位置
-          let x, y, w, h;
+      // groups.forEach((group, sheetIndex) => {
+      //   if (sheetIndex > 0) pdf.addPage();
+
+      //   group.forEach((_, idxInSheet) => {
+      //     const pageIndex = sheetIndex * perSheet + idxInSheet;
+      //     const page = this.pages[pageIndex];
+
+      //     // 离屏画布
+      //     const pageCanvas = document.createElement("canvas");
+      //     pageCanvas.width = this.pageWidth * DPR;
+      //     pageCanvas.height = this.pageHeight * DPR;
+      //     const ctx = pageCanvas.getContext("2d");
+      //     ctx.scale(DPR, DPR);
+
+      //     // 背景
+      //     ctx.fillStyle = "#fff";
+      //     ctx.fillRect(0, 0, this.pageWidth, this.pageHeight);
+
+      //     const layout = this.getItemSize(page.layoutMode);
+      //     const coords = this.getCoordinate(0, layout);
+
+      //     coords.forEach((coord, q) => {
+      //       const photoId = page.list[q];
+      //       let imgItem = this.photos.find(p => p.id === photoId)
+      //       const photo = {
+      //         ...imgItem,
+      //         ...page.item[q],
+      //       }
+
+      //       // 相框底板
+      //       ctx.fillStyle = photoId?'#fff':"#D9D9D9";
+      //       ctx.fillRect(coord.x, coord.y, coord.width, coord.height);
+      //       // ctx.strokeStyle = "#eee";
+      //       // ctx.strokeRect(coord.x, coord.y, coord.width, coord.height);
+
+      //       if (photo) {
+      //         const img = this.imgCache.get(photo.id);
+      //         if (img && img.complete) {
+      //           // 图片裁切(不超出相框)
+      //           ctx.save();
+      //           ctx.beginPath();
+      //           ctx.rect(coord.x, coord.y, coord.width, coord.height);
+      //           ctx.clip();
+
+      //           const s = Math.min(coord.width / img.width, coord.height / img.height);
+      //           let w = img.width * s;
+      //           const h = img.height * s;
+      //           let x = coord.x + (coord.width - w) / 2;
+      //           const y = coord.y + (coord.height - h) / 2;
+      //           ctx.drawImage(img, x, y, w, h);
+
+      //           ctx.restore();
+      //         }
+
+      //         // 文字
+      //         ctx.fillStyle = "#000";
+      //         const text = photo.id?photo.name:"说明文字";
+      //         this.drawCenteredTextWithEllipsis(
+      //           ctx, text,
+      //           coord.x + coord.width / 2,
+      //           coord.y + coord.height + 40,
+      //           24, 2
+      //         );
+
+      //         // 虚线框
+      //         // ctx.setLineDash([1, 1]);
+      //         // ctx.strokeRect(coord.x, coord.y + coord.height + this.imgMargin, coord.width, this.titleHieght);
+      //         // ctx.setLineDash([]);
+      //       }
+      //     });
+      //     // 页码
+      //     ctx.fillStyle = '#666666'
+      //     ctx.font = `${16}px sans-serif`
+      //     ctx.textAlign = 'right'
+      //     ctx.fillText(
+      //       `第 ${pageIndex + 1 + this.pageCount} 页`,
+      //       this.pageWidth - (75),
+      //       this.pageHeight - (50)
+      //     )
+      //     // ==========================================
+      //     // 🔥 1:1 还原你原 drawGuideLine 标引逻辑
+      //     // ==========================================
+      //     this.renderIndexList(ctx, pageIndex, true)
+
+      //     const imgData = pageCanvas.toDataURL("image/png", 1.0);
+
+      //     // PDF 位置
+      //     let x, y, w, h;
+      //     if (paperType === "a4") {
+      //       [x, y, w, h] = [0 + 28, 0, pdfW-28, pdfH];
+      //     } else if (paperType === "a3") {
+      //       w = ((pdfW / 2) - 28); h = pdfH; x = (idxInSheet * w)+56; y = 0;
+      //     } else {
+      //       w = pdfW / 4; h = pdfH;
+      //       x = idxInSheet * (pdfW / 4);
+      //       y = 0;
+      //     }
+
+      //     pdf.addImage(imgData, "PNG", x, y, w, h);
+      //   });
+      // });
+      const list = this.renderPage(paperType, 'pdf')
+      list.map((imgData,groupIndex) => {
+        if (groupIndex > 0) pdf.addPage();
+          let x = 0, y = 0, w = pdfW, h;
           if (paperType === "a4") {
-            [x, y, w, h] = [0 + 28, 0, pdfW-28, pdfH];
+            x = 28
+            w = pdfW + 7
           } else if (paperType === "a3") {
-            w = ((pdfW / 2) - 28); h = pdfH; x = (idxInSheet * w)+56; y = 0;
+            x = 56;
+            w = pdfW + 14
           } else {
-            w = pdfW / 4; h = pdfH;
-            x = idxInSheet * (pdfW / 4);
-            y = 0;
+            x = 0;
+            w = pdfW
           }
+        pdf.addImage(imgData, "PNG", x, y, w, pdfH);
+        // zip.file(`第${groupIndex + 1}张.jpg`, base64.split(",")[1], { base64: true });
 
-          pdf.addImage(imgData, "PNG", x, y, w, h);
-        });
-      });
+      })
       let fileName = name || "完整导出_" + Date.now();
       pdf.save(fileName + `.pdf`);
       ElMessage.success("PDF导出成功!");
@@ -1693,20 +1707,183 @@ resizePageAndReflow(pages, pageIndex, itemValue) {
       text: "正在生成图片...",
       background: "rgba(0, 0, 0, 0.7)",
     });
-
-    const DPR = 3;
     const zip = new JSZip();
 
-    // 完全和你 exportPagesToPDF 保持一致的规则
-    const rules = {
-      a4: { perSheet: 1 },
-      a3: { perSheet: 2 },
-      four: { perSheet: 4 },
-    };
-    const perSheet = rules[paperType]?.perSheet || 1;
 
     try {
-      // 分组:几页拼一张图(a4=1,a3=2,four=4)
+      // const DPR = 3;
+
+      // // 完全和你 exportPagesToPDF 保持一致的规则
+      // const rules = {
+      //   a4: { perSheet: 1 },
+      //   a3: { perSheet: 2 },
+      //   four: { perSheet: 4 },
+      // };
+      // const perSheet = rules[paperType]?.perSheet || 1;
+      // const groups = [];
+      // for (let i = 0; i < this.pages.length; i += perSheet) {
+      //   groups.push(this.pages.slice(i, i + perSheet));
+      // }
+
+      // // 遍历每组 → 生成一张图片
+      // for (let groupIndex = 0; groupIndex < groups.length; groupIndex++) {
+      //   const group = groups[groupIndex];
+
+      //   // 创建画布(和PDF导出尺寸逻辑一致)
+      //   const pageCanvas = document.createElement("canvas");
+      //   let pageWidth = this.pageWidth
+      //   // if (paperType === "four") {
+      //   //   pageWidth = pageWidth * (724 / 840)
+      //   // }
+      //   const mmToPx = 96 / 25.4;
+      //   const bindingMargin = (paperType === "a3" ? 56 : paperType === "a4" ? 28 : 0) * DPR * mmToPx; // mm
+      //   const pageWith = pageWidth * DPR * (paperType === "a3" ? 2 : paperType === "a4" ? 1 : 4);
+      //   pageCanvas.width = pageWith + bindingMargin
+      //   pageCanvas.height = this.pageHeight * DPR * 1;
+      //   const ctx = pageCanvas.getContext("2d");
+      //   ctx.scale(DPR, DPR);
+      //   // 白色背景
+      //   ctx.fillStyle = "#fff";
+      //   ctx.fillRect(0, 0, pageCanvas.width + bindingMargin, pageCanvas.height);
+
+      //   // 绘制本组页面
+      //   group.forEach((page, idxInSheet) => {
+      //     const pageIndex = groupIndex * perSheet + idxInSheet;
+      //     let offsetX = 0;
+      //     let offsetY = 0;
+
+      //     if (paperType === "a3") offsetX = idxInSheet * this.pageWidth;
+      //     if (paperType === "four") {
+      //       offsetX = idxInSheet * pageWidth;
+      //       // offsetY = idxInSheet * this.pageHeight;
+      //     }
+
+      //     ctx.save();
+      //     ctx.translate(offsetX, offsetY);
+
+      //     // ==========================================
+      //     // 🔥 直接复用你 PDF 里一模一样的绘制逻辑
+      //     // ==========================================
+      //     const layout = this.getItemSize(page.layoutMode);
+      //     const coords = this.getCoordinate(0, layout);
+
+      //     coords.forEach((coord, i) => {
+      //       const photoId = page.list[i];
+      //       let imgItem = this.photos.find(p => p.id === photoId)
+      //       const photo = {
+      //         ...imgItem,
+      //         ...page.item[i],
+      //       }
+
+      //       ctx.fillStyle = photoId?'#fff':"#D9D9D9";
+      //       ctx.fillRect(coord.x, coord.y, coord.width, coord.height);
+      //       // ctx.strokeStyle = "#eee";
+      //       // ctx.strokeRect(coord.x, coord.y, coord.width, coord.height);
+
+      //       if (photo) {
+      //         const img = this.imgCache.get(photo.id);
+      //         if (img && img.complete) {
+      //           ctx.save();
+      //           ctx.beginPath();
+      //           ctx.rect(coord.x, coord.y, coord.width, coord.height);
+      //           ctx.clip();
+
+      //           const s = Math.min(coord.width / img.width, coord.height / img.height);
+      //           let w = img.width * s;
+      //           const h = img.height * s;
+      //           let x = coord.x + (coord.width - w) / 2;
+      //           const y = coord.y + (coord.height - h) / 2;
+      //           // if (paperType == 'four') {
+      //           //   w = w / (724 / 840)
+      //           //   x = x * (724 / 840)
+      //           // }
+      //           ctx.drawImage(img, x, y, w, h);
+      //           ctx.restore();
+      //         }
+
+      //         // 文字
+      //         ctx.fillStyle = "#000";
+      //         const text = photo.id?photo.name:"说明文字";
+      //         this.drawCenteredTextWithEllipsis(
+      //           ctx, text,
+      //           coord.x + coord.width / 2,
+      //           coord.y + coord.height + 40,
+      //           24, 2
+      //         );
+
+      //         // ctx.setLineDash([1, 1]);
+      //         // ctx.strokeRect(coord.x, coord.y + coord.height + this.imgMargin, coord.width, this.titleHieght);
+      //         // ctx.setLineDash([]);
+      //       }
+      //     });
+      //     // 页码
+      //     ctx.fillStyle = '#666666'
+      //     ctx.font = `${16}px sans-serif`
+      //     ctx.textAlign = 'right'
+      //     ctx.fillText(
+      //       `第 ${pageIndex + 1 + this.pageCount} 页`,
+      //       this.pageWidth - (75),
+      //       this.pageHeight - (50)
+      //     )
+      //     // ==========================================
+      //     // 🔥 1:1 还原你原 drawGuideLine 标引逻辑
+      //     // ==========================================
+      //     this.renderIndexList(ctx, pageIndex, false)
+
+      //     ctx.restore();
+      //   });
+      //   // 转图片并加入 ZIP
+      //   // ========= 加在这里 =========
+
+      //   const newCanvas = document.createElement('canvas');
+      //   newCanvas.width = pageCanvas.width;
+      //   newCanvas.height = pageCanvas.height;
+      //   const ctxs = newCanvas.getContext('2d');
+      //   ctxs.fillStyle = '#fff';
+      //   ctxs.fillRect(0,0, newCanvas.width, newCanvas.height);
+      //   ctxs.drawImage(pageCanvas, bindingMargin, 0);
+
+      //   // 导出用 newCanvas
+      //   const base64 = newCanvas.toDataURL('image/jpeg');
+      //   // const base64 = pageCanvas.toDataURL("image/jpeg");
+      //   zip.file(`第${groupIndex + 1}张.jpg`, base64.split(",")[1], { base64: true });
+      // }
+      const list = this.renderPage(paperType, 'img')
+      list.map((base64,groupIndex) => {
+        zip.file(`第${groupIndex + 1}张.jpg`, base64.split(",")[1], { base64: true });
+
+      })
+      
+      // 下载
+      const filename = name || "照片卷";
+      zip.generateAsync({ type: "blob" }).then(blob => {
+        saveAs(blob, `${filename}.zip`);
+        ElMessage.success("导出成功!");
+      }).catch(() => {
+        ElMessage.error("导出失败");
+      });
+      // const blob = await zip.generateAsync({ type: "blob" });
+      // saveAs(blob, `${filename}.zip`);
+      // ElMessage.success("导出成功!");
+      return true
+    } catch (err) {
+      console.error(err);
+      ElMessage.error("导出失败");
+      return false
+    } finally {
+      loading.close();
+    }
+  }
+  renderPage(paperType, ExportType = 'pdf') {
+      const DPR = 3;
+      const rules = {
+        a4: { perSheet: 1 },
+        a3: { perSheet: 2 },
+        four: { perSheet: 4 },
+      };
+      const perSheet = rules[paperType]?.perSheet || 1;
+      let base64List = []
+
       const groups = [];
       for (let i = 0; i < this.pages.length; i += perSheet) {
         groups.push(this.pages.slice(i, i + perSheet));
@@ -1731,7 +1908,7 @@ resizePageAndReflow(pages, pageIndex, itemValue) {
         ctx.scale(DPR, DPR);
         // 白色背景
         ctx.fillStyle = "#fff";
-        ctx.fillRect(0, 0, pageCanvas.width + bindingMargin, pageCanvas.height);
+        ctx.fillRect(0, 0, pageCanvas.width, pageCanvas.height);
 
         // 绘制本组页面
         group.forEach((page, idxInSheet) => {
@@ -1739,7 +1916,7 @@ resizePageAndReflow(pages, pageIndex, itemValue) {
           let offsetX = 0;
           let offsetY = 0;
 
-          if (paperType === "a3") offsetX = idxInSheet * this.pageWidth;
+          if (paperType === "a3") offsetX = idxInSheet * pageWidth;
           if (paperType === "four") {
             offsetX = idxInSheet * pageWidth;
             // offsetY = idxInSheet * this.pageHeight;
@@ -1815,59 +1992,47 @@ resizePageAndReflow(pages, pageIndex, itemValue) {
           // ==========================================
           // 🔥 1:1 还原你原 drawGuideLine 标引逻辑
           // ==========================================
-          this.renderIndexList(ctx, pageIndex, false)
 
           ctx.restore();
         });
+        this.renderIndexList(ctx, groupIndex, pageWidth, perSheet)
+        ctx.restore();
         // 转图片并加入 ZIP
         // ========= 加在这里 =========
-
-        const newCanvas = document.createElement('canvas');
-        newCanvas.width = pageCanvas.width;
-        newCanvas.height = pageCanvas.height;
-        const ctxs = newCanvas.getContext('2d');
-        ctxs.fillStyle = '#fff';
-        ctxs.fillRect(0,0, newCanvas.width, newCanvas.height);
-        ctxs.drawImage(pageCanvas, bindingMargin, 0);
-
-        // 导出用 newCanvas
-        const base64 = newCanvas.toDataURL('image/jpeg');
-        // const base64 = pageCanvas.toDataURL("image/jpeg");
-        zip.file(`第${groupIndex + 1}张.jpg`, base64.split(",")[1], { base64: true });
+        if(ExportType == 'img'){
+          const newCanvas = document.createElement('canvas');
+          newCanvas.width = pageCanvas.width;
+          newCanvas.height = pageCanvas.height;
+          const ctxs = newCanvas.getContext('2d');
+          ctxs.fillStyle = '#fff';
+          ctxs.fillRect(0,0, newCanvas.width, newCanvas.height);
+          ctxs.drawImage(pageCanvas, bindingMargin, 0);
+
+          // 导出用 newCanvas
+          const base64 = newCanvas.toDataURL('image/jpeg');
+          base64List.push(base64)
+        }else{
+          const base64 = pageCanvas.toDataURL("image/png", 1.0);
+          base64List.push(base64) 
+        }
       }
-
-      // 下载
-      const filename = name || "照片卷";
-      zip.generateAsync({ type: "blob" }).then(blob => {
-        saveAs(blob, `${filename}.zip`);
-        ElMessage.success("导出成功!");
-      }).catch(() => {
-        ElMessage.error("导出失败");
-      });
-      // const blob = await zip.generateAsync({ type: "blob" });
-      // saveAs(blob, `${filename}.zip`);
-      // ElMessage.success("导出成功!");
-      return true
-    } catch (err) {
-      console.error(err);
-      ElMessage.error("导出失败");
-      return false
-    } finally {
-      loading.close();
-    }
+      console.log('base64List', base64List)
+      return base64List;
   }
-  renderIndexList(ctx, pageIndex, isPdf = false) {
+  renderIndexList(ctx, pageIndex, pageWith, perSheet = 1) {
     this.indexingLineList.forEach(line => {
       const { points, coordinate, indexingList } = line;
       const startInfo = indexingList[0];
       const endInfo = indexingList[1];
 
       // 当前正在导出的是哪一页
-      const currentIsStart = startInfo.pageIndex === pageIndex;
-      const currentIsEnd = endInfo.pageIndex === pageIndex;
-      if (isPdf && !currentIsStart && !currentIsEnd) return;
-      if (!isPdf && !currentIsEnd) return;
-
+      // const currentIsStart = startInfo.pageIndex === pageIndex;
+      // const currentIsEnd = endInfo.pageIndex === pageIndex || startInfo.pageIndex === pageIndex;
+      // if (isPdf && !currentIsStart && !currentIsEnd) return;
+      // if (!isPdf && !currentIsEnd) return;
+      if((pageIndex*perSheet > endInfo.pageIndex || (pageIndex+1)*perSheet < endInfo.pageIndex) && (pageIndex*perSheet > startInfo.pageIndex || (pageIndex+1)*perSheet < startInfo.pageIndex)){
+        return;
+      }
       ctx.save();
       ctx.strokeStyle = '#ff0000';
       ctx.fillStyle = '#ff0000';
@@ -1876,8 +2041,8 @@ resizePageAndReflow(pages, pageIndex, itemValue) {
       ctx.lineJoin = 'round';
 
       // 页面全局偏移(核心修正)
-      const pageOffsetX = pageIndex * (this.pageWidth + this.pageMargin);
-
+      const pageOffsetX = pageIndex * ((pageWith + this.pageMargin) * perSheet);
+      // const pageOffsetX = pageIndex * (this.pageWidth + this.pageMargin) * perSheet;
       // 绘制连线
       ctx.beginPath();
       points.forEach((p, i) => {
@@ -1886,18 +2051,8 @@ resizePageAndReflow(pages, pageIndex, itemValue) {
         i === 0 ? ctx.moveTo(x, y) : ctx.lineTo(x, y);
       });
       ctx.stroke();
-
-      // 起点圆点(只在起点页画)
-      // if (currentIsStart) {
-      //   const first = points[0];
-      //   const fx = first.x - pageOffsetX;
-      //   ctx.beginPath();
-      //   ctx.arc(fx, first.y, 4, 0, Math.PI * 2);
-      //   ctx.fill();
-      // }
-
       // T型端线(只在终点页画)
-      if (currentIsEnd) {
+      // if (currentIsEnd) {
         const last = points[points.length - 1];
         ctx.beginPath();
         if (startInfo.count == endInfo.count && startInfo.count == 2 && startInfo.itemIndex == endInfo.itemIndex && points.length == 4) {
@@ -1911,7 +2066,7 @@ resizePageAndReflow(pages, pageIndex, itemValue) {
           ctx.lineTo(last.x - pageOffsetX, coordinate.y + coordinate.height);
         }
         ctx.stroke();
-      }
+      // }
 
       ctx.restore();
     });