Two different settings cause the symptoms in the Angular 6 example: a data URL has no download filename because it is being assigned to window.location.href, while the PDF remains A4 because new jspdf('p', 'mm', 'a4') explicitly requests A4. Give the image an anchor with a download filename, and create the PDF with custom page dimensions that match the card you want to print. If images disappear, check cross-origin permissions before changing export code.
Fix the PNG download filename
canvas.toDataURL('image/png') produces a PNG data URL. It contains image bytes and a MIME type, but it does not contain a filesystem name. Navigating to that URL, including after changing its MIME string to image/octet-stream, leaves filename handling to the browser.
Use an anchor instead. Set its download property to a name ending in .png (or .jpg when exporting JPEG), assign the data URL to href, and click it.
html2canvas(element).then(canvas => {
const link = document.createElement('a');
link.download = 'card.png';
link.href = canvas.toDataURL('image/png');
link.click();
});
This is the documented html2canvas download pattern. Do not replace a PNG data URL with image/octet-stream when the goal is a predictable image file. A browser or security context can still apply its own download rules, but the anchor supplies the intended filename.
#1 Best Overall
Angular component example
import html2canvas from 'html2canvas';
export class CardComponent {
downloadCard(): void {
const element = document.getElementById('card');
if (!element) {
throw new Error('Card element was not found');
}
html2canvas(element).then(canvas => {
const link = document.createElement('a');
link.download = 'card.png';
link.href = canvas.toDataURL('image/png');
link.click();
});
}
}
The exact import form depends on the html2canvas version installed by the Angular 6 project. Check package.json and package-lock.json and use that version’s documentation; a current example does not prove compatibility with a 2018 dependency.
Why the PDF is A4
The original constructor asks jsPDF for portrait A4 in millimetres:
const pdf = new jspdf('p', 'mm', 'a4');
The later imgWidth = 208 assignment changes only the image’s placement width. It cannot change the page format. The proportional height calculation preserves the captured image’s aspect ratio, but it does not make the page the same size as the card.
Choose a physical page size first
A PDF page has physical units; a canvas has pixels. Decide the desired page width and height in one unit, then place the raster image inside those bounds. Do not treat 208 mm as a standard card measurement: it was simply a value in the reported code, and the intended card dimensions were not supplied.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Rank #2
Custom format with the options object
import { jsPDF } from 'jspdf';
html2canvas(element).then(canvas => {
const pdf = new jsPDF({
orientation: 'landscape',
unit: 'mm',
format: [100, 60]
});
const pageWidth = 100;
const pageHeight = 60;
const imageRatio = canvas.width / canvas.height;
const pageRatio = pageWidth / pageHeight;
let imageWidth;
let imageHeight;
let x;
let y;
if (imageRatio > pageRatio) {
imageWidth = pageWidth;
imageHeight = pageWidth / imageRatio;
x = 0;
y = (pageHeight - imageHeight) / 2;
} else {
imageHeight = pageHeight;
imageWidth = pageHeight * imageRatio;
y = 0;
x = (pageWidth - imageWidth) / 2;
}
pdf.addImage(canvas.toDataURL('image/png'), 'PNG', x, y,
imageWidth, imageHeight);
pdf.save('card.pdf');
});
Replace [100, 60] with the physical dimensions you actually need. This “contain” calculation preserves the card’s proportions and may leave white margins. Filling the page by stretching distorts text and graphics; cropping fills the page but removes content. Choose deliberately.
Legacy constructor form
Older jsPDF releases may use the positional constructor. The equivalent concept is:
const pdf = new jspdf('l', 'mm', [100, 60]);
Whether this signature is available in the Angular 6 project’s installed version must be verified against its package version. Current jsPDF documentation also shows an options object such as new jsPDF({ orientation: 'landscape', unit: 'in', format: [4, 2] }); current documentation alone does not establish compatibility with the historical dependency.
Relate canvas pixels to PDF size
html2canvas captures pixels. jsPDF interprets the width and height supplied to addImage in the document unit you selected. A larger canvas gives more raster detail at the same physical size; it does not automatically create a larger paper page. If the capture is too small, increase the capture scale where supported by your installed html2canvas version, or render a suitably large element, then keep the PDF dimensions fixed.
Rank #3
For a CSS card that is 400 by 240 CSS pixels, you must still choose a physical output size—for example, 100 by 60 mm. The pixel-to-millimetre conversion is an output decision, not a property html2canvas can infer reliably. Preserve the ratio 400:240 (5:3) when fitting the image.
Images missing from the canvas: CORS diagnosis
Browsers protect canvases from cross-origin resources. html2canvas may skip an image that would taint the canvas. useCORS: true helps only when the image server responds with an appropriate Access-Control-Allow-Origin header.
html2canvas(element, {
useCORS: true
}).then(canvas => {
// export canvas here
});
Three hosting choices
- Same origin: Serve the page and images from the same scheme, host and port. This is usually the simplest arrangement.
- Cross origin with CORS: Configure the image server to return an allowed origin, then use
useCORS: true. - Same-origin proxy: Fetch the asset through your own server and expose it from the application’s origin when you cannot change the remote server.
html2canvas cannot circumvent browser content-policy restrictions. allowTaint is not a fix that makes a tainted canvas safely readable for export. Inspect the browser network panel for the image response and its CORS headers.
Blank, clipped or visually different captures
Viewport and scrolling
If a long card is clipped, the clone may be using viewport dimensions rather than the element’s full scroll area. Try dimensions based on the element:
Rank #4
const rect = element.getBoundingClientRect();
html2canvas(element, {
windowWidth: element.scrollWidth || Math.ceil(rect.width),
windowHeight: element.scrollHeight || Math.ceil(rect.height)
});
Use the exact option names supported by your installed version. Very large canvases can exceed browser or device limits; those limits vary by browser, platform and hardware, so there is no universal safe megapixel threshold. Capture a smaller region, reduce scale, or split a very large export.
Unsupported CSS
html2canvas rebuilds a representation by traversing the DOM and reading implemented style information; it is not a literal screenshot. CSS properties that the library does not implement can differ from what you see on screen. Simplify unsupported effects, provide fallback styles, or use a browser-level screenshot service when pixel fidelity is essential.
Reliable export sequence
- Wait until the card’s data and web fonts have loaded.
- Confirm every image URL works in the browser and decide whether it is same-origin, CORS-enabled or proxied.
- Capture the intended element, accounting for its full scroll dimensions.
- For an image, create an anchor and set an explicit filename.
- For a PDF, select physical page dimensions, preserve the image ratio, and place the image with deliberate margins.
- Test a small card and a card containing remote images before exporting large pages.
Common errors and fixes
| Symptom | Likely cause | Fix |
|---|---|---|
File downloads without .png |
Data URL was navigated to directly | Use an anchor with download = 'card.png'. |
| PDF is always A4 | Constructor contains 'a4' |
Pass a custom [width, height] format. |
| Image absent in canvas | Remote response lacks CORS permission | Use same-origin hosting, configure CORS, or proxy the asset. |
| Blank or partial canvas | Oversized canvas or viewport-sized clone | Reduce capture size/scale and set appropriate window dimensions. |
| Effects differ from the page | CSS is not implemented by html2canvas | Use supported styles or a browser screenshot approach. |
Or skip the browser setup
ScreenshotNeo provides a website screenshot API and MCP server. It accepts consent banners before capture and removes more than 60 known consent platforms, newsletter popups and chat widgets; each step can be disabled. Bot checks, blank pages, timeouts, failed loads and cache hits are not billed, and response headers identify the page verdict and billing status.
One GET request returns PNG, JPEG, WebP or PDF. The API supports full-page lazy-image loading, CSS-selector element capture, dark mode, device presets or custom viewports, retina scale, PDF paper size and margins, custom CSS and JavaScript, clicks, waits, request blocking, headers, cookies, user agents, authorization, timezone, geolocation, transparent backgrounds, resizing, TTL caching, signed image links, asynchronous webhooks, bulk capture of up to 100 URLs per call, usage reporting and an OpenAPI specification.
The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →cURL
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
Python
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
timeout=90,
)
open("shot.webp", "wb").write(r.content)
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}`);
See the ScreenshotNeo documentation for authentication and capture parameters. The Free plan includes 1,000 screenshots each month without a card; paid plans start at $5 for 3,000 shots. An MCP server lets Claude, Cursor and other MCP clients call take_screenshot, get_page_info and capture_pdf.
Create a free ScreenshotNeo account to try the 1,000 monthly screenshots.
Frequently Asked Questions
Can I make a PDF exactly the same physical size as a CSS card?
Yes, but you must choose a CSS-to-physical conversion and pass the resulting width and height as the custom PDF format; the browser cannot infer your preferred paper size.
Will useCORS fix every missing image?
No. It works only when the remote image response grants the requesting origin with an appropriate CORS header; otherwise use same-origin hosting or a proxy.
Free tools Windows power users keep installed
One-click scans. No signup required.
Why does the PDF look blurry even when the page size is correct?
The PDF contains a raster canvas. Increase capture resolution within browser limits or reduce the physical output size while preserving the card ratio.
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.

