审查视图

app/utils/fileExport/toPdf.ts 5.1 KB
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
import html2canvas from "html2canvas";
import jsPDF from "jspdf";
import { pdfToText } from "pdf-ts";

export async function htmlToPdf2(htmlCode: string) {
  const container = document.createElement("div");
  container.style.cssText = `
    position: fixed;
    left: -9999px;
    top: -9999px;
    width: 210mm; // 固定 A4 宽度
    background: white;
  `;
  container.innerHTML = htmlCode;
  document.body.appendChild(container);

  try {
    // 关键修改 1: 确保所有图片加载完成
    await waitForImages(container);

    // 关键修改 2: 强制触发布局计算
    void container.offsetHeight;

    const canvas = await html2canvas(container, {
      scale: 2,
      useCORS: true,
      logging: true,
      scrollY: -window.scrollY, // 消除滚动偏移
      windowWidth: container.scrollWidth,
      windowHeight: container.scrollHeight,
    });

    const pdf = new jsPDF("p", "mm", "a4");
    const pageWidth = pdf.internal.pageSize.getWidth();
    const imgRatio = canvas.width / canvas.height;

    // 关键修改 3: 动态计算高度
    const imgHeight = (pageWidth * canvas.height) / canvas.width;
    pdf.addImage(
      canvas.toDataURL("image/png"),
      "PNG",
      0,
      0,
      pageWidth,
      imgHeight,
    );

    // 关键修改 4: 处理多页内容
    if (imgHeight > pdf.internal.pageSize.getHeight()) {
      pdf.addPage();
      pdf.addImage(
        canvas.toDataURL("image/png"),
        "PNG",
        0,
        -pdf.internal.pageSize.getHeight(),
        pageWidth,
        imgHeight,
      );
    }

    pdf.save("document.pdf");
  } catch (error) {
    console.error("生成失败:", error);
  } finally {
    document.body.removeChild(container);
  }
}

// 图片加载等待函数
const waitForImages = (element: HTMLElement) => {
  return new Promise<void>((resolve) => {
    const images = element.getElementsByTagName("img");
    let loaded = 0;

    const checkDone = () => {
      if (loaded >= images.length) resolve();
    };

    if (images.length === 0) return resolve();

    Array.from(images).forEach((img) => {
      if (img.complete) {
        loaded++;
        checkDone();
      } else {
        img.onload = () => {
          loaded++;
          checkDone();
        };
        img.onerror = checkDone;
      }
    });
  });
};

export function htmlToPdf(htmlCode: string) {
  // 1. 动态创建一个 div 元素,并配置为隐藏(display: none)
  const container = document.createElement("div");
  container.innerHTML = htmlCode;
  container.style.display = "none";
  document.body.appendChild(container);
  // 2. 为了让 html2canvas 能捕获内容,将 display 修改为 block,并移至视野之外
  container.style.display = "block";
  container.style.position = "absolute";
  container.style.top = "-9999px";
  container.style.left = "-9999px";
  window.pageYOffset = 0;
  document.documentElement.scrollTop = 0;
  document.body.scrollTop = 0;
  setTimeout(() => {
    html2canvas(container, {
      allowTaint: true,
      useCORS: true,
      scale: 2, // 提升画面质量,但是会增加文件大小
      height: container.scrollHeight, // 需要注意,element的 高度 宽度一定要在这里定义一下,不然会存在只下载了当前你能看到的页面   避雷避雷!!!
      windowHeight: container.scrollHeight,
    }).then(function (canvas) {
      var contentWidth = canvas.width;
      var contentHeight = canvas.height;
      // console.log('contentWidth', contentWidth)
      // console.log('contentHeight', contentHeight)
      // 一页pdf显示html页面生成的canvas高度;
      var pageHeight = (contentWidth * 841.89) / 592.28;
      // 未生成pdf的html页面高度
      var leftHeight = contentHeight;
      // console.log('pageHeight', pageHeight)
      // console.log('leftHeight', leftHeight)
      // 页面偏移
      var position = 0;
      // a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高  //40是左右页边距
      var imgWidth = 595.28 - 40;
      var imgHeight = (592.28 / contentWidth) * contentHeight;
      var pageData = canvas.toDataURL("image/jpeg", 1.0);
      var pdf = new jsPDF("p", "pt", "a4");
      // 有两个高度需要区分,一个是html页面的实际高度,和生成pdf的页面高度(841.89)
      // 当内容未超过pdf一页显示的范围,无需分页
      if (leftHeight < pageHeight) {
        // console.log('没超过1页')
        pdf.addImage(pageData, "JPEG", 20, 20, imgWidth, imgHeight);
      } else {
        while (leftHeight > 0) {
          // console.log('超过1页')
          pdf.addImage(pageData, "JPEG", 20, position, imgWidth, imgHeight);
          leftHeight -= pageHeight;
          position -= 841.89;
          // 避免添加空白页
          if (leftHeight > 0) {
            pdf.addPage();
          }
        }
      }
      pdf.save("out.pdf");
    });
  }, 1000);
}

export async function getPdfData(file: File) {
  try {
    const arrayBuffer = await file.arrayBuffer();
    const text = await pdfToText(new Uint8Array(arrayBuffer));
    return text;
  } catch (error) {
    console.error("Error extracting PDF content:", error);
    throw error;
  }
}