Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Scan for outdated or missing drivers - takes under a minute3Clear out junk files and repair common Windows errorsUse one jsPDF document, place the first canvas with addImage(), and call addPage() before each subsequent canvas. The canvas itself is accepted as image input; a PNG data URL also works. The important details are converting each canvas’s pixel dimensions into the PDF’s configured unit, preserving its aspect ratio, and adding pages before saving.
Complete example: one canvas per PDF page
Install jsPDF with your package manager, then import it in the module that creates the PDF:
npm install jspdf
This example assumes canvas1, canvas2, and canvas3 are already-rendered HTML canvas elements. It creates A4 portrait pages with a 10 mm margin and centers each canvas without distortion.
import { jsPDF } from "jspdf";
const canvases = [canvas1, canvas2, canvas3];
const pdf = new jsPDF({
orientation: "portrait",
unit: "mm",
format: "a4"
});
const margin = 10;
const pageWidth = pdf.internal.pageSize.getWidth();
const pageHeight = pdf.internal.pageSize.getHeight();
const maxWidth = pageWidth - margin * 2;
const maxHeight = pageHeight - margin * 2;
canvases.forEach((canvas, index) => {
if (index > 0) {
pdf.addPage("a4", "portrait");
}
const scale = Math.min(
maxWidth / canvas.width,
maxHeight / canvas.height
);
const width = canvas.width * scale;
const height = canvas.height * scale;
const x = (pageWidth - width) / 2;
const y = (pageHeight - height) / 2;
pdf.addImage(canvas, "PNG", x, y, width, height);
});
pdf.save("canvases.pdf");
The first page is created by the jsPDF constructor. For every later canvas, addPage() creates and activates a new page; then addImage() places that canvas on the active page. Saving only happens after the final image has been added.
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 →#1 Best Overall
- EDIT text, images & designs in PDF documents. ORGANIZE PDFs. Convert PDFs to Word, Excel & ePub.
- READ and Comment PDFs – Intuitive reading modes & document commenting and mark up.
- CREATE, COMBINE, SCAN and COMPRESS PDFs
- FILL forms & Digitally Sign PDFs. PROTECT and Encrypt PDFs
- LIFETIME License for 1 Windows PC or Laptop. 5GB MobiDrive Cloud Storage Included.
How the fit calculation works
Canvas dimensions are normally reported in pixels, while this document uses millimetres. jsPDF does not automatically choose a page fit policy for you. The destination x, y, width, and height values are interpreted in the unit selected in the constructor.
- Available area: page width and height minus both margins.
- Scale: the smaller of the width ratio and height ratio, so neither dimension exceeds the available area.
- Position: subtract the scaled image size from the page size and divide by two to center it.
- Aspect ratio: use the same scale for width and height; independently setting both dimensions will stretch the drawing.
If you want top-left placement instead of centering, use x = margin and y = margin. If the canvas must fill the entire page, calculate a cover-style scale and accept that some content may be cropped, or split the drawing into several canvases before export.
Passing a canvas directly or as encoded image data
Direct canvas input
An existing HTML canvas can be passed directly to addImage():
pdf.addImage(canvas, "PNG", x, y, width, height);
This keeps the application flow simple and avoids an intermediate string. Specify the format explicitly when you know it, such as PNG, JPEG, or WEBP.
Data URL input
If another part of your application already serializes the canvas, pass the resulting data URL instead:
const imageData = canvas.toDataURL("image/png");
pdf.addImage(imageData, "PNG", x, y, width, height);
Use a matching format argument and data URL. PNG is useful when transparency or sharp line art matters; JPEG can produce smaller files for photographic content, but it does not preserve transparency. Browser encoding behavior and memory use can vary, so test the chosen format with the canvases your application actually produces.
Reusable helper for any number of canvases
Putting the placement logic in a function makes it easier to export a dynamic array, change margins, or switch page formats:
import { jsPDF } from "jspdf";
function addCanvasPages(canvases, options = {}) {
const {
orientation = "portrait",
unit = "mm",
format = "a4",
margin = 10,
imageFormat = "PNG",
filename = "canvases.pdf"
} = options;
if (!canvases.length) {
throw new Error("At least one canvas is required");
}
const pdf = new jsPDF({ orientation, unit, format });
canvases.forEach((canvas, index) => {
if (!canvas || !canvas.width || !canvas.height) {
throw new Error(`Canvas ${index + 1} has no usable dimensions`);
}
if (index > 0) {
pdf.addPage(format, orientation);
}
const pageWidth = pdf.internal.pageSize.getWidth();
const pageHeight = pdf.internal.pageSize.getHeight();
const availableWidth = pageWidth - margin * 2;
const availableHeight = pageHeight - margin * 2;
const scale = Math.min(
availableWidth / canvas.width,
availableHeight / canvas.height
);
const width = canvas.width * scale;
const height = canvas.height * scale;
const x = (pageWidth - width) / 2;
const y = (pageHeight - height) / 2;
pdf.addImage(canvas, imageFormat, x, y, width, height);
});
pdf.save(filename);
}
addCanvasPages([canvas1, canvas2, canvas3], {
margin: 12,
imageFormat: "PNG",
filename: "drawing-set.pdf"
});
Validate dimensions before calling addImage(). A canvas can exist in the DOM while still having a zero drawing size, especially when its dimensions are assigned by a component after initial render.
Choose page size, orientation, and units deliberately
Set orientation, measurement unit, and page format when constructing the document:
const pdf = new jsPDF({
orientation: "landscape",
unit: "pt",
format: "letter"
});
- Orientation:
"portrait"or"landscape". - Units: commonly
"mm","pt","in", or"px"; use the same unit for every placement calculation. - Format: standard names such as
"a4"and"letter", or a custom dimension array supported by the API.
Subsequent pages can use a standard format and orientation:
Rank #2
- Edit PDFs with Ease. Modify text, images, and layouts directly within your PDF documents.
- Convert & Organize. Export PDFs to Word, Excel, or ePub, and organize files with ease.
- Read & Annotate. Enjoy intuitive reading modes and powerful tools to comment, highlight, and mark up PDFs.
- Create & Manage PDFs. Create new PDFs, combine multiple files, scan documents, and compress for easy sharing.
- Fill & Sign Forms. Complete forms and digitally sign documents with secure e-signature tools.
pdf.addPage("letter", "landscape");
For a custom page, pass the documented dimension array in the format position. If every page has the same geometry, keeping the constructor and addPage() arguments consistent avoids accidental size changes.
Rendering canvases before exporting
Export only after each canvas contains its final pixels. If a chart, font, image, or other drawing operation is asynchronous, wait for those rendering promises before calling addImage(). Confirm the final canvas.width, canvas.height, and visible content at export time.
For high-resolution output, set the canvas’s backing-store dimensions intentionally and scale the drawing context for the device pixel ratio. The PDF placement size is still determined by the destination dimensions you pass to jsPDF; a larger source canvas increases detail but also increases encoding time and memory consumption.
Large canvases can create large data URLs and temporarily require substantial memory. Prefer direct canvas input when it fits your application, release references after export where appropriate, and consider exporting in batches if a single document contains many very large pages.
One canvas per page versus one canvas split across pages
One canvas per page
This is the simplest case: each canvas is an independent image, and addPage() separates them. It preserves each canvas’s complete aspect ratio as long as it fits the available page rectangle.
One oversized canvas split across pages
addImage() accepts destination dimensions, but it does not decide how an unusually tall or wide drawing should be paginated. If a single canvas is taller than the page, choose a policy in your code: scale it down, crop it, or render page-sized slices into separate canvases and add each slice to its own page. Slicing is preferable when text must remain readable.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Mixed orientations
You can create a portrait document and add a landscape page when needed:
const pdf = new jsPDF({ orientation: "portrait", unit: "mm", format: "a4" });
pdf.addImage(firstCanvas, "PNG", 10, 10, 190, 277);
pdf.addPage("a4", "landscape");
pdf.addImage(wideCanvas, "PNG", 10, 10, 277, 190);
Recalculate page width, page height, and fit dimensions after every page-size or orientation change.
Canvas plugin or addImage()?
For an already-rendered HTML canvas, direct addImage(canvas, ...) is the straightforward route. The jsPDF Canvas plugin is a different abstraction: it wraps canvas-like drawing operations so code can draw against a PDF-backed canvas interface. Choose it when your application needs that drawing interface; do not add it merely because you already have finished canvas elements. A version-specific compatibility matrix is not established here, so verify plugin behavior against the jsPDF version used by your project.
Troubleshooting
Only one page appears
Call addPage() between image additions, not before the first page and not after save(). The first canvas belongs on the page created by the constructor.
Rank #3
- EVERY PDF TOOL UNLOCKED - 30+ tools in one app: edit text and images, convert, merge, split, compress, sign, OCR, redact, watermark, batch process, and more. No feature gates, no upsells, nothing held back.
- PAY ONCE, OWN FOREVER — A one-time purchase, not a subscription. Other apps runs $240/year — Scrivar is yours for life, with free updates included.
- UNLIMITED eSIGN, BUILT IN — Send contracts and forms for signature and track every step. Recipients sign in their browser with no account or app needed. Replace DocuSign and save hundreds a year.
- PC, MAC, AND WEB — Install on any Win 10/11 PC or macOS 11+ Mac (Intel or Apple Silicon), or work in your browser at scrivar.com. Same tools, same account, everywhere you work.
- OCR + FULL OFFICE CONVERSION — Turn scanned documents into searchable, selectable text, and convert PDFs to and from Word, Excel, and PowerPoint with formatting kept intact.
The image is clipped, stretched, or tiny
Check that x, y, width, and height use the document’s configured unit. Recheck the available area after subtracting margins, and derive both destination dimensions from one scale factor.
The PDF is blank
Inspect the canvas immediately before export. Ensure its width and height are non-zero, its drawing operations have completed, and it is not being cleared or replaced while the export loop runs.
Transparency or format looks wrong
Pass an explicit format and inspect the source data. Use PNG when transparency is required. If you use a data URL, make sure its MIME type and the addImage() format agree.
Later pages have the wrong size
Supply the intended format and orientation to each addPage() call, then recalculate the active page dimensions. Do not reuse portrait measurements after switching to landscape.
Free tools Windows power users keep installed
One-click scans. No signup required.
Export is slow or the browser runs out of memory
Reduce unnecessary backing-store resolution, avoid converting every canvas to a duplicate data URL, and export fewer very large canvases per document. Test on the least capable browser and device you support.
Or skip the browser setup
If your actual requirement is a clean screenshot or PDF of a web page rather than exporting locally rendered canvas elements, ScreenshotNeo provides a single HTTP endpoint. It is not a replacement for embedding arbitrary in-memory canvas objects, but it can remove browser automation from webpage capture workflows.
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 documentation for request options. Before capture, it accepts cookie or consent banners like a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup step can be disabled. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, and the response identifies 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. The Free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 shots. Sign up for the free plan.
Quick checklist
- Create one jsPDF instance.
- Put the first canvas on the constructor-created page.
- Call
addPage()before every later canvas. - Use one scale factor to preserve each canvas’s aspect ratio.
- Keep placement values in the configured document unit.
- Choose page format and orientation explicitly, including for added pages.
- Wait for asynchronous drawing to finish before exporting.
- Call
save()only after the final image has been added.
Frequently Asked Questions
Can I add canvases with different dimensions to the same PDF?
Yes. Calculate a separate scale and position for each canvas against the active page’s available area.
Does jsPDF automatically create a new page when an image is too tall?
No. You must choose whether to scale, crop, or split the drawing and then call addPage() yourself.
Should I use PNG or JPEG for canvas pages?
PNG is generally the safer choice for transparency and crisp graphics; JPEG may be smaller for photographic content but does not preserve transparency.
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.




