
Typical Business Application
npm init
npm install pdfkit
npm install request
npm install axios"use strict";
const _REQUEST = require("request");
module.exports =
{
doRequest: doRequest
}
async function doRequest(requestPayload)
{
return new Promise(function(resolve, reject)
{
_REQUEST(requestPayload, function(err, response)
{
if (err)
{
reject(err);
}
else
{
resolve(response);
}
});
});
}
"use strict"
const _INVOICE_GENERATOR = require("./InvoiceGenerator");
const _kINVOICE_DATA =
{
invoiceNumber: "9900001",
dueDate: "March 31, 2021",
subtotal: 8000,
paid: 500,
memo: "Delivery expected in 7 days",
addresses:
{
billing:
{
name: "Santa Claus",
address: "1 Elf Street",
city: "Arctic City",
state: "Arctic Circle",
postalCode: "H0H 0H0",
country: "North Pole"
}
},
items:
[
{
itemCode: "12341",
itemDescription: "Best Run laptop computer",
quantity: 4,
price: 2985.00
},
{
itemCode: "12342",
itemDescription: "Best Run desktop computer",
quantity: 2,
price: 2295.00
}
]
};
let ig = new _INVOICE_GENERATOR(_kINVOICE_DATA);
void async function main()
{
await ig.generate();
}()"use strict"
const _AXIOS = require("axios");
const _FS = require("fs");
const _PDFKIT = require("pdfkit");
const _REQUEST = require("request");
const _REQUEST_UTIL = require("./RequestUtil");
class InvoiceGenerator
{
constructor(invoice)
{
this.invoice = invoice;
}
async generate()
{
let pdfkit = new _PDFKIT();
let pdfOutputFile = `./Invoice-${this.invoice.invoiceNumber}.pdf`;
// [COMMENT] The PDF file is to be written to the file system.
pdfkit.pipe(_FS.createWriteStream(pdfOutputFile));
await this.writeContent(pdfkit);
pdfkit.end();
}
async writeContent(pdfkit)
{
this.generateHeaders(pdfkit);
this.generateTable(pdfkit);
this.drawBoxes(pdfkit);
await this.displayImage(pdfkit);
this.generateBulletList(pdfkit);
this.generateNumberedList(pdfkit);
this.generateLetteredList(pdfkit);
this.generateMutliLevelList(pdfkit);
this.generateHyperlink(pdfkit);
this.generateFooter(pdfkit);
}
generateHeaders(pdfkit) {...}
generateTable(pdfkit) {...}
drawBoxes(pdfkit) {...}
async displayImage(pdfkit) {...}
// displayImageBase64(pdfkit) {...}
generateBulletList(pdfkit) {...}
generateNumberedList(pdfkit) {...}
generateLetteredList(pdfkit) {...}
generateMultiLevelList(pdfkit) {...}
generateHyperlink(pdfkit) {...}
generateFooter(pdfkit) {...}
}
module.exports = InvoiceGenerator;generateHeaders(pdfkit)
{
let billingAddress = this.invoice.addresses.billing;
pdfkit.image("./SAP.png", 25, 25, {width: 150})
.fillColor("#000")
.fontSize(20)
.text("INVOICE", 400, 25, {align: "right"})
.fontSize(10)
.text(`Invoice Number: ${this.invoice.invoiceNumber}`, {align: "right"})
.text(`Due Date: ${this.invoice.dueDate}`, {align: "right"})
.text(`Balance Due: €${this.invoice.subtotal - this.invoice.paid}`, {align: "right"});
// [COMMENT] A blank line between Balance Due and Billing Address.
pdfkit.moveDown();
pdfkit.text(`Billing Address:\n${billingAddress.name}`, {align: "right"})
.text(`${billingAddress.address}\n${billingAddress.city}`, {align: "right"})
.text(`${billingAddress.state} ${billingAddress.postalCode}`, {align: "right"})
.text(`${billingAddress.country}`, {align: "right"});
const _kPAGE_BEGIN = 25;
const _kPAGE_END = 580;
// [COMMENT] Draw a horizontal line.
pdfkit.moveTo(_kPAGE_BEGIN, 200)
.lineTo(_kPAGE_END, 200)
.stroke();
pdfkit.text(`Memo: ${this.invoice.memo}`, 50, 210);
pdfkit.moveTo(_kPAGE_BEGIN, 250)
.lineTo(_kPAGE_END, 250)
.stroke();
}
The Generated Header
generateTable(pdfkit)
{
const _kTABLE_TOP_Y = 270;
const _kITEM_CODE_X = 50;
const _kDESCRIPTION_X = 100;
const _kQUANTITY_X = 250;
const _kPRICE_X = 300;
const _kAMOUNT_X = 350;
pdfkit.fontSize(10)
.text("Item Code", _kITEM_CODE_X, _kTABLE_TOP_Y, {bold: true, underline: true})
.text("Description", _kDESCRIPTION_X, _kTABLE_TOP_Y, {bold: true, underline: true})
.text("Quantity", _kQUANTITY_X, _kTABLE_TOP_Y, {bold: true, underline: true})
.text("Price", _kPRICE_X, _kTABLE_TOP_Y, {bold: true, underline: true})
.text("Amount", _kAMOUNT_X, _kTABLE_TOP_Y, {bold: true, underline: true});
let items = this.invoice.items;
for (let idx = 0; idx < items.length; idx++)
{
let item = items[idx];
let yCoord = _kTABLE_TOP_Y + 25 + (idx * 25);
pdfkit.fontSize(10)
.text(`${item.itemCode}`, _kITEM_CODE_X, yCoord)
.text(`${item.itemDescription}`, _kDESCRIPTION_X, yCoord)
.text(`${item.quantity}`, _kQUANTITY_X, yCoord)
.text(`€${item.price}`, _kPRICE_X, yCoord)
.text(`€${item.price * item.quantity}`, _kAMOUNT_X, yCoord);
}
}
The Generated Table
drawBoxes(pdfkit)
{
const _kTOP_H_LINE_X = 100;
const _kTOP_H_LINE_Y = 500;
const _kBOTTOM_H_LINE_X = 100;
const _kBOTTOM_H_LINE_Y = 525;
const _kH_LINE_LENGTH = 400;
// [COMMENT] Draw the 2 horizontal lines.
pdfkit.moveTo(_kTOP_H_LINE_X, _kTOP_H_LINE_Y)
.lineTo(_kH_LINE_LENGTH, _kTOP_H_LINE_Y)
.stroke();
pdfkit.moveTo(_kBOTTOM_H_LINE_X, _kBOTTOM_H_LINE_Y)
.lineTo(_kH_LINE_LENGTH, _kBOTTOM_H_LINE_Y)
.stroke();
const _kV_LINE_1_X = 100;
const _kV_LINE_2_X = 200;
const _kV_LINE_3_X = 300;
const _kV_LINE_4_X = 400;
const _kV_LINE_LENGTH = 25;
// [COMMENT] Draw the vertical lines.
pdfkit.moveTo(_kV_LINE_1_X, _kTOP_H_LINE_Y)
.lineTo(_kV_LINE_1_X, _kTOP_H_LINE_Y + _kV_LINE_LENGTH)
.stroke();
pdfkit.moveTo(_kV_LINE_2_X, _kTOP_H_LINE_Y)
.lineTo(_kV_LINE_2_X, _kTOP_H_LINE_Y + _kV_LINE_LENGTH)
.stroke();
pdfkit.moveTo(_kV_LINE_3_X, _kTOP_H_LINE_Y)
.lineTo(_kV_LINE_3_X, _kTOP_H_LINE_Y + _kV_LINE_LENGTH)
.stroke();
pdfkit.moveTo(_kV_LINE_4_X, _kTOP_H_LINE_Y)
.lineTo(_kV_LINE_4_X, _kTOP_H_LINE_Y + _kV_LINE_LENGTH)
.stroke();
// [COMMENT] Write the text “Box 1”, “Box 2”, and “Box 3” in the boxes.
pdfkit.fontSize(10)
.text("Box 1", _kV_LINE_1_X + 5, _kTOP_H_LINE_Y + 5)
.text("Box 2", _kV_LINE_2_X + 5, _kTOP_H_LINE_Y + 5)
.text("Box 3", _kV_LINE_3_X + 5, _kTOP_H_LINE_Y + 5)
}
The Drawn Boxes
async displayImage(pdfkit)
{
let requestPayload =
{
url: "https://www.sap.com/dam/application/shared/photos/hero-product-category/sap-s4hana-custom-hero.jpg/_jcr_content/renditions/sap-s4hana-custom-hero_3198_1648.jpg.adapt.1599_824.false.false.false.false.jpg/1563795394722.jpg",
method: "GET",
encoding: null
}
let response = await _REQUEST_UTIL.doRequest(requestPayload);
let statusCode = response.statusCode;
let responseBody = response.body;
let imgBinary = Buffer.from(responseBody, "binary");
// [COMMENT] The image is encoded in base64 string.
let imgBase64 = imgBinary.toString("base64");
let img = Buffer.from(imgBase64, "base64");
pdfkit.addPage().text("Image").image(img, 100, 100, {width: 400});
}async displayImage(pdfkit)
{
let imageUrl = "https://www.sap.com/dam/application/shared/photos/hero-product-category/sap-s4hana-custom-hero.jpg/_jcr_content/renditions/sap-s4hana-custom-hero_3198_1648.jpg.adapt.1599_824.false.false.false.false.jpg/1563795394722.jpg";
let response = await _AXIOS.request(
{
method: "GET",
url: imageUrl,
responseEncoding: "binary"
});
let responseData = response.data;
let imgBinary = Buffer.from(responseData, "binary");
// [COMMENT] The image is encoded in base64 string.
let imgBase64 = imgBinary.toString("base64");
let img = Buffer.from(imgBase64, "base64");
pdfkit.addPage().text("Image").image(img, 100, 100, {width: 400});
}
displayImage(pdfkit)
{
// [COMMENT] The image is encoded in base64 string.
let imgBase64 = "/9j/4AAQSkZJRgABAgAA ... atrdbG1sbH0LY2Nn/9k=";
let img = Buffer.from(imgBase64, "base64");
pdfkit.addPage().text("Image").image(img, 100, 100, {width: 400});
}
The Displayed Image
generateBulletList(pdfkit)
{
let theList = ["Item A", "Item B", "Item C"];
let xCoord = 100;
let yCoord = 400;
pdfkit.fontSize(10)
.fillColor("green")
.list(theList, xCoord, yCoord, {listType: "bullet"});
}
The Generated Bullet List
generateNumberedList(pdfkit)
{
let theList = ["Item A", "Item B", "Item C"];
let xCoord = 100;
let yCoord = 450;
pdfkit.fontSize(10)
.fillColor("purple")
.list(theList, xCoord, yCoord, {listType: "numbered"});
}
The Generated Numbered List
generateLetteredList(pdfkit)
{
let theList = ["Item A", "Item B", "Item C"];
let xCoord = 100;
let yCoord = 500;
pdfkit.fontSize(10)
.fillColor("purple")
.list(theList, xCoord, yCoord, {listType: "lettered"});
}
The Generated Lettered List
generateMutliLevelList(pdfkit)
{
let theList = ["Item A", ["Item A1", "Item A2"], "Item B", "Item C"];
let xCoord = 100;
let yCoord = 550;
pdfkit.fontSize(10)
.fillColor("purple")
.list(theList, xCoord, yCoord, {listType: "bullet"});
}
The Generated Multi-Level List
generateHyperlink(pdfkit)
{
let linkText = "SAP.com";
let xCoord = 100;
let yCoord = 650;
pdfkit.fontSize(10)
.fillColor("blue")
.text(linkText, xCoord, yCoord);
let width = pdfkit.widthOfString(linkText);
let height = pdfkit.currentLineHeight();
pdfkit.underline(100, 650, width, height, {color: "blue"})
.link(100, 650, width, height, "https://www.sap.com");
}
The Generated Clickable Hyperlink
generateFooter(pdfkit)
{
pdfkit.fontSize(10)
.fillColor("black")
.text("Payment due upon receipt.", 50, 700, {align: "center"});
}
The Generated Footer

The Generated PDF File
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
| User | Count |
|---|---|
| 45 | |
| 44 | |
| 34 | |
| 32 | |
| 29 | |
| 25 | |
| 23 | |
| 22 | |
| 21 | |
| 21 |