Hardware FixRecommendedDevice not working? Your driver may be the problemCheck updates for common hardware issues.Fix DriversOctober DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsClean PCRecommendedOne scan can reveal what keeps slowing WindowsLook for cleanup and repair opportunities.Run Scan×
Skip to content
Image Processing

How to Center and Fit an Image on a jsPDF Page (Without Distortion)

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

Use one uniform scale factor for both dimensions, choosing the smaller of the width and height ratios. Then add half of the leftover space to the target rectangle’s x and y coordinates. This keeps the entire image visible, preserves its aspect ratio, and centers it on any jsPDF page:

const pageWidth = doc.internal.pageSize.getWidth();
const pageHeight = doc.internal.pageSize.getHeight();

const margin = 10;
const boxX = margin;
const boxY = margin;
const boxWidth = pageWidth - margin * 2;
const boxHeight = pageHeight - margin * 2;

const imageWidth = img.naturalWidth;
const imageHeight = img.naturalHeight;

if (imageWidth <= 0 || imageHeight <= 0) {
  throw new Error("Image has no usable dimensions");
}

const scale = Math.min(boxWidth / imageWidth, boxHeight / imageHeight);
const drawWidth = imageWidth * scale;
const drawHeight = imageHeight * scale;
const x = boxX + (boxWidth - drawWidth) / 2;
const y = boxY + (boxHeight - drawHeight) / 2;

doc.addImage(img, "PNG", x, y, drawWidth, drawHeight);

The fit-and-center calculation

jsPDF does not automatically fit an image to a page. Its addImage API receives the image, format, x coordinate, y coordinate, width, and height. Coordinates start at the page’s left and upper edges, and the geometry uses the document’s configured units.

To fit an image inside a rectangle, call the rectangle the box. The largest distortion-free scale is:

const scale = Math.min(boxWidth / imageWidth, boxHeight / imageHeight);

Using Math.min guarantees that neither scaled dimension exceeds the box. The remaining space is centered with:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
#1 Best Overall
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.
const x = boxX + (boxWidth - drawWidth) / 2;
const y = boxY + (boxHeight - drawHeight) / 2;

If the aspect ratios differ, one direction will have unused space. That is the expected result of fitting rather than stretching.

A complete browser example

Wait for the image to load before reading its intrinsic dimensions. An HTMLImageElement exposes those dimensions through naturalWidth and naturalHeight. The following example creates an A4 portrait PDF, leaves a 10 mm margin, and centers a PNG in the remaining area.

import { jsPDF } from "jspdf";

function loadImage(url) {
  return new Promise((resolve, reject) => {
    const image = new Image();
    image.onload = () => resolve(image);
    image.onerror = () => reject(new Error(`Could not load image: ${url}`));
    image.src = url;
  });
}

async function makePdf() {
  const img = await loadImage("/images/photo.png");
  const doc = new jsPDF({ orientation: "portrait", unit: "mm", format: "a4" });

  const pageWidth = doc.internal.pageSize.getWidth();
  const pageHeight = doc.internal.pageSize.getHeight();
  const margins = { left: 10, right: 10, top: 10, bottom: 10 };

  const boxX = margins.left;
  const boxY = margins.top;
  const boxWidth = pageWidth - margins.left - margins.right;
  const boxHeight = pageHeight - margins.top - margins.bottom;

  if (!img.naturalWidth || !img.naturalHeight || boxWidth <= 0 || boxHeight <= 0) {
    throw new Error("Image or target box has invalid dimensions");
  }

  const scale = Math.min(
    boxWidth / img.naturalWidth,
    boxHeight / img.naturalHeight
  );
  const drawWidth = img.naturalWidth * scale;
  const drawHeight = img.naturalHeight * scale;
  const x = boxX + (boxWidth - drawWidth) / 2;
  const y = boxY + (boxHeight - drawHeight) / 2;

  doc.addImage(img, "PNG", x, y, drawWidth, drawHeight);
  doc.save("centered-image.pdf");
}

makePdf().catch(console.error);

The format string must match the actual data. Use "JPEG" for a JPEG, "WEBP" for a WebP where supported by your jsPDF build, and "PNG" for a PNG. The API also accepts data URLs, canvas elements, Uint8Array data, and RGBA data; malformed image data can raise an error. See the image-source documentation for accepted input forms.

Choose the page and unit system first

Set orientation, units, and format when constructing the document, then obtain the resulting dimensions from the document itself. The official jsPDF README uses A4 portrait with millimeters by default, but your code should not assume that every document has that size.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
const doc = new jsPDF({
  orientation: "landscape",
  unit: "in",
  format: "letter"
});

const width = doc.internal.pageSize.getWidth();
const height = doc.internal.pageSize.getHeight();

Supported configuration units include pt, mm, cm, in, and px. If you choose pixels, the constructor documentation says to use the px_scaling hotfix for correct pixel scaling. Keep source dimensions and output geometry conceptually separate: intrinsic image pixels establish the ratio, while x, y, width, and height are expressed in the PDF’s units. The constructor and page-configuration reference lists predefined and custom page formats.

Margins as a reusable box

Do not subtract a single “margin” unless all four margins are equal. Define each edge explicitly:

const boxX = left;
const boxY = top;
const boxWidth = pageWidth - left - right;
const boxHeight = pageHeight - top - bottom;

This same rectangle can be used for a cover image, a chart, or a scanned document. Validate that its width and height remain positive before calculating ratios.

Fit versus fill: two different outcomes

Fit (show the complete image)

The Math.min formula is a “contain” operation. Every pixel remains visible, proportions remain correct, and letterboxing may appear on the sides or top and bottom. Use it for photos, screenshots, diagrams, and documents where cropping content is unacceptable.

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

Fill (cover every part of the box)

Edge-to-edge coverage requires a different operation. Use the larger ratio, then crop or clip the overflow:

const scale = Math.max(boxWidth / imageWidth, boxHeight / imageHeight);
const drawWidth = imageWidth * scale;
const drawHeight = imageHeight * scale;
const x = boxX + (boxWidth - drawWidth) / 2;
const y = boxY + (boxHeight - drawHeight) / 2;

This computes a centered, oversized image; the portions outside the box must be clipped or otherwise excluded by your layout. Simply passing the box dimensions to addImage would fill the rectangle by distorting the image, which is usually undesirable. The reviewed addImage reference documents explicit geometry and optional rotation, not an automatic fit-or-crop mode.

Fit and fill at a glance

Goal Scale Result Trade-off
Fit Math.min(width ratio, height ratio) Complete image inside the box Whitespace on one axis when ratios differ
Fill Math.max(width ratio, height ratio) Box is fully covered Requires cropping or clipping

Reusable helper functions

Putting the geometry in a helper prevents subtle inconsistencies across pages.

function fitImageInBox({
  imageWidth,
  imageHeight,
  boxX,
  boxY,
  boxWidth,
  boxHeight
}) {
  if (![imageWidth, imageHeight, boxWidth, boxHeight].every(Number.isFinite) ||
      imageWidth <= 0 || imageHeight <= 0 || boxWidth <= 0 || boxHeight <= 0) {
    throw new RangeError("All image and box dimensions must be positive numbers");
  }

  const scale = Math.min(boxWidth / imageWidth, boxHeight / imageHeight);
  const width = imageWidth * scale;
  const height = imageHeight * scale;

  return {
    x: boxX + (boxWidth - width) / 2,
    y: boxY + (boxHeight - height) / 2,
    width,
    height,
    scale
  };
}

const placement = fitImageInBox({
  imageWidth: img.naturalWidth,
  imageHeight: img.naturalHeight,
  boxX: 10,
  boxY: 10,
  boxWidth: pageWidth - 20,
  boxHeight: pageHeight - 20
});

doc.addImage(img, "PNG", placement.x, placement.y,
  placement.width, placement.height);

The returned scale is useful when you need to place a caption immediately below the image or calculate the next content y-coordinate.

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

Loading images safely

  • Wait for decoding: resolve the image’s onload event; for already-loaded images, await img.decode() can make decoding explicit where supported.
  • Check cross-origin access: a remote image may need appropriate CORS headers, especially when drawing it to a canvas before passing the canvas to jsPDF.
  • Use the right representation: convert files to a data URL or typed byte array when your runtime cannot pass a browser image element directly.
  • Check dimensions: never divide by zero or use an image whose intrinsic dimensions are unavailable.

Browser security, network availability, and image decoding are separate from jsPDF placement. A correct formula cannot repair an image that failed to load.

Multiple pages and large images

For a document with different page formats, calculate page dimensions after each page is created or changed. Do not reuse A4 dimensions for a letter, legal, custom, or landscape page. For repeated images, cache the decoded image or encoded data and reuse an alias where appropriate; this avoids repeating conversion work. Very large raster images can increase memory use and PDF size, so resize images that contain far more detail than the output page needs. Choose compression deliberately through the optional arguments supported by addImage, and inspect the generated PDF at its intended print or screen resolution.

Troubleshooting common failures

The image is stretched

Cause: width and height were chosen independently. Fix: calculate one scale with Math.min (fit) or Math.max (fill), then derive both dimensions from the original ratio.

Rank #4
DeskFX Free Audio Effects & Audio Enhancer Software [PC Download]
  • Transform audio playing via your speakers and headphones
  • Improve sound quality by adjusting it with effects
  • Take control over the sound playing through audio hardware

The image is not centered

Cause: the image was placed at the box origin, or the page dimensions were hard-coded. Fix: calculate x and y from the unused space and obtain dimensions with doc.internal.pageSize.getWidth() and getHeight().

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

Everything is the wrong size

Cause: mixed units, such as treating pixel dimensions as millimeters. Fix: configure the document explicitly and pass all target geometry in that unit system. For pixel units, follow the constructor documentation’s px_scaling hotfix guidance.

There is unexpected whitespace

Cause: the image and box have different aspect ratios; this is normal for fit mode. If the design demands full coverage, use fill mode and crop or clip the overflow.

addImage throws an invalid-image error

Cause: incomplete, malformed, unsupported, or not-yet-decoded data. Fix: await loading, verify the format argument, inspect the data URL or byte array, and confirm that the image source is available before calling addImage. The API reference notes that invalid image data can throw.

The image loads locally but not from a URL

Cause: the browser blocked a cross-origin request or canvas read. Fix: serve the image with suitable CORS headers, host it on the same origin, or fetch it through a server that is authorized to access it.

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.
Best Value
MixPad Multitrack Recording Software for Sound Mixing and Music Production Free [Mac Download]
  • Mix an audio, music and voice tracks
  • Record single or multiple tracks simultaneously
  • Intuitive tools to split, trim, join, and many other editing features
  • Loaded with audio effects including EQ, compression, reverb, and more.
  • Load an audio file and export to all popular audio formats from studio quality wav to high compression formats
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

If your input is a web page or web image and you do not want to maintain browser automation, ScreenshotNeo returns a screenshot from one GET request. It accepts consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed as clean shots, and the response identifies the page verdict and billing result in X-Page-Verdict and X-Billed headers.

Here is the cURL request; the ScreenshotNeo documentation lists all options and output formats:

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

The same request in Python:

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(`Screenshot failed: ${res.status}`);
const buffer = Buffer.from(await res.arrayBuffer());
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', buffer));

ScreenshotNeo also provides an MCP server with take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. Its free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 screenshots. Create a free ScreenshotNeo account to try it.

Reference links

Frequently Asked Questions

Can I center an image without knowing the page size in advance?

Yes. Read the created document’s width and height with doc.internal.pageSize.getWidth() and getHeight(), then calculate the placement from those values.

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

Why does fitting leave a blank band?

The image and target rectangle have different aspect ratios. Preserving the complete image necessarily leaves unused space on one axis; use a crop-based fill layout when that is unacceptable.

Does addImage automatically preserve aspect ratio?

No. You supply both output dimensions, so your code must derive them from a single uniform scale.

Quick Recap

Bestseller No. 1
MixPad Free Multitrack Recording Studio and Music Mixing Software [Download]
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.
Bestseller No. 4
DeskFX Free Audio Effects & Audio Enhancer Software [PC Download]
DeskFX Free Audio Effects & Audio Enhancer Software [PC Download]
Transform audio playing via your speakers and headphones; Improve sound quality by adjusting it with effects
Bestseller No. 5
MixPad Multitrack Recording Software for Sound Mixing and Music Production Free [Mac Download]
MixPad Multitrack Recording Software for Sound Mixing and Music Production Free [Mac Download]
Mix an audio, music and voice tracks; Record single or multiple tracks simultaneously; Intuitive tools to split, trim, join, and many other editing features

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
Outdated Drivers Are Slowing You DownFree scan - exact matches
Windows Errors? Fix Them Before They SpreadFree repair scan

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.