EmbedPDF

Stamps

A stamp puts a picture on a page: a logo, a signature, an “Approved” mark. You give the engine the picture as PNG, JPEG or PDF bytes, and the box to put it in:

const image = await (await fetch('/approved.png')).blob();
 
const { annotation } = await page.annotations.create(
  { subtype: 'stamp', box: { x: 72, y: 102, width: 150, height: 50 } },
  { resources: { appearance: image } },
);

The picture goes in the options, as resources.appearance. A Blob (such as a file the user picked) and a Uint8Array both work.

FieldWhat it isDefault
boxThe box the stamp fills, { x, y, width, height } in points, before any turnrequired
fitHow the picture fills the box: 'contain', 'cover' or 'fill''contain'
opacityFrom 0 (invisible) to 1 (solid), over the whole picture1
nameA label for the stamp, such as 'Approved'none
rotationHow far the stamp is turned, in degrees clockwise; see Turn a stampnone

A read also has rect, where the stamp sits on the page: its box, or the upright box around it when it’s turned. The engine works it out.

fit works like CSS object-fit: 'contain' shows the whole picture at its own proportions, 'cover' fills the box at its own proportions and crops what sticks out, 'fill' stretches the picture to the box. The stamp remembers its fit, so a later resize fills the new box the same way.

Images and PDF drawings#

BytesWhat you get
PNGThe image, with its transparency.
JPEGThe image, stored as it is, without re-encoding.
PDFThe page as a vector drawing, sharp at any zoom. One page only.

The engine tells which it is from the bytes themselves, never from a file name or a MIME type. Anything else, a PDF with more than one page included, is refused with InvalidArg before anything is written. So is a stamp without an appearance.

A page of a PDF#

To use a page of an open document as a stamp, extract it: pages.extract() returns a one-page PDF.

const drawing = await doc.pages.extract([pageRef]);
 
await page.annotations.create({ subtype: 'stamp', box }, { resources: { appearance: drawing } });

Standard stamps#

The engine has no stamps of its own. name is only a label stored with the stamp; the picture is always the appearance you give it.

The standard set (Approved, Draft, Confidential, Sign Here and more) ships as vector drawings in @embedpdf/default-stamps: one PDF per language, one page per stamp. Each page is registered under a name identifier=label, such as Approved=Goedgekeurd in the Dutch file:

import { loadDefaultLibrary } from '@embedpdf/default-stamps/library';
 
const library = await engine.open({ kind: 'bytes', bytes: await loadDefaultLibrary('en') });
const { namedPages } = await library.pages.list();
const approved = namedPages.find((entry) => entry.name.startsWith('Approved='));
 
if (approved?.target.kind === 'page') {
  const drawing = await library.pages.extract([approved.target.page]);
  await page.annotations.create(
    { subtype: 'stamp', box, name: 'Approved', subject: 'Approved' },
    { resources: { appearance: drawing } },
  );
}
await library.close();

The identifier becomes the stamp’s name and the label its subject, the way Acrobat writes stamps from its own libraries. In a viewer, the stamp plugin does this for you.

Turn a stamp#

A stamp turns like a rectangle: give its own box as box and the angle as rotation, in degrees clockwise. See Turned shapes.

const { annotation } = await page.annotations.create(
  {
    subtype: 'stamp',
    box: { x: 300, y: 442, width: 100, height: 50 }, // 100 × 50
    rotation: 90,
  },
  { resources: { appearance: image } },
);
 
annotation.rect; // { x: 325, y: 417, width: 50, height: 100 }: the same box, turned

A stamp turned in Acrobat reads the same way: its rotation, and its own box as box. A stamp you turn opens in Acrobat as a turned stamp.

Resize and refit#

A new box or a new fit places the same picture again. Nothing is uploaded or re-encoded:

await page.annotations.update(annotation.ref, {
  box: { x: 72, y: 102, width: 300, height: 90 },
});
await page.annotations.update(annotation.ref, { fit: 'cover' });

The stamp keeps its whole picture, whatever box it’s in, so a stamp set from 'cover' back to 'contain' shows all of it again.

To change the picture itself, pass a new resources.appearance:

await page.annotations.update(annotation.ref, {}, { resources: { appearance: otherImage } });

A new opacity replaces the old one, and applies to the picture as a whole: overlapping parts of the artwork don’t show through each other.

Download a stamp’s drawing#

A read never contains the picture. downloadResource() returns it, as a one-page PDF:

const drawing = await page.annotations.downloadResource(annotation.ref, 'appearance');

The drawing is the picture before the stamp’s fit, rotation and opacity. For a stamp made from a PNG or JPEG, it’s the image at its own size, one pixel to a point, whatever box the stamp is in. For a stamp made by another app, it’s the picture as that app drew it.

Copy a stamp#

The read and the drawing together make the same stamp again, on another page or in another document:

const drawing = await page.annotations.downloadResource(stamp.ref, 'appearance');
 
await otherPage.annotations.create(stamp, { resources: { appearance: drawing } });

The copy has the same box, fit, rotation, opacity and name; the engine records the user who makes it as its author.

To copy on the same page, clear the unique name: { ...stamp, nm: null } (see Refs & identity). A copy with a name that’s taken on its page fails with InvalidArg.

To copy many annotations at once, stamps included, use Import & export.

Permissions#

Stamps are annotations: creating, changing and deleting them needs the same permissions as any annotation (see Permissions). Downloading a drawing sends document content out, so it needs doc.download, and so does pages.extract().

Good to know#

Shared drawings#

Stamps with the same picture share one drawing, so a logo placed 100 times is stored once, also after a save, and when you download it and place it again.

Changing one stamp never changes the others. A new picture for one stamp gives that stamp a drawing of its own; the stamps that shared the old one keep it.

The same drawing is the same bytes#

A drawing always downloads as the same bytes: from the local and the cloud engine, and again after a copy. So you can store drawings by their hash and keep one copy for every stamp that uses it.

Stamps from other apps#

A stamp made by Acrobat or another app records no fit and reads fit: null. A resize stretches its picture to the new box, as every PDF app shows it. A stamp from another app keeps its saved opacity through a resize or copy; a new opacity replaces it. The same goes the other way: Acrobat can change the opacity of a stamp made here.

Large images#

An image becomes a drawing at its own size, one pixel to a point, scaled down to fit 14,400 points (Acrobat’s largest page size). The stamp’s box then scales it to where it goes.

The name#

name takes any text that isn’t empty: a standard stamp name such as 'Approved', or the id Acrobat gives a stamp from a custom library. In the PDF it’s the stamp’s /Name.

Was this page helpful?

Your feedback goes directly to the documentation team.