An easy to use Line by Line pdf generator for NodeJS using PDFKit, with support of text, images, backgrounds, borders, and page layout control without needing a browser engine installed!
- Dynamic layout with rows and columns
- Support for text, images, and layout control (page breaks, splits, etc.)
- Customizable styling (fonts, colors, borders, margins)
- Get PDF as a buffer as a return
- No need for a browser engine to be installed
npm install line-by-line-pdf-generator
You can run the generatePdf
function it expects 2 arguments, the first one is a 2-dimensional array with all the
columns and the second one is optional and is the options for the pdf.
import pdfGenerator from "line-by-line-pdf-generator"
const generatedPdf = await pdfGenerator([
[
/* PDF columns for the first row */
],
[
/* PDF columns for the second row */
]
], {
/* Optional options */
})
An example of a very simple PDF
import pdfGenerator from "line-by-line-pdf-generator"
import {PdfColumnType} from "line-by-line-pdf-generator/types";
import fs from "fs"
const generatedPdf = await pdfGenerator([
[
{
type: PdfColumnType.TEXT,
text: "Hello world",
justify: "center",
},
{
type: PdfColumnType.EMPTY,
cols: 2
},
{
type: PdfColumnType.TEXT,
text: "Goodbye",
},
],
[
{
type: PdfColumnType.TEXT,
text: "Image: ",
size: 24,
justify: "left",
color: "black",
background: "yellow"
},
{
type: PdfColumnType.IMAGE,
cols: 3,
url: "https://picsum.photos/300/200",
options: {
fit: ["colum-width", 300]
}
},
]
], {
textColor: "green",
textJustify: "right"
})
fs.writeFileSync("pdf.pdf", generatedPdf)
The PDF options exists of the following arguments all of these are optional
Option | Type | Default | Description |
---|---|---|---|
margin | number | 30 | A margin on the pdf page |
rowHeight | number | 1 | The amount of pixels on the top and bottom of texts columns |
colMargin | number | 0 | The amount of pixels on the right and left of texts columns |
textSize | number | 12 | The default font size of text |
textColor | string | black | The default text color |
textFont | string | Helvetica | The default font |
textJustify | TextJustify | left | The justify for all text (see text columns for more info) |
To create a PDF with the line by line PDF generator you have to use a 2-dimensional array of Rows containing Columns, think of it like this
[
[{ /* First col of the first line*/}, { /* Second col of the first line*/}], /* First line of the PDF*/
[{ /* First col of the second line*/}, { /* Second col of the second line*/}] /* Second line of the PDF*/
]
The location if the columns will be automatically calculated. There are multiple column types
TEXT
IMAGE
EMPTY
PAGE_BREAK
PAGE_SPLIT
Each of these have their own unique features but all of them have common attributes that can be used by any of them
These attributes can be used by all column types:
The background of the column, it can be any a color name or a hex value
Example
const yellowColumn = {
type: PdfColumnType.EMPTY,
background: "yellow"
}
The Border of the column, it has 4 optional sub attributes left
, right
, top
, and bottom
they indicate the axes
of the border each axes has 2 attributes width
and an optional color
, width
is the size of the border and color
is the border color with will default to the font color
Example
const borderedColumn = {
type: PdfColumnType.EMPTY,
border: {
top: {
width: 1,
color: "black"
},
bottom: {
width: 1,
color: "black"
},
left: {
width: 1,
color: "black"
},
right: {
width: 1,
color: "black"
}
}
}
The width of Columns by default is all the same, but sometimes you want some colums to be bigger or smaller than other
columns, you can use the cols
attribute for that, cols
is a number with default 1 that indicates the size this
column
indicates, if cols
is 2 it will be twice as big as the default.
Example
const differentSizeRow = [
{
type: PdfColumnType.EMPTY,
cols: 1 /* this col will take 25% of the page */
},
{
type: PdfColumnType.EMPTY,
cols: 2 /* this col will take 50% of the page */
},
{
type: PdfColumnType.EMPTY,
cols: 1 /* this col will take 25% of the page */
}
]
you can also make cols intentionally smaller
const differentSizeRow = [
{
type: PdfColumnType.EMPTY,
cols: 1 /* this col will take 50% of the page */
},
{
type: PdfColumnType.EMPTY,
cols: 0.5 /* this col will take 25% of the page */
},
{
type: PdfColumnType.EMPTY,
cols: 0.5 /* this col will take 25% of the page */
}
]
Be aware that cols: 1
is the default so its not necessary to include, I only included it for extra clarity
Adds texts to the column, text will not exceed a size of a column and will be wrapped inside the column, the height will be automatically be taken care off. A text column can have the following attributes:
This is a required string, that will be the text that is placed in the column, it will be automatically wrapped to the size of the column
Example
const textColumn = {
type: PdfColumnType.TEXT,
text: "Hello world"
}
An oprional string to make text a clickable link.
Example
const textColumn = {
type: PdfColumnType.TEXT,
text: "Go to my website!",
link: "https://michelle-honnebier.com"
}
An optional string of the color of the text will default to the textColor
value in the PDF options, color can be a
color name or HEX value.
Example
const textColumn = {
type: PdfColumnType.TEXT,
text: "Hello world",
color: "green"
}
An optional string of the color of the text will default to the textSize
value in the PDF options
Example
const textColumn = {
type: PdfColumnType.TEXT,
text: "Hello world!",
size: 36
}
An optional string of the font of the text will default to the textFont
value in the PDF options learn more about
fonts here for now you can only use the default fonts the ability to register
new fonts will be availible soon
Example
const textColumn = {
type: PdfColumnType.TEXT,
text: "Hello world",
font: "Helvatica-Bolt",
}
An optinal value that is indicate how the text can be aligned in the column it can be left
, center
, right
, or
justify
. It will fallback to the textJustify
value in the PDF options. read more about
it here
Example
const textColumn = {
type: PdfColumnType.TEXT,
text: "Hello world",
justify: "right",
}
Empty columns are columns without anything, they can be used to create a buffer or make use of the common attributes to
get a background text, it has one attribute size
which is the size in pixels how big the empty column.
You can use empty column to create a vertical buffer
const PdfRows = [
[{
type: PdfColumnType.TEXT,
text: "Hello world"
}],
[{
type: PdfColumnType.EMPTY,
size: 150 /* 150px empty space between rows*/
}],
[{
type: PdfColumnType.TEXT,
text: "Goodbye!"
}]
]
You can also use empty column to use default attributes and align all your columns correctly
const PdfRow = [
{
type: PdfColumnType.TEXT,
text: "Hello world"
}, {
type: PdfColumnType.EMPTY,
cols: 2,
color: "yellow" /* ads an empty yellow block between the 2 texts that takes 50% of the page */
}, {
type: PdfColumnType.TEXT,
text: "Goodbye!"
}
]
Image columns can be used to insert images, it expects an attribute url
, file
, or buffer
and options
, url
,
file
, or buffer
is how the image should be fetched url
points to a url file
points to a file, and buffer
is an
ArrayBuffer of the image, options
are the PDFKIT image options, If you
want to use the column with as image with you can use the "column-with"
string and it will be replaced by the column
with, currently only width
and fit
are supported, more support is coming soon
Simple image from an url:
const imageColumn = {
type: PdfColumnType.IMAGE,
cols: 3,
url: "https://picsum.photos/300/200",
options: {
width: 300,
height: 200
}
}
Simple image from a file:
const imageColumn = {
type: PdfColumnType.IMAGE,
cols: 3,
file: "assets/images/logo.png",
options: {
width: 300,
height: 200
}
}
Simple image from a buffer:
const imageColumn = {
type: PdfColumnType.IMAGE,
cols: 3,
buffer: <ArrayBuffer>,
options: {
width: 300,
height: 200
}
}
Image to fit in specific width and height:
const imageColumn = {
type: PdfColumnType.IMAGE,
cols: 3,
url: "https://picsum.photos/300/200",
options: {
fit: [300, 200],
}
}
Image to within column width:
const imageColumn = {
type: PdfColumnType.IMAGE,
cols: 3,
url: "https://picsum.photos/300/200",
options: {
fit: ["column-width", 200],
}
}
Images will not have their height calculated within the row height, this is intended behaviour since its quite common
you want multiple text
rows next to an image, if you want to text below an image you can create an Empty column with cols: 0
and
size: image-size
to make the height of the row the height of the image, a way to calculate the image height in the row
height is coming soon.
End of page will end the page, all following rows will appear on a new page
const PdfRows = [
[{
type: PdfColumnType.TEXT,
text: "Hello world" /* This will appear on page one */
}],
[{
type: PdfColumnType.PAGE_BREAK,
}],
[{
type: PdfColumnType.TEXT,
text: "Goodbye!" /* This will appear on page two */
}]
]
You can also use default attributes on a page break
const PdfRows = [
[{
type: PdfColumnType.TEXT,
text: "Hello world" /* This will appear on page one */
}],
[{
type: PdfColumnType.EMPTY,
}, {
type: PdfColumnType.PAGE_BREAK,
background: "blue",
cols: 2 /* 66% of the rest of the page will a blue block*/
}],
[{
type: PdfColumnType.TEXT,
text: "Goodbye!" /* This will appear on page two */
}]
]
Will create a split in the page, the lines after a split will be rendered on the bottom of the page, if the 2 sections do not fit on one page a new page will be created.
const PdfRows = [
[{
type: PdfColumnType.TEXT,
text: "Hello world" /* This on top */
}], [{
type: PdfColumnType.TEXT,
text: "Hello world" /* This one line below*/
}],
[{
type: PdfColumnType.PAGE_SPLIT,
}],
[{
type: PdfColumnType.TEXT,
text: "Goodbye!" /* This will one line above the the bottom of the page */
}],
[{
type: PdfColumnType.TEXT,
text: "Goodbye!" /* This will appear on the bottom of the age */
}]
]
If the 2 sections are to big for one page it will look like this
const PdfRows = [
[{
type: PdfColumnType.TEXT,
text: "Hello world" /* This on top */
}], [{
type: PdfColumnType.EMPTY,
size: 1000
}],
[{
type: PdfColumnType.PAGE_SPLIT,
}],
[{
type: PdfColumnType.TEXT,
text: "Goodbye!" /* This be on top of a new page */
}],
[{
type: PdfColumnType.EMPTY,
size: 1000
}]
]
You can also use page split columns with the common attributes
const PdfRows = [
[{
type: PdfColumnType.TEXT,
text: "Hello world" /* This on top */
}], [{
type: PdfColumnType.TEXT,
text: "Hello world" /* This one line below*/
}],
[{
type: PdfColumnType.PAGE_SPLIT,
background: "orange",
border: {
bottom: {
width: 1,
color: white
}
} /* The space between the sections will be orange and there will be a white border before the second section */
}],
[{
type: PdfColumnType.TEXT,
text: "Goodbye!" /* This will one line above the the bottom of the page */
}],
[{
type: PdfColumnType.TEXT,
text: "Goodbye!" /* This will appear on the bottom of the age */
}]
]
You can only use one page split per page, if you want to use another one you need to place an PAGE_BREAK
component
between them
This will give an error:
const PdfRows = [
[{
type: PdfColumnType.TEXT,
text: "Hello world"
}], [{
type: PdfColumnType.TEXT,
text: "Hello world"
}],
[{
type: PdfColumnType.PAGE_SPLIT,
}],
[{
type: PdfColumnType.TEXT,
text: "Goodbye!"
}],
[{
type: PdfColumnType.TEXT,
text: "Goodbye!"
}],
[{
type: PdfColumnType.PAGE_SPLIT,
}],
[{
type: PdfColumnType.TEXT,
text: "Goodbye!"
}],
[{
type: PdfColumnType.TEXT,
text: "Goodbye!"
}]
]
This will work fine
const PdfRows = [
[{
type: PdfColumnType.TEXT,
text: "Hello world"
}], [{
type: PdfColumnType.TEXT,
text: "Hello world"
}],
[{
type: PdfColumnType.PAGE_SPLIT,
}],
[{
type: PdfColumnType.TEXT,
text: "Goodbye!"
}],
[{
type: PdfColumnType.TEXT,
text: "Goodbye!"
}],
[{
type: PdfColumnType.PAGE_BREAK,
}],
[{
type: PdfColumnType.TEXT,
text: "Goodbye!"
}],
[{
type: PdfColumnType.TEXT,
text: "Goodbye!"
}],
[{
type: PdfColumnType.PAGE_SPLIT,
}],
[{
type: PdfColumnType.TEXT,
text: "Goodbye!"
}],
[{
type: PdfColumnType.TEXT,
text: "Goodbye!"
}],
]