diff --git a/src/components/forms/custom-form-builder.tsx b/src/components/forms/custom-form-builder.tsx index 6949c63..12782f1 100644 --- a/src/components/forms/custom-form-builder.tsx +++ b/src/components/forms/custom-form-builder.tsx @@ -943,6 +943,47 @@ export function CustomFormBuilder() { drawTablePdf(seg.rows); continue; } + if (seg.kind === "image") { + // Compute display size in points. Default cap to content width. + let wPt = seg.widthPx ? seg.widthPx * 0.75 : Math.min(maxW, 240); + let hPt = seg.heightPx ? seg.heightPx * 0.75 : 0; + if (wPt > maxW) { + const scale = maxW / wPt; + wPt = maxW; + if (hPt) hPt = hPt * scale; + } + // If height unknown, estimate from natural ratio via Image() + if (!hPt) { + try { + const im = new Image(); + im.src = seg.src; + // For data URLs, naturalWidth/Height is generally available synchronously after a tick. + // We approximate with a default 4:3 if unavailable. + const nw = im.naturalWidth || 0; + const nh = im.naturalHeight || 0; + hPt = nw > 0 && nh > 0 ? wPt * (nh / nw) : wPt * 0.75; + } catch { + hPt = wPt * 0.75; + } + } + if (y + hPt > pageH - margin) { + doc.addPage(); + y = margin; + } + let x = margin; + if (seg.align === "center") x = margin + (maxW - wPt) / 2; + else if (seg.align === "right") x = margin + (maxW - wPt); + try { + // jsPDF auto-detects format from data URL header + const fmt = (seg.src.match(/^data:image\/(png|jpeg|jpg|gif|webp)/i)?.[1] || "PNG").toUpperCase(); + doc.addImage(seg.src, fmt as any, x, y, wPt, hPt); + } catch (e) { + // Skip image if it fails to embed + console.warn("Image embed failed", e); + } + y += hPt + 6; + continue; + } const indentPx = seg.indent || 0; const indentPt = indentPx * 0.75; // px → pt const markerGapPt = seg.marker ? Math.max(14, doc.getTextWidth(seg.marker) + 8) : 0;