npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

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.

License

MIT