/* Slim Uiltjies — PDF generation Renders an invoice (or statement) HTML node into a PDF using html2canvas + jsPDF. Uses JPEG (more reliable than PNG for jsPDF). */ (function () { 'use strict'; function nextFrame() { return new Promise((r) => requestAnimationFrame(() => r())); } async function renderNodeToCanvas(node, scale = 2) { // Wait for fonts to be ready so capture is stable if (document.fonts && document.fonts.ready) { try { await document.fonts.ready; } catch {} } await nextFrame(); return window.html2canvas(node, { scale, backgroundColor: '#FFF8E7', useCORS: true, allowTaint: true, logging: false, windowWidth: node.scrollWidth, windowHeight: node.scrollHeight, }); } async function nodeToPdfBlob(node, { filename = 'document.pdf', scale = 2 } = {}) { const { jsPDF } = window.jspdf; const canvas = await renderNodeToCanvas(node, scale); // A4 portrait, units in pt const pdf = new jsPDF({ orientation: 'portrait', unit: 'pt', format: 'a4' }); const pageW = pdf.internal.pageSize.getWidth(); const pageH = pdf.internal.pageSize.getHeight(); // Calculate scaling const imgW = pageW; const scaleFactor = imgW / canvas.width; const pageCanvasH = pageH / scaleFactor; // canvas px that fits one page let renderedH = 0; let first = true; while (renderedH < canvas.height) { const sliceH = Math.min(pageCanvasH, canvas.height - renderedH); const slice = document.createElement('canvas'); slice.width = canvas.width; slice.height = sliceH; const ctx = slice.getContext('2d'); ctx.fillStyle = '#FFF8E7'; ctx.fillRect(0, 0, slice.width, slice.height); ctx.drawImage( canvas, 0, renderedH, canvas.width, sliceH, 0, 0, slice.width, sliceH ); // Use JPEG for reliability (PNG can fail with large images in jsPDF) const dataUrl = slice.toDataURL('image/jpeg', 0.92); if (!first) pdf.addPage(); const sliceImgH = sliceH * scaleFactor; pdf.addImage(dataUrl, 'JPEG', 0, 0, imgW, sliceImgH, undefined, 'FAST'); renderedH += sliceH; first = false; } const blob = pdf.output('blob'); blob.name = filename; return blob; } async function nodeToPdfDataUri(node, options = {}) { const blob = await nodeToPdfBlob(node, options); return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = () => resolve(reader.result); reader.onerror = () => reject(reader.error); reader.readAsDataURL(blob); }); } window.SUPDF = { nodeToPdfBlob, nodeToPdfDataUri }; })();