pdfmkr
v0.5.4
Published
Generate PDF documents from JavaScript objects
Downloads
97
Readme
PDF Maker
PDF Maker is a library for generating PDF documents in JavaScript.
- Easy to use: contents are defined in plain objects.
- Works anywhere: in the browser, in Node.js, Deno, and Bun.
- TypeScript support: types are included in the npm package.
This project is inspired by pdfmake and builds on pdf-lib and fontkit. It would not exist without the great work and the profound knowledge contributed by the authors of those projects.
Usage
The makePdf()
function creates PDF data from a given document
definition. This definition is a plain object.
Content
The most important attribute in the definition is named content
. This
attribute accepts a list of blocks. There are different types of
blocks, such as text blocks, image blocks, column and row layout blocks.
Basic Example
const fontData = await readFile('Roboto-Regular.ttf');
const fontDataItalic = await readFile('Roboto-Italic.ttf');
const pdfData = await makePdf({
// Fonts must be registered (see below)
fonts: {
Roboto: [{ data: fontData }, { data: fontDataItalic, italic: true }],
},
// Content as an array of blocks
content: [
// Blocks can contain text and text attributes
{ text: 'Lorem ipsum', italic: true, textAlign: 'center', fontSize: 24 },
// Text can also be an array of text ranges with different attributes
{
text: [
'dolor sit amet, consectetur adipiscing elit ',
{ text: 'sed do eiusmod', italic: true },
' tempor, incididunt ut labore et dolore magna aliqua.',
],
},
],
});
await writeFile(`hello.pdf`, pdfData);
There are more examples in the examples/ folder.
Fonts
All fonts are embedded in the PDF and must be registered with the
fonts
attribute. Font data is accepted in .ttf
or .otf
format, as
ArrayBuffer or Uint8Array. Each font family can contain different
variants which are selected based on the attributes bold
and italic
.
The font family that is registered first becomes the default.
const documentDefinition = {
fonts: {
'DejaVu-Sans': [
// Different font versions for fontFamily "DejaVu-Sans"
// TTF / OTF font data as ArrayBuffer or Uin8Array
{ data: fontDataDejaVuSansNormal },
{ data: fontDataDejaVuSansBold, bold: true },
{ data: fontDataDejaVuSansItalic, italic: true },
{ data: fontDataDejaVuSansBoldItalic, bold: true, italic: true },
],
Roboto: [
// Different font versions for fontFamily "Roboto"
{ data: fontDataRobotoNormal },
{ data: fontDataRobotoMedium, bold: true },
],
},
content: [
{ text: 'lorem ipsum', fontFamily: 'Roboto', bold: true }, // will use Roboto Medium
{ text: 'dolor sit amet' }, // will use DejaVu-Sans (the font registered first), normal
],
};
Images
JPG and PNG images are supported. When the same image is used more than
once, the image data is only included once in the PDF. The size of an
image can be confined using the width
and height
attributes.
const documentDefinition = {
images: {
'logo': { data: imageData }
…
},
content: [
// An image block
{ image: 'images/logo.png', width: 200, height: 100 },
…
]
};
Columns
To arrange blocks horizontally, they can be included in a block with a
columns
attribute. When columns have a width
attribute, it is
respected. The remaining space id distributed evenly across all columns.
{
columns: [
{ text: 'Column 1', width: 100 }, // 100 pt wide
{ text: 'Column 2' }, // gets half of the remaining width
{ text: 'Column 3' }, // gets half of the remaining width
],
}
Rows
A row layout can be used to group multiple rows into a single block, e.g. to apply common attributes or to enclose rows in a surrounding columns layout.
{
rows: [
{ text: 'Row 1' },
{ text: 'Row 2' },
{ text: 'Row 3' },
],
textAlign: 'right',
}
Graphics
Each block can have a graphics
attribute that accepts a list of shapes
to draw into that block or a function that returns a list of shapes. The
function will be called with the block's width and height. This can be
used to draw shapes that depend on the block's size.
Shapes can be lines, rectangles, circles, or SVG paths. In the following example, a graphics attribute is used to draw a yellow background behind the text and a blue border at the left edge.
{
text: 'Lorem ipsum',
graphics: ({ width, height }) => [
{ type: 'rect', x: 0, y: 0, width, height, fillColor: 'yellow' },
{ type: 'line', x1: 0, y1: 0, x2: 0, y2: height, lineColor: 'blue', lineWidth: 2 },
],
padding: { left: 5 },
}
Also see the graphics example.
Margin and padding
The margin
attribute can be used to add space around blocks. It
accepts either a single value (applies to all four edges) an object with
any of the attributes top
, right
, bottom
, left
, x
, and y
.
The attributes x
and y
can be used as shorthands to set both left
and right
or top
and bottom
at the same time. Values can be given
as numbers (in pt) or as strings with a unit. If a string is given, it
must contain one of the units pt
, in
, mm
, or cm
;
{
margin: { x: 5, top: 10 },
content: [
{ text: 'Lorem ipsum' },
{ text: 'dolor sit amet' },
],
}
The top
and bottom
margins of adjacent blocks
are collapsed into a single margin whose size is the maximum of the two
margins. Column margins don't collapse.
The padding
attribute can be used to add space between the content and
the edges of blocks.
Page layout
The top-level pageSize
attribute can be used to set the page size.
Various standard sizes are supported, such as A4
, Letter
, and
Legal
. The default is A4. A custom page size can be specified as an
object with the attributes width
and height
. Values can be given as
numbers (in pt) or as strings with a unit.
{
pageSize: { width: '20cm', height: '20cm' }
}
The pageOrientation
attribute can be used to set the page orientation.
The value can be either portrait
or landscape
. The default is
portrait.
{
pageSize: 'A5',
pageOrientation: 'landscape',
content: [
{ text: 'Lorem ipsum' },
{ text: 'dolor sit amet' },
],
}
Headers and footers
Headers and footers that repeat on each page can be defined using the
optional header
and footer
attributes. Both accept either a single
block or a function that returns a block. The function will be called
with the page number and the total number of pages. The page number
starts at 1.
{
footer: ({ pageNumber, pageCount }) => ({
text: `Page ${pageNumber} of ${pageCount}`,
textAlign: 'right',
margin: { x: '20mm', bottom: '1cm' },
}),
content: [
{ text: 'Lorem ipsum' },
{ text: 'dolor sit amet' },
],
}
Page breaks
Page breaks are included automatically. When a block does not fit on the
current page, a new page is added to the document. To insert a page
break before or after a block, set the breakBefore
or breakAfter
attribute of a block to always
. To prevent a page break, set this
attribute to avoid
.
Page breaks are also automatically inserted between the lines of a text
block. To prevent a page break within a text block, set the
breakInside
attribute to avoid
.
{
content: [
{ text: 'Lorem ipsum' },
{ text: 'This text will go on a new page', breakBefore: 'always' },
],
}
Documentation
While there is no generated documentation yet, you can refer to the content.ts for a specification of all supported attributes in a document definition.
Also check out the examples in the examples/ folder.