{"id":20198509,"url":"https://github.com/eclipsesource/pdf-maker","last_synced_at":"2025-04-10T10:53:31.873Z","repository":{"id":39674102,"uuid":"468782825","full_name":"eclipsesource/pdf-maker","owner":"eclipsesource","description":"Generate PDF documents in JavaScript","archived":false,"fork":false,"pushed_at":"2025-01-19T14:39:52.000Z","size":1325,"stargazers_count":20,"open_issues_count":1,"forks_count":2,"subscribers_count":6,"default_branch":"main","last_synced_at":"2025-04-03T20:38:30.112Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/eclipsesource.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-03-11T14:30:45.000Z","updated_at":"2025-04-02T14:11:13.000Z","dependencies_parsed_at":"2023-12-10T18:24:49.482Z","dependency_job_id":"fb9d78f6-2b08-40ae-9dc2-1c30300bf985","html_url":"https://github.com/eclipsesource/pdf-maker","commit_stats":{"total_commits":192,"total_committers":2,"mean_commits":96.0,"dds":0.00520833333333337,"last_synced_commit":"46f6028894a3dce2fe19bcb366caabbaf3d334cf"},"previous_names":[],"tags_count":14,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eclipsesource%2Fpdf-maker","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eclipsesource%2Fpdf-maker/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eclipsesource%2Fpdf-maker/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eclipsesource%2Fpdf-maker/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/eclipsesource","download_url":"https://codeload.github.com/eclipsesource/pdf-maker/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248204687,"owners_count":21064885,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-14T04:31:55.724Z","updated_at":"2025-04-10T10:53:31.864Z","avatar_url":"https://github.com/eclipsesource.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# PDF Maker\n\nPDF Maker is a library for generating PDF documents in JavaScript.\n\n## Usage\n\n```sh\nnpm install pdfmkr\n```\n\nA `PdfMaker` instance creates PDF data from a given _document\ndefinition_.\n\n```ts\n// Define the contents of the document\nconst doc = {\n  content: [text('Hello World!')],\n};\n\n// create an instance of PdfMaker and register fonts\nconst pdfMaker = new PdfMaker();\npdfMaker.registerFont(await readFile('path/to/Roboto-Regular.ttf'));\n\n// create a PDF from the document\nconst pdfData = await pdfMaker.makePdf(doc);\nawait writeFile(`hello.pdf`, pdfData);\n```\n\n## Fonts\n\nFonts need to be registered before they can be used in a document. The\n`registerFont()` method accepts font data in `TTF` or `OTF` format.\nFonts will be selected based on their font family, font style, and font\nweight. This information is extracted from the font by `registerFont()`,\nit but can also be provided as a second parameter if needed.\n\n```ts\npdfMaker.registerFont(await readFile('path/to/Roboto-Regular.ttf'));\npdfMaker.registerFont(await readFile('path/to/Roboto-Italic.ttf'));\n...\n\nconst doc = {\n  // Define the default font\n  defaultStyle: { fontFamily: 'Roboto', fontSize: 12 },\n  content: [\n    // This block will use the Roboto-Regular font\n    text('Hello World!')\n    // This block will use the Roboto-Italic font\n    text('Hello World!', { fontStyle: 'italic' })\n  ],\n};\n```\n\nIf no font family is specified in the document, the first\nmatching font will be used.\n\n## Content\n\nThe content of a document is composed of _blocks_. There are different\ntypes of blocks, such as text blocks, image blocks, column and row\nlayout blocks. The `content` property of the document definition accepts\na list of blocks.\n\n### Text\n\nText blocks can be created using the `text()` function. Besides the\ntext to display, this function accepts [block](#block-properties) and\n[text](#text-properties) properties.\n\n```ts\nconst block = text('Lorem ipsum', { fontStyle: 'italic', fontSize: 12 });\n```\n\n#### Text spans\n\nThe text property can be a single string or an array of strings or text\nspans. A text span is an inline stretch of text with a specific style,\nsuch as an emphasized word or a link. Text spans can be created using\nthe `span()` function. Text spans support [text\nproperties](#text-properties).\n\n```ts\nconst block = text([\n  'This is some text with an ',\n  span('emphasized text span', { fontStyle: 'italic' }),\n  ' in the middle.',\n]);\n```\n\nThis block will result in the following text:\n\n\u003e This is some text with an _emphasized text span_ in the middle.\n\nText spans can also be nested:\n\n```ts\nspan(['This is ', span('super', { fontWeight: 'bold' }), ' important'], { fontStyle: 'italic' });\n```\n\n\u003e _This is **super** important._\n\nFor convenience, the functions `bold()` and `italic()` can be used to\ncreate bold and italic text spans:\n\n```ts\nitalic(['This is ', bold('super'), ' important']);\n```\n\n#### Line breaks\n\nLine breaks are inserted automatically at word boundaries. Explicit\nline breaks can be inserted as line feed characters (`\\n`):\n\n```ts\ntext('Explicit line\\nbreaks are\\nsupported.');\n```\n\n#### Subscripts and superscripts\n\nSubscripts and superscripts can be created using the `span()` function\nwith the `rise` property. This property does not affect the line height.\n\n```ts\ntext(['H', span('₂', { rise: -3 }), 'O']);\ntext(['10', span('⁻³', { rise: 3 }), '.']);\n```\n\n#### Links\n\nText spans can also be used to create links to external URLs or to\n[anchors](#anchors) in the document.\n\n```ts\nspan('example.com', { link: 'https://example.com', color: 'blue' });\n```\n\n#### Text alignment\n\nText alignment can be set using the `textAlign` property. The value can\nbe `left`, `center`, or `right`. The default is `left`.\n\n```ts\ntext('Centered text', { textAlign: 'center' });\n```\n\nThe text alignment can be defined for an entire block and is propagated\nto all children in the block. Children can override the alignment.\n\n```ts\nrows(\n  [\n    text(\"I'm centered.\"),\n    text(\"I'm centered.\"),\n    text(\"I'm not!\", { textAlign: 'left' }),\n  ],\n  { textAlign: 'center' },\n),\n```\n\n#### Text properties\n\nText properties can be set for an entire text block or for individual\ntext spans. The following text properties are supported:\n\n- `fontFamily`: The font family to use.\n- `fontStyle`: The font style. Can be `normal`, `italic`, or `bold`.\n- `fontWeight`: The font weight. Can be a number between `100` and\n  `900`. The literal values `normal` and `bold` are also supported.\n- `fontSize`: The font size in pt.\n- `lineHeight`: The line height as a multiple of the font size (default:\n  `1.2`).\n- `color`: The text [color](#colors).\n- `link`: Renders the text as a link to the given target. Can be a URL\n  or an [anchor](#anchors) reference.\n- `rise`: Vertical offset in pt for baseline shifts. Positive values\n  shift the baseline up, negative values shift it down.\n- `letterSpacing`: The character spacing in pt. Positive values increase\n  the space between characters, negative values decrease it.\n\n### Images\n\nImages can be included in image blocks, which can be created using the\n`image()` function. This function accepts the image URL and an optional\nobject containing [image](#image-properties) and\n[block](#block-properties) properties. Images are supported in JPG and\nPNG format. URLs can be `data:`, `http:`, `https:`, or `file:` URLs. The\nsize of an image can be confined using the `width` and `height`\nproperties.\n\n```ts\nconst block = image('file:/images/logo.png', { width: 200, height: 100 });\n```\n\nWhen the same image URL is used multiple times in the document, the\nimage data is embedded in the PDF only once.\n\n#### Image properties\n\n- `imageAlign`: Aligns the image within the block. The alignment of the\n  image within the block. Supported values are `left`, `center`, and\n  `right`. The default is `center`.\n\n### Graphics\n\nEach block can have a `graphics` property that accepts a list of\n_shapes_ to draw into that block. Alternatively, this property accepts a\nfunction that returns a list of shapes. The function will be called with\nthe block's width and height. This can be used to draw shapes that\ndepend on the block's size. The coordinate system for graphics shapes\nstarts at the top left corner of the block.\n\nShapes can be lines, rectangles, circles, or SVG paths. They can be\ncreated using the `line()`, `rect()`, `circle()`, and `path()`\nfunctions.\n\nIn the following example, the `graphics` property is used to draw a\nyellow background behind the text and a blue border at the left edge.\n\n```ts\ntext('Lorem ipsum', {\n  graphics: ({ width, height }) =\u003e [\n    rect(0, 0, width, height, { fillColor: 'yellow' }),\n    line(0, 0, 0, height, { lineColor: 'blue', lineWidth: 2 }),\n  ],\n  padding: { left: 5 },\n});\n```\n\n#### Lines\n\nLines are defined by the coordinates of the start and end points of the\nline. They support [stroke](#stroke-properties) and\n[transform](#transform-properties) properties.\n\n```ts\nline(10, 20, 90, 20, { lineColor: 'blue', lineWidth: 2 });\n```\n\n#### Rectangles\n\nRectangles are defined by the coordinates of the top-left corner, the\nwidth, and height of the rectangle. They support\n[stroke](#stroke-properties), [fill](#fill-properties), and\n[transform](#transform-properties) properties.\n\n```ts\nrect(10, 20, 50, 25, { lineColor: '#4488cc', lineJoin: 'round' });\n```\n\n#### Circles\n\nCircles are defined by the coordinates of the center and the radius of\nthe circle. They support [stroke](#stroke-properties),\n[fill](#fill-properties), and [transform](#transform-properties)\nproperties.\n\n```ts\ncircle(cx, cy, 20, { fillColor: 'red' });\n```\n\n#### Paths\n\nPaths allow to create arbitrary shapes using a series of drawing\ncommands. These commands are accepted in the format of an SVG path data\nstring (see\n[MDN](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/d) for\ndetails). Paths support [stroke](#stroke-properties),\n[fill](#fill-properties), and [transform](#transform-properties)\nproperties.\n\n```ts\npath('M45,0 L15,94 L90,34 L0,34 L75,94 Z', {\n  fillColor: '#4488cc',\n  translate: { x: 100 },\n});\n```\n\n#### Stroke properties\n\nStroke properties define the appearance of stroked lines. The following\nstroke properties are supported:\n\n- `lineWidth`: The width of stroked lines in pt.\n- `lineColor`: The [color](#colors) of stroked lines.\n- `lineOpacity`: The opacity of stroked lines as a number between `0`\n  and `1`.\n- `lineCap`: The shape at the end of open paths when they are\n  stroked.\n  - `butt`: indicates that the stroke for each subpath does not extend\n    beyond its two endpoints. On a zero length subpath, the path will\n    not be rendered at all.\n  - `round`: indicates that at the end of each subpath the stroke will\n    be extended by a half circle with a diameter equal to the stroke\n    width. On a zero length subpath, the stroke consists of a full\n    circle centered at the subpath's point.\n  - `square`: indicates that at the end of each subpath the stroke will\n    be extended by a rectangle with a width equal to half the width of\n    the stroke and a height equal to the width of the stroke. On a zero\n    length subpath, the stroke consists of a square with its width equal\n    to the stroke width, centered at the subpath's point.\n- `lineJoin`: The shape to be used at the corners of paths or\n  basic shapes when they are stroked.\n  - `miter`: indicates that the outer edges of the strokes for the two\n    segments should be extended until they meet at an angle, as in a\n    picture frame.\n  - `round`: indicates that the outer edges of the strokes for the two\n    segments should be rounded off by a circular arc with a radius equal\n    to half the line width.\n  - `bevel`: indicates that the two segments should be finished with\n    butt caps and the resulting notch should be filled with a triangle.\n- `lineDash` (`number[]`): The dash pattern to use for drawing paths. Each\n  element defines the length of a dash or a gap, in pt, starting with\n  the first dash. If the array contains an odd number of elements, then\n  the elements are repeated to yield an even number of elements. An\n  empty array stands for no dash pattern, i.e. a continuous line.\n\n#### Fill properties\n\nFill properties define the appearance of the areas enclosed by paths or\nbasic shapes. The following fill properties are supported:\n\n- `fillColor`: The [color](#colors) to use for filling the shape.\n- `fillOpacity`: The opacity to use for filling the shape as number\n  between `0` and `1`.\n\n#### Transform properties\n\nTransform properties can be used to move, resize, rotate, or transform\nshapes in other ways. The following transform properties are supported:\n\n- `translate` (`{ x: number, y: number }`): Moves the shape by `x` and\n  `y` pt.\n- `scale` (`{ x: number, y: number }`): Stretches the shape by `x` and\n  `y` pt.\n- `rotate` (`{ angle: number, cx?: number, cy?: number }`): Rotates the\n  shape by `angle` degrees clockwise about the point `[cx,cy]`. If `cx`\n  and `cy` are omitted, the rotation is about the origin of the\n  coordinate system.\n- `skew` (`{ x: number, y: number }`): Skews the shape by `x` degrees\n  along the x axis and by `y` degrees along the y axis.\n- `matrix` (`number[]`): Applies a custom transformation matrix to the\n  shape. The matrix is given as an array of six values `[a, b, c, d, e,\nf]` that represent the transformation matrix:\n  ```\n  | a c e |\n  | b d f |\n  | 0 0 1 |\n  ```\n\n### Colors\n\nColors can be specified in the format `#rrggbb` where `rr`, `gg`, and\n`bb` are the red, green, and blue components respectively, in\nhexadecimal notation.\n\nIn addition, the named colors `black`, `gray`, `white`, `red`, `blue`,\n`green`, `cyan`, `magenta`, `yellow`, `lightgray`, `darkgray` are\nsupported.\n\n## Layout\n\n### Columns\n\nTo arrange blocks horizontally, they can be included in a _columns_\nblock. The width of each column can be set using the `width` property.\nWhen the width is set to `auto`, the column will shrink to the width of\nits content. The remaining space is distributed evenly across all\ncolumns that don't have a fixed width.\n\nColumn blocks can be created using the `columns()` function, which takes\nan array of blocks and an optional object with\n[block](#block-properties) and [text](#text-properties) properties. Text\nproperties will be inherited by included text blocks.\n\n```ts\nconst block = columns([\n  text('Column 1', { width: 100 }), // 100 pt wide\n  text('Column 2'), // gets half of the remaining width\n  text('Column 3'), // gets half of the remaining width\n]);\n```\n\n### Rows\n\nTo arrange blocks vertically, they can be included in a _rows_ block.\nThis can be useful to group multiple rows into a single block, e.g. to\napply common properties or to enclose rows in a surrounding columns\nlayout.\n\nRow blocks can be created using the `rows()` function, which takes an\narray of blocks and an optional object with\n[block](#block-properties) and [text](#text-properties) properties. Text\nproperties will be inherited by included text blocks.\n\n```ts\nconst block = rows(\n  [text('Row 1'), text('Row 2'), text('Row 3')],\n  { margin: 10, fontSize: 18 }, // fontSize is applied to all rows\n);\n```\n\n### Margin\n\nThe `margin` property can be used to add space around blocks. It\naccepts either a single value (applies to all four edges) an object with\nany of the properties `top`, `right`, `bottom`, `left`, `x`, and `y`.\nThe properties `x` and `y` can be used as shorthands to set both `left`\nand `right`, or `top` and `bottom`, respectively. Values can be given\nas numbers (in pt) or as strings with a unit. If a string is given, it\nmust contain one of the units `pt`, `in`, `mm`, or `cm`;\n\n```ts\ntext('Lorem ipsum', { margin: 5 }); // 5 pt margin on all sides\n```\n\n```ts\ntext('Lorem ipsum', { margin: { y: '5cm' } }); // 5 cm top and bottom margin\n```\n\nThe `top` and `bottom` margins of adjacent blocks\nare collapsed into a single margin whose size is the maximum of the two\nmargins. Column margins don't collapse.\n\n```ts\nrows([\n  text('Lorem ipsum', { margin: { y: 5 } }),\n  // only 5 pt margin between the two blocks\n  text('dolor sit amet', { margin: { y: 5 } }),\n]);\n```\n\n### Padding\n\nThe `padding` property can be used to add space between the content and\nthe edges of blocks. It accepts the same values as the `margin`\nproperty.\n\n```ts\ntext('Lorem ipsum', { padding: { x: '5pt', y: '2pt' });\n```\n\n#### Block properties\n\nThe following properties can be set for all types of blocks:\n\n- `padding`: Space to leave between the content and the edges of the\n  block.\n- `margin`: Space to surround the block.\n- `width`: The width of the block. If this property is set to `auto`,\n  the block will use the width of the widest element in the block.\n- `height`: The height of the block. If this property is not set, the\n  height of the block is defined by its content.\n- `verticalAlign`: Aligns the block vertically within a columns block.\n  Supported values are `top`, `middle`, and `bottom`. By default, blocks\n  are top-aligned.\n- `id`: An optional _unique_ id for the element that can be used as an\n  [anchor](#anchors).\n- `graphics`: A list of [graphic](#graphics) elements to draw in the\n  area covered by the block. A function can be passed to take the final\n  size of the block into account.\n- `breakBefore`: Controls whether a page break may occur before the\n  block.\n  - `auto` (default): Insert a page break when needed.\n  - `always`: Always insert a page break before this block.\n  - `avoid`: Do not insert a page break before this block if it can be\n    avoided.\n- `breakAfter`: Controls whether a page break may occur after the block.\n  - `auto` (default): Insert a page break when needed.\n  - `always`: Always insert a page break after this block.\n  - `avoid`: Do not insert a page break after this block if it can be avoided.\n\n## Page layout\n\n### Page size\n\nThe top-level `pageSize` property can be used to set the page size.\nVarious standard sizes are supported, such as `A4`, `Letter`, and\n`Legal`. The default is A4. A custom page size can be specified as an\nobject with the properties `width` and `height`. Values can be given as\nnumbers (in pt) or as strings with a unit.\n\n```ts\nconst document = {\n  pageSize: { width: '20cm', height: '20cm' }\n  content: [text('Lorem ipsum')],\n};\n```\n\n### Page orientation\n\nThe `pageOrientation` property can be used to set the page orientation.\nThe value can be either `portrait` or `landscape`. The default is\nportrait.\n\n```ts\nconst document = {\n  pageSize: 'A5',\n  pageOrientation: 'landscape',\n  content: [text('Lorem ipsum')],\n};\n```\n\n### Headers and footers\n\nHeaders and footers that repeat on each page can be defined using the\noptional `header` and `footer` properties. Both accept either a single\nblock or a function that returns a block. The function will be called\nwith the page number and the total number of pages. The page number\nstarts at 1.\n\n```ts\nconst document = {\n  footer: ({ pageNumber, pageCount }) =\u003e\n    text(`Page ${pageNumber} of ${pageCount}`, {\n      textAlign: 'right',\n      margin: { x: '20mm', bottom: '7mm' },\n    }),\n  content: [text('Lorem ipsum'), text('dolor sit amet')],\n};\n```\n\n### Page breaks\n\nPage breaks are included automatically. When a block does not fit on the\ncurrent page, a new page is added to the document. To insert a page\nbreak before or after a block, set the `breakBefore` or `breakAfter`\nproperty of a block to `always`. To prevent a page break, set this\nproperty to `avoid`.\n\nPage breaks are also automatically inserted between the lines of a text\nblock. To prevent a page break within a text block, set the\n`breakInside` property to `avoid`.\n\n```ts\nconst document = {\n  content: [\n    text('Lorem ipsum'),\n    text('This text will go on a new page', { breakBefore: 'always' }),\n  ],\n};\n```\n\n## Anchors\n\nAnchors can be used to create links to other locations in the document.\nAn anchor is created by setting a unique `id` property to the block that\nshould be the target of the link:\n\n```ts\ntext('Section Two', { id: 'section2' });\n```\n\nAn internal reference to this anchor can be created by setting the\n`link` property of a text span to a hash sign (`#`), followed by the\n`id` of the target block:\n\n```ts\ntext([\n  'See ',\n  span('Section Two', { link: '#section2' }), // Link to a section\n  ' for more information.'\n]);\n...\n```\n\n## Metadata\n\nPDF documents can include metadata such as the title, author, subject,\nand keywords. This information can be set using the `info` property of\nthe document.\n\n```ts\nconst document = {\n  info: {\n    title: 'Invoice Dec 2024',\n    author: 'John Doe',\n  },\n  content: [text('Hello World!')],\n};\n```\n\nThe following properties are supported:\n\n- `title`: The document’s title.\n- `author`: The name of the person who created the document.\n- `subject`: The subject of the document.\n- `keywords`: Keywords associated with the document.\n- `creationDate`: The date and time the document was created. If not\n  set, the current time is used.\n- `modificationDate`: The date and time the document was last modified.\n  If not set, the current time is used.\n- `creator`: The name of the application that created the original\n  content.\n- `producer`: The name of the application that converted the original\n  content into a PDF.\n\n## Embedded files\n\nSupplementary files can be stored directly within a PDF document. This\ncan be useful for creating self-contained documents, such as for\narchival purposes. Those files can be added to the document using the\n`embeddedFiles` property, which accepts an array of objects, each\nrepresenting a file with the following properties:\n\n- `content`: The binary content of the file as a `Uint8Array`.\n- `fileName`: The name of the file as it will appear in the list of\n  attachments in the PDF viewer.\n- `mimeType`: The MIME type of the file.\n- `description` (optional): A brief description of the file's content or\n  purpose. This information can be displayed to the user in the PDF\n  viewer.\n- `creationDate` (optional): The date and time when the file was\n  created.\n- `modificationDate` (optional): The date and time when the file was\n  last modified.\n- `relationship` (optional): A name that specifies the relationship\n  between the file and the document.\n\n```ts\nconst document = {\n  content: [text('Hello World!')],\n  embeddedFiles: [\n    {\n      fileName: \"Study-Results-2025.csv\",\n      mimeType: \"text/csv\",\n      content: /* binary data of the data */,\n      mimeType: 'image/png',\n      description: \"CSV file containing the result data of the 2025 study.\",\n      creationDate: new Date(\"2025-01-12\"),\n    },\n  ],\n};\n```\n\n## Dev tools\n\n### Visual Debugging\n\nThis feature can be used to visually inspect the structure and layout of\nblocks in the PDF document during development. When enabled, it includes\nsome visual guides in the generated PDF:\n\n- Each block is rendered with a gray border to indicate its bounds.\n- Page headers and footers are separated from the page content by a\n  horizontal line.\n- Each line of text is surrounded by a thin green border. Another thin\n  green line indicates the text baseline.\n- Margins and paddings get a semi-transparent overlay. Margins are shown\n  in yellow, paddings in purple. Overlapping margins will\n  result in a darker shade of yellow.\n\nTo enable visual debugging, set the `dev.guides` property in the\ndocument to `true`:\n\n```ts\nconst document = {\n  dev: { guides: true }, // Enable visual debugging\n  content: [\n    text('Hello World!'),\n  ],\n  ...\n};\n```\n\n## License\n\n[MIT](LICENSE.txt)\n\n## Thanks\n\nThis project is inspired by [pdfmake] and builds on [pdf-lib] and\n[fontkit]. It would not exist without the great work and the profound\nknowledge contributed by the authors of those projects.\n\n[pdfmake]: https://github.com/bpampuch/pdfmake\n[pdf-lib]: https://github.com/Hopding/pdf-lib\n[fontkit]: https://github.com/Hopding/fontkit\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feclipsesource%2Fpdf-maker","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feclipsesource%2Fpdf-maker","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feclipsesource%2Fpdf-maker/lists"}