From 8f571ddc3023a00925524442d8385dd297c6c5d5 Mon Sep 17 00:00:00 2001 From: sahilkhan09k Date: Fri, 13 Mar 2026 07:27:07 +0530 Subject: [PATCH] fix: ensure images load correctly when printing to PDF (#14618) Fixes #14304 ## Summary This PR resolves an issue where images sometimes fail to appear when exporting or printing AFFiNE pages to PDF. The issue occurs because images may not finish loading inside the hidden print iframe before `window.print()` is triggered. ## Changes - Avoid using `display: none` for the print iframe and instead keep it hidden while remaining in the rendering tree to ensure resources load correctly. - Remove `loading="lazy"` from all images before printing to prevent viewport-based lazy loading from blocking image fetches. - Force image reload by reassigning the `src` attribute after removing lazy loading. - Add a `waitForImages` helper to ensure all images (including those inside Shadow DOM) finish loading before calling `window.print()`. - Improve reliability by checking both `img.complete` and `img.naturalWidth` to confirm successful image loading. - Wait for fonts using `document.fonts.ready` before triggering the print dialog. ## Verification 1. Run AFFiNE in development mode: npm run dev 2. Open a page containing multiple images. 3. Click **Print** and select **Save as PDF** (or any PDF printer). 4. Verify that all images appear correctly in the generated PDF. ## Notes This change focuses only on improving the reliability of the existing print-to-PDF workflow without altering any feature flags or export behavior. ## Summary by CodeRabbit * **Bug Fixes** * Improved PDF export reliability by waiting for all images (including inside shadow content) and fonts to load before printing. * Removed lazy-loading interference so images reliably appear in exports. * Ensured styles and light-theme attributes are consistently applied to the print document. * **Improvements** * More robust print preparation using a hidden-but-rendering iframe document, deep-cloning content (flattening shadow DOM), and preserved canvas mapping for accurate renders. --- .../affine/shared/src/utils/print-to-pdf.ts | 182 +++++++++++++++--- 1 file changed, 160 insertions(+), 22 deletions(-) diff --git a/blocksuite/affine/shared/src/utils/print-to-pdf.ts b/blocksuite/affine/shared/src/utils/print-to-pdf.ts index 61a656e5de..a94e00d4c8 100644 --- a/blocksuite/affine/shared/src/utils/print-to-pdf.ts +++ b/blocksuite/affine/shared/src/utils/print-to-pdf.ts @@ -17,7 +17,14 @@ export async function printToPdf( return new Promise((resolve, reject) => { const iframe = document.createElement('iframe'); document.body.append(iframe); - iframe.style.display = 'none'; + // Use a hidden but rendering-enabled state instead of display: none + Object.assign(iframe.style, { + visibility: 'hidden', + position: 'absolute', + width: '0', + height: '0', + border: 'none', + }); iframe.srcdoc = ''; iframe.onload = async () => { if (!iframe.contentWindow) { @@ -28,6 +35,44 @@ export async function printToPdf( reject(new Error('Root element not defined, unable to print pdf')); return; } + + const doc = iframe.contentWindow.document; + + doc.write(``); + doc.close(); iframe.contentWindow.document .write(`