eKoopmans / html2pdf.js

Client-side HTML-to-PDF rendering using pure JS.
MIT License
4.12k stars 1.39k forks source link

0.10.2 introduce PDF to cut off on the left #715

Open DenysMoro opened 2 months ago

DenysMoro commented 2 months ago

Hi. We did upgrade to 0.10.2 because of security issues, but PDF is broken now. Can you please help us? I did downgrade and issue is gone, but we don't wanna to downgrade because of xmldom security issues.

Correct PDF (0.9.0 - 0.9.3 version) Napoleon Maclovio Sandy Saavedra_20 Fundo_2024 (2).pdf

Incorrect PDF (0.10.2 version) Napoleon Maclovio Sandy Saavedra_20 Fundo_2024 (3).pdf

Some configs:

// function that returns config - start

  const doc_width = 11.69; // A4 measures 210 × 297 millimeters or 8.27 × 11.69 inches
  const doc_height = 8.27;
  const dpi = 120; // targeting ~1200 window width
  const img_width = doc_width * dpi;
  const img_height = doc_height * dpi;
  const win_width = img_width;
  const win_height = img_height;

  const html2canvasOpts = {
    width: img_width,
    height: img_height,
    windowWidth: win_width,
    windowHeight: win_height,
    scale: 2,
    letterRendering: true,
    useCORS: true,
    removeContainer: false,
  };

  const jsPDFOpts = {
    orientation, // 'landscape'
    unit: 'in',
    format: [doc_height, doc_width],
  };

  const pdfConfig = {
    filename: `${fileName}.pdf`,
    image: { type: 'jpeg', quality: 0.7 },
    html2canvas: html2canvasOpts,
    jsPDF: jsPDFOpts,
  };

// function that returns config - end

const HTMLToPDF = async (html: string[], fileName: string, output?: string) => {
  const a4PdfConfig = getA4PdfConfig('landscape', fileName); // returns pdfConfig

  // Initialize a PDF document using html2pdf library
  let doc = html2pdf()
    .set(a4PdfConfig) // Set the PDF configuration to A4 size
    .from(html[0]) // Convert the content of the first element to PDF
    .toPdf();

  // Convert the HTMLCollection to an array for easier manipulation
  const elementsArray = Array.from(html);

  // Loop through additional elements starting from the second one
  for (let j = 1; j < elementsArray.length; j += 1) {
    doc = doc
      .get('pdf') // Retrieve the existing PDF document
      .then((pdf: any) => {
        pdf.addPage(); // Add a new page to the PDF document
      })
      .from(elementsArray[j]) // Convert the content of the current element to PDF
      .toContainer()
      .toCanvas()
      .toImg()
      .toPdf();
  }

  // Use Promise.all to wait for all pages to be converted
  await Promise.all(elementsArray.map(element => doc.from(element).toPdf()));

  if (output) {
    return doc.output(output);
  }

  return doc.save();
}
DenysMoro commented 2 months ago

I did noticed that it cut off when you change screen (window) width

DenysMoro commented 2 months ago

@eKoopmans Hello. Do you have any ideas?

DenysMoro commented 2 months ago

Did figure out. The issue was because of CSS + windowWidth: win_width, windowHeight: win_height for html2canvas.

We are generating A4 size and using the same size for windowWidth and windowHeight what is wrong and it did move content somehow to the left. So I removed windowWidth and windowHeight and starting to use constant size at CSS for HTML container.

renaldodev commented 2 months ago

I had the same issue, what I did was create a wrapper with fixed dimensions based on A4 portait.