Guide

Images

Add PNG and JPEG images with pdf-image from a data URL, a URL, a Blob, an ArrayBuffer or a Uint8Array, and control their size with width, height and object-fit.

pdf-image draws a PNG or JPEG image. Its one input, src, is required.

ts
@Component({
  selector: 'app-badge-document',
  imports: [PDF_ELEMENTS],
  template: `
    <pdf-document>
      <pdf-page size="A5" style="padding: 24">
        <pdf-view style="flex-direction: row; gap: 12; align-items: center">
          <pdf-image src="/assets/logo.png" style="width: 48" />
          <pdf-text style="font-size: 16">Visitor badge</pdf-text>
        </pdf-view>
        <pdf-image
          [src]="photo()"
          style="width: 120; height: 160; object-fit: cover; margin-top: 12; border: 1 solid #cccccc"
        />
      </pdf-page>
    </pdf-document>
  `,
})
export class BadgeDocument {
  readonly photo = input.required<Blob>();
}

Sources

src is a string, a Blob, an ArrayBuffer or a Uint8Array.

Source How ngpdf reads it
a string starting with data: decoded in place, base64 or percent-encoded
any other string downloaded with the browser's fetch
a Blob (or a File) read with blob.arrayBuffer()
an ArrayBuffer used as it is
a Uint8Array, such as a Node Buffer its bytes, as it is (a view into a larger buffer reads only its own bytes)

The format is detected from the bytes, not from the URL, the file name or the MIME type. PNG and JPEG are supported. GIF, WebP and other formats fail with image is neither PNG nor JPEG, and so does SVG: draw an SVG with pdf-svg instead, which keeps it as vector shapes. To use the other formats, draw them on a <canvas> and pass canvas.toBlob(…, 'image/png'):

ts
export function canvasToPng(canvas: HTMLCanvasElement): Promise<Blob> {
  return new Promise((resolve, reject) => {
    canvas.toBlob((blob) => (blob ? resolve(blob) : reject(new Error('Could not encode the chart'))), 'image/png');
  });
}

Other typed arrays, such as Uint16Array, are not accepted.

The data: prefix and its ;base64 marker are matched in any case, so DATA:image/png;BASE64,… is decoded in place too.

Fetching URLs

  • ngpdf calls fetch(src, { credentials: 'same-origin' }). A relative URL such as /assets/logo.png resolves against your page, as any fetch does.
  • The request runs under your page's CORS rules and Content-Security-Policy. An image on another origin needs CORS headers that allow your origin; cookies are sent only to your own origin.
  • A response that is not OK fails, for example with HTTP 404.
  • There is no timeout, and no size limit unless you set maxImageBytes (below).
  • All images of a document load in parallel before layout. The same string src used several times in one render is fetched once.
  • On the server, renderToBuffer reads an absolute URL only through your fetchImage, and refuses a relative one. See Images and fonts on the server.

A size cap

By default a fetched image is downloaded in full, however large. If image URLs in your documents come from users or another service, set maxImageBytes, a render option next to inputs:

ts
await this.pdf.download(InvoiceDocument, {
  inputs: { customer, lines },
  fileName: 'invoice.pdf',
  maxImageBytes: 10_000_000, // 10 MB
});
  • It caps images fetched from a URL only. Data URLs, Blobs, ArrayBuffers and Uint8Arrays are already in memory and are not counted, and neither are emoji images or fonts.
  • A response whose Content-Length is over the cap is refused before its body is read. Otherwise ngpdf counts the bytes as they arrive and stops the download as soon as they pass the cap. An image of exactly maxImageBytes bytes loads.
  • Past the cap the render rejects with ngpdf: could not load image "<source>": larger than N bytes, where N is the cap.
  • It must be a positive whole number. Any other value rejects the render with ngpdf: invalid maxImageBytes "<value>" before any image loads.
  • Every way to render takes it: PdfRenderer.toBlob and .download, renderToBlob, downloadPdf, pdfResource, renderToBuffer, the pdfMaxImageBytes input of PdfDownload and the maxImageBytes input of pdf-viewer. See Rendering API.
  • On the server, ngpdf checks the bytes your fetchImage returns, but it cannot stop your function's download. Put a size limit in fetchImage itself as well.

Errors

The first image that fails rejects the whole render with:

ngpdf: could not load image "<source>": <reason>

<source> is the URL without its query string and fragment (they often carry a token), or data URL, Blob, ArrayBuffer or Uint8Array. <reason> is the cause, such as HTTP 404, larger than N bytes, the browser's network error, ngpdf: image is neither PNG nor JPEG, or the image data is corrupt or cut off for a PNG whose pixel data is broken or truncated; where it repeats the URL, the URL is shortened the same way. On failure no PDF is downloaded, though part of the image may have been fetched before the error, and the document component is destroyed.

Size

The image keeps its aspect ratio unless you give it both dimensions.

You set Result
nothing natural size, 1 image pixel = 1pt (72 / dpi points with a dpi on the page), capped to the width available
width only the height follows the aspect ratio
height only the width follows the aspect ratio
width and height the box you set; object-fit places the image in it

A JPEG with an EXIF orientation, as phone photos usually have, is drawn turned the way browsers show it, and its size and aspect ratio are those of the turned picture: a photo stored 4000x3000 with a quarter-turn orientation (5 to 8) is 3000 wide and 4000 high. The orientation is read from the first Exif APP1 segment before the image data, which is where cameras write it, so an XMP segment or a comment in front of it does not hide it. Its value is read as a 16-bit number, because that is how pdfkit reads it; a value outside 1 to 8 is ignored.

A 2x image (for example a canvas captured at twice the screen size) therefore comes out twice as large as on screen. Set a width to scale it.

An image with no size set is not stretched by its parent's default align-items: stretch. Set align-self: stretch to make it take the full width, with its height following.

object-fit

When the box and the image have different proportions:

  • contain (the default) scales the image to fit inside the box and centers it.
  • cover scales it to fill the box, centers it, and clips what overflows.

The image is drawn inside the content box, so padding and borders on a pdf-image frame it. opacity applies to the image.

Things to avoid

  • Do not put elements inside pdf-image. The render rejects with ngpdf: pdf-image cannot have children, naming the first one, before any image is fetched. Text inside it is ignored.
  • Do not rely on src changing after the render starts. The component is rendered once.