Driver FixRecommendedSound, Wi-Fi or graphics acting up? Check drivers firstFind missing or outdated drivers fast.Check DriversOctober DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsWindows FixRecommendedWindows errors stealing your time? Find the fix fastScan stability, cleanup and performance issues.Fix Now×
Skip to content
Chromium

How to Load Canvas-Rendered Images in Puppeteer PDF Generation

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Wait for the application to finish drawing the canvas before calling page.pdf(). The most reliable pattern is to set a page-side readiness flag after every asynchronous image, data, and drawing operation completes, then wait for that flag in Puppeteer. Also wait for fonts, choose print or screen media deliberately, and enable backgrounds when the design requires them. Converting the canvas to an <img> is optional; use it when downstream PDF tooling needs a normal image resource or when you want an independently observable image-load event.

The deterministic capture sequence

page.pdf() captures the current page state at the moment it runs. networkidle2 only tells you that network activity has quieted; it does not prove that your application has completed a canvas draw, decoded an image, or rendered chart data. Use an application-specific signal for that work.

  1. Navigate with a readiness condition such as waitUntil: 'networkidle2'.
  2. Have the page set window.canvasReady = true only after the final draw and all required image loads or data promises finish.
  3. Wait for that flag with page.waitForFunction().
  4. Wait for document.fonts.ready if text or labels affect layout.
  5. Select screen or print media intentionally and call page.pdf() with the options your output needs.

Page code with an explicit readiness flag

<canvas id="chart" width="800" height="400"></canvas>
<script>
  const canvas = document.querySelector('#chart');
  const ctx = canvas.getContext('2d');

  // Complete all asynchronous data and image work before this point.
  ctx.fillStyle = '#245';
  ctx.fillRect(0, 0, canvas.width, canvas.height);
  window.canvasReady = true;
</script>

In a real chart, move the flag assignment below every fetch(), image onload, font-dependent measurement, and final drawing operation. If any promise can still change pixels, the flag is early.

Complete Puppeteer example

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({headless: true});
  const page = await browser.newPage();

  try {
    await page.goto('https://example.com/report', {
      waitUntil: 'networkidle2',
      timeout: 90000
    });

    await page.waitForFunction(
      () => window.canvasReady === true,
      { timeout: 30000 }
    );

    await page.evaluate(() => document.fonts.ready);

    // Use 'screen' when the PDF should match screen CSS.
    await page.emulateMediaType('screen');

    await page.pdf({
      path: 'output.pdf',
      printBackground: true,
      format: 'A4',
      waitForFonts: true
    });
  } finally {
    await browser.close();
  }
})();

The waitForFonts PDF option and an explicit document.fonts.ready wait address font loading, but neither one knows whether application JavaScript has finished drawing a canvas. Keep the canvas signal separate.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
#1 Best Overall
Brother Compact Monochrome Laser Printer, HLL2395DW, Flatbed Copy & Scan, Wireless Printing, NFC with Refresh Subscription Free Trial and Amazon Dash Replenishment Ready
  • Engineered for convenience – This new Brother Monochrome Laser Printer is conveniently equipped with a flatbed scan glass for quick copying and scanning. Mobile Device Compatibility AirPrint, Google Cloud Print 2.0, Brother iPrint and Scan, Mopria, Cortado Workplace
  • Optimized for efficiency – Engineered with new features, the HL L2395DW laser printer (replacement for the HLL2380DW) and has been optimized for efficiency, allowing you to print up to 36 pages per minute(1)
  • Faster, high quality prints: This monochrome laser printer is built with a 250 sheet paper capacity that helps improve efficiency due to less time spent refilling trays. It also handles both letter and legal sized paper. Power Source AC 120V 50/60Hz.Machine Noise (Ready/Printing): 30dB / 50dB
  • Cloud based print & scan – Print from and scan to popular Cloud services directly from the 2.7" color touchscreen, including Dropbox, Google Drive, Evernote, OneNote, and more(4)
  • Wireless printing & exceptional support – This printer’s simple to connect wireless technology allows you to submit print jobs from your laptop, smartphone, desktop, and tablets(2). The "Touch to connect" printing with NFC delivers added convenience(3).

Should you convert the canvas to an image?

For ordinary Chromium PDF output, a completed canvas can remain a canvas. Direct printing avoids serialization and is the simplest path. Convert it when a downstream processor expects an image element, when you need to verify an image’s own load event, or when replacing the canvas makes the document pipeline easier to inspect.

Approach Readiness control Memory and timing Cross-origin behavior Print fidelity
Print the canvas directly Requires an application flag after the final draw No bitmap serialization; still wait for all drawing and decoding Canvas can become tainted if foreign-origin pixels lack suitable CORS, although no export call is made Controlled by media selection, print backgrounds, and CSS color-adjust rules
Replace with an <img> made with toBlob() Wait for the replacement image’s load event Creates a Blob and object URL; practical for large images Export throws if the canvas is origin-unclean Normal image behavior after decode; still subject to PDF media settings
Replace with a data: URL from toDataURL() Wait for the image to load after assigning the URL Encodes the bitmap as a large in-memory string; convenient for small images Also fails when the canvas is tainted Same media and background rules as other images

Blob conversion for large canvases

await page.evaluate(async () => {
  const canvas = document.querySelector('#chart');
  if (!canvas || canvas.width === 0 || canvas.height === 0) {
    throw new Error('Canvas is missing or has zero dimensions');
  }

  const blob = await new Promise(resolve =>
    canvas.toBlob(resolve, 'image/png')
  );
  if (!blob) throw new Error('Canvas could not be encoded');

  const img = new Image();
  img.alt = 'Rendered chart';
  img.src = URL.createObjectURL(blob);
  await new Promise((resolve, reject) => {
    img.onload = resolve;
    img.onerror = reject;
  });

  canvas.replaceWith(img);
});

await page.pdf({
  path: 'output.pdf',
  printBackground: true,
  waitForFonts: true
});

Keep the object URL alive until after PDF generation. If the page remains open afterward, call URL.revokeObjectURL() only once the PDF no longer needs the image.

When a data URL is acceptable

toDataURL() is convenient for a small bitmap or a short-lived document. It returns a data URL string, which can become expensive for large canvases because the entire encoded image lives in memory as a string. For large charts or screenshots, prefer toBlob() and an object URL.

Canvas prerequisites that commonly break PDF output

Non-zero dimensions

A canvas whose width or height is zero has no useful bitmap. Check both the HTML attributes and the runtime properties before drawing or exporting. A zero-dimension toDataURL() result is the data:, URL rather than a rendered image.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Images must be decoded before the final draw

Do not set the readiness flag immediately after assigning an image’s src. Wait for its onload event (and any application-level decode step), then call drawImage, and only then mark the canvas ready.

Cross-origin pixels and tainting

Drawing an image from another origin without an appropriate CORS policy makes the canvas origin-unclean. Calls to toDataURL() or toBlob() can then throw a SecurityError. Fix the source rather than suppressing the error:

Rank #2
Brother MFC-L3710CW Compact Digital Color All-in-One Printer Providing Laser Printer Quality Results with Wireless, Amazon Dash Replenishment Ready
  • FAST PRINT AND SCAN: The Brother MFC-L3710CW lets you get things done with up to 19 ppm print speed and scans up to 29 ipm in black and 22 ipm in color
  • AFFORDABLE AND FLEXIBLE COLOR PRINTING: Affordably print professional quality, rich, vivid color documents with laser printer quality. The 250 sheet adjustable paper tray helps minimize refills and the manual feed slot handles varied printing needs
  • 3.7” COLOR TOUCHSCREEN: Print from and scan to popular cloud apps directly from the 3.7" color touchscreen including Dropbox, Google Drive, Evernote, OneNote and more. Save time by creating custom shortcuts on the touchscreen for your most used features.
  • PRINT AND CONNECT YOUR WAY: Print wirelessly from your desktop, laptop, smartphone and tablet with built-in wireless, and Wi-Fi Direct or connect locally to a single computer via USB interface.
  • UNIT DIMENSIONS (WxDxH): 16.1” W x 18.7” D x 16.3” H
  • Serve the image with an Access-Control-Allow-Origin policy that permits the page.
  • Set img.crossOrigin before assigning img.src.
  • Proxy the asset through the same origin when you control neither the source headers nor the browser request.

Directly printing a canvas may avoid an export call, but it does not make an origin-unclean canvas safe to serialize later.

Media, colors, and backgrounds in the PDF

Puppeteer PDF generation uses print media by default. A canvas may be present while surrounding CSS appears wrong because print styles hide elements, alter dimensions, or remove colors. Choose the media mode that matches the intended document:

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  • await page.emulateMediaType('screen') applies screen CSS before capture.
  • Omit that call when print styles are intentional.
  • Set printBackground: true when CSS backgrounds, chart fills, or page artwork must appear.
  • Use -webkit-print-color-adjust: exact where exact print colors are required by the design.

These settings affect the page around the canvas as well as the visual context in which the canvas is displayed.

Race-proofing asynchronous charts

For a chart assembled from several operations, make one promise represent the complete render and set the flag in its final continuation. This prevents a fast first draw from winning a race against a slower image or data request.

<script>
  async function renderChart() {
    const canvas = document.querySelector('#chart');
    const ctx = canvas.getContext('2d');
    const response = await fetch('/chart-data.json');
    const points = await response.json();

    const image = new Image();
    image.crossOrigin = 'anonymous';
    image.src = '/branding/logo.png';
    await new Promise((resolve, reject) => {
      image.onload = resolve;
      image.onerror = reject;
    });

    // Every pixel-changing operation belongs before this assignment.
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    drawAxesAndPoints(ctx, points);
    ctx.drawImage(image, 20, 20);
    window.canvasReady = true;
  }

  renderChart().catch(error => {
    window.canvasError = String(error);
    console.error(error);
  });
</script>

In Puppeteer, wait for canvasReady and expose canvasError in your diagnostics. A timeout should tell you whether the page never completed, rather than silently producing a partial PDF.

Troubleshooting missing or incorrect canvas images

The PDF contains a blank chart

Cause: page.pdf() ran before the final draw. Fix: set the readiness flag after all data, image loads, and drawing promises, then use waitForFunction() instead of a guessed delay.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Rank #3
MixPad Free Multitrack Recording Studio and Music Mixing Software [Download]
  • Create a mix using audio, music and voice tracks and recordings.
  • Customize your tracks with amazing effects and helpful editing tools.
  • Use tools like the Beat Maker and Midi Creator.
  • Work efficiently by using Bookmarks and tools like Effect Chain, which allow you to apply multiple effects at a time
  • Use one of the many other NCH multimedia applications that are integrated with MixPad.

The readiness wait times out

Cause: an exception, rejected fetch, failed image load, or code path that never assigns the flag. Fix: catch render errors in the page, expose a diagnostic value, inspect the browser console, and make every success and failure path explicit. Increase the timeout only after correcting the lifecycle.

The chart is the wrong size or missing entirely

Cause: the canvas has zero dimensions, is resized after drawing, or responsive layout has not settled. Fix: verify canvas.width and canvas.height, set the viewport before navigation, perform any final resize before the last draw, and then set the flag.

Export throws SecurityError

Cause: a cross-origin image tainted the canvas. Fix: configure CORS, set crossOrigin before src, or proxy the image through the page’s origin. Conversion cannot succeed until the canvas is origin-clean.

Colors or CSS backgrounds disappear

Cause: print media rules or disabled background printing. Fix: choose screen media when appropriate, enable printBackground, and apply -webkit-print-color-adjust: exact for elements that require exact colors.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Text around the canvas shifts between runs

Cause: fonts were not ready when layout was measured. Fix: await document.fonts.ready and use the PDF option waitForFonts; retain the independent canvas readiness wait.

The replacement image is blank

Cause: the Blob was null, the object URL was revoked too early, or PDF generation started before img.onload. Fix: reject on a null Blob, keep the URL alive through page.pdf(), and await the replacement image’s load event.

Rank #4
Corel PDF Fusion Software
  • Save money by using PDF Fusion to view over 100 file formats without having to purchase additional software
  • Merge incompatible files quickly and easily by dragging and dropping in PDF Fusion to create a new PDF documents
  • Save time with PDF Fusion's editing tools to reuse the content from existing documents without starting from scratch
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Performance and reliability choices

  • Prefer a readiness signal to fixed sleeps. A long delay slows every successful job; a short delay remains racy.
  • Use toBlob() for large bitmaps to avoid the large in-memory string produced by toDataURL().
  • Keep canvas dimensions realistic. Very large bitmaps increase encoding, memory, and PDF processing time.
  • Reuse one page only when your application can reset its readiness state and object URLs safely; otherwise isolate jobs to avoid stale flags.
  • Record whether the page reached readiness, its final dimensions, and any export error so failed PDFs are diagnosable.
  • Wait for the specific selector or application state that means the chart is complete. Network-idle is a navigation aid, not a rendering contract.

Or skip the browser setup

ScreenshotNeo is a website screenshot API and MCP server when you need a rendered page without maintaining your own Puppeteer lifecycle. One GET request returns PNG, JPEG, WebP, or PDF. It removes cookie-consent banners, newsletter popups, and chat widgets before capture; bot checks, blank pages, timeouts, failed loads, and cache hits are not billed. Responses identify the page verdict and billing status in X-Page-Verdict and X-Billed headers. Its MCP server exposes take_screenshot, get_page_info, and capture_pdf to Claude, Cursor, and other MCP clients.

curl -G "https://api.screenshotneo.com/v1/shot" 
  -d access_key=YOUR_API_KEY 
  --data-urlencode url=https://stripe.com 
  -o shot.webp

See the ScreenshotNeo API documentation for request options. The same request in Python is:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
    timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)

And in Node.js:

const q = new URLSearchParams({
  access_key: 'YOUR_API_KEY',
  url: 'https://stripe.com'
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = Buffer.from(await res.arrayBuffer());
require('fs').writeFileSync('shot.webp', data);

ScreenshotNeo includes full-page capture with lazy images loaded, element selectors, custom CSS and JavaScript, waits for selectors, delays or network idle, device and viewport controls, PDF paper and margin settings, custom headers and cookies, caching with a chosen TTL, async jobs with signed webhooks, bulk capture, usage reporting, and an OpenAPI specification. Every feature is on every plan: 1,000 shots per month are free with no card; paid plans start at $5 for 3,000 shots, with yearly billing providing two months free. Create a free ScreenshotNeo account.

Verification checklist before shipping

  • The final draw occurs before canvasReady becomes true.
  • Every source image has loaded and satisfies the required CORS policy.
  • Canvas width and height are non-zero at capture time.
  • Fonts are ready before PDF layout is finalized.
  • The selected media type matches the intended design.
  • printBackground: true is enabled when backgrounds matter.
  • If converting, the Blob is non-null, the object URL remains alive, and the replacement image has loaded.
  • Failures expose a useful error instead of silently writing a partial PDF.

Frequently Asked Questions

Is a fixed timeout ever sufficient?

It can mask a race in a controlled demo, but it cannot prove that variable network, image, or data work has finished. A page-side readiness condition is the deterministic contract.

Can I export a canvas after drawing a remote image?

Only when the image is loaded under a CORS policy that keeps the canvas origin-clean. Otherwise serialization methods can raise a SecurityError.

Why does a canvas look right in the browser but differ in the PDF?

PDF generation applies print media by default, so print CSS, background settings, and color-adjust rules can change the surrounding layout and colors.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Quick Recap

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Read next

Recommended PC Tool
Recommended PC Tool
PC Slower Than It Used to Be?Free scan - under a minute
Outdated Drivers Are Slowing You DownFree scan - exact matches

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.