Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Scan for outdated or missing drivers - takes under a minuteDriver Scan →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.
- Navigate with a readiness condition such as
waitUntil: 'networkidle2'. - Have the page set
window.canvasReady = trueonly after the final draw and all required image loads or data promises finish. - Wait for that flag with
page.waitForFunction(). - Wait for
document.fonts.readyif text or labels affect layout. - 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.
#1 Best Overall
- 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.
Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchWindows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallImages 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
- 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-Originpolicy that permits the page. - Set
img.crossOriginbefore assigningimg.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.
await page.emulateMediaType('screen')applies screen CSS before capture.- Omit that call when print styles are intentional.
- Set
printBackground: truewhen CSS backgrounds, chart fills, or page artwork must appear. - Use
-webkit-print-color-adjust: exactwhere 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.
Recommended Free Tools
Rank #3
- 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.
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
- 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
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 bytoDataURL(). - 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:
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
canvasReadybecomes 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: trueis 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.
The Tool Desk
Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →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.




