A lightweight Typescript library that interacts with Gotenberg's different routes to convert a variety of document formats to PDF files.
Using npm:
npm install chromiumly
Using yarn:
yarn add chromiumly
Before attempting to use Chromiumly, be sure you install Docker if you have not already done so.
After that, you can start a default Docker container of Gotenberg as follows:
docker run --rm -p 3000:3000 gotenberg/gotenberg:8
Chromiumly supports configurations via both dotenv and config configuration libraries or directly via code to add Gotenberg endpoint to your project.
GOTENBERG_ENDPOINT=http://localhost:3000
{
"gotenberg": {
"endpoint": "http://localhost:3000"
}
}
import { Chromiumly } from "chromiumly";
Chromiumly.configure({ endpoint: "http://localhost:3000" });
Gotenberg introduces basic authentication support starting from version 8.4.0. Suppose you are running a Docker container using the command below:
docker run --rm -p 3000:3000 \
-e GOTENBERG_API_BASIC_AUTH_USERNAME=user \
-e GOTENBERG_API_BASIC_AUTH_PASSWORD=pass \
gotenberg/gotenberg:8.4.0 gotenberg --api-enable-basic-auth
To integrate this setup with Chromiumly, you need to update your configuration as outlined below:
GOTENBERG_ENDPOINT=http://localhost:3000
GOTENBERG_API_BASIC_AUTH_USERNAME=user
GOTENBERG_API_BASIC_AUTH_PASSWORD=pass
Or
{
"gotenberg": {
"endpoint": "http://localhost:3000",
"api": {
"basicAuth": {
"username": "user",
"password": "pass"
}
}
}
}
Or
Chromiumly.configure({
endpoint: "http://localhost:3000",
username: "user",
password: "pass",
});
To implement advanced authentication or add custom HTTP headers to your requests, you can use the customHttpHeaders
option within the configure
method. This allows you to pass additional headers, such as authentication tokens or custom metadata, with each API call.
For example, you can include a Bearer token for authentication along with a custom header as follows:
const token = await generateToken();
Chromiumly.configure({
endpoint: "http://localhost:3000",
customHttpHeaders: {
Authorization: `Bearer ${token}`,
"X-Custom-Header": "value",
},
});
Chromiumly introduces different classes that serve as wrappers to
Gotenberg's routes. These classes encompass methods featuring an
input file parameter, such as html
, header
, footer
, and markdown
, capable of accepting inputs in the form of a
string
(i.e. file path), Buffer
, or ReadStream
.
There are three different classes that come with a single method (i.e.convert
) which calls one of
Chromium's Conversion routes to convert html
and markdown
files, or
a url
to a buffer
which contains the converted PDF file content.
Similarly, a new set of classes have been added to harness the recently introduced Gotenberg Screenshot routes. These classes include a single method called capture
, which allows capturing full-page screenshots of html
, markdown
, and url
.
import { UrlConverter } from "chromiumly";
const urlConverter = new UrlConverter();
const buffer = await urlConverter.convert({
url: "https://www.example.com/",
});
import { UrlScreenshot } from "chromiumly";
const screenshot = new UrlScreenshot();
const buffer = await screenshot.capture({
url: "https://www.example.com/",
});
The only requirement is that the file name should be index.html
.
import { HtmlConverter } from "chromiumly";
const htmlConverter = new HtmlConverter();
const buffer = await htmlConverter.convert({
html: "path/to/index.html",
});
import { HtmlScreenshot } from "chromiumly";
const screenshot = new HtmlScreenshot();
const buffer = await screenshot.capture({
html: "path/to/index.html",
});
This route accepts an index.html
file plus a markdown file.
import { MarkdownConverter } from "chromiumly";
const markdownConverter = new MarkdownConverter();
const buffer = await markdownConverter.convert({
html: "path/to/index.html",
markdown: "path/to/file.md",
});
import { MarkdownScreenshot } from "chromiumly";
const screenshot = new MarkdownScreenshot();
const buffer = await screenshot.capture({
html: "path/to/index.html",
markdown: "path/to/file.md",
});
convert()
method takes an optional properties
parameter of the following type which dictates how the PDF generated
file will look like.
type PageProperties = {
singlePage?: boolean; // Print the entire content in one single page (default false)
size?: {
width: number; // Paper width, in inches (default 8.5)
height: number; //Paper height, in inches (default 11)
};
margins?: {
top: number; // Top margin, in inches (default 0.39)
bottom: number; // Bottom margin, in inches (default 0.39)
left: number; // Left margin, in inches (default 0.39)
right: number; // Right margin, in inches (default 0.39)
};
preferCssPageSize?: boolean; // Define whether to prefer page size as defined by CSS (default false)
printBackground?: boolean; // Print the background graphics (default false)
omitBackground?: boolean; // Hide the default white background and allow generating PDFs with transparency (default false)
landscape?: boolean; // Set the paper orientation to landscape (default false)
scale?: number; // The scale of the page rendering (default 1.0)
nativePageRanges?: { from: number; to: number }; // Page ranges to print
};
In addition to the PageProperties
customization options, the convert()
method also accepts a set of parameters to further enhance the versatility of the conversion process. Here's an overview of the full list of parameters:
type ConversionOptions = {
properties?: PageProperties; // Customize the appearance of the generated PDF
pdfFormat?: PdfFormat; // Define the PDF format for the conversion
pdfUA?: boolean; // Enable PDF for Universal Access for optimal accessibility (default false)
userAgent?: string; // Customize the user agent string sent during conversion
header?: PathLikeOrReadStream; // Specify a custom header for the PDF
footer?: PathLikeOrReadStream; // Specify a custom footer for the PDF
emulatedMediaType?: EmulatedMediaType; // Specify the emulated media type for conversion
waitDelay?: string; // Duration (e.g., '5s') to wait when loading an HTML document before conversion
waitForExpression?: string; // JavaScript expression to wait before converting an HTML document into PDF
extraHttpHeaders?: Record<string, string>; // Include additional HTTP headers in the request
failOnHttpStatusCodes?: number[]; // List of HTTP status codes triggering a 409 Conflict response (default [499, 599])
failOnConsoleExceptions?: boolean; // Return a 409 Conflict response if there are exceptions in the Chromium console (default false)
skipNetworkIdleEvent?: boolean; // Do not wait for Chromium network to be idle (default true)
metadata?: Metadata; // Metadata to be written.
cookies?: Cookie[]; // Cookies to be written.
downloadFrom?: DownloadFrom; //Download a file from a URL. It must return a Content-Disposition header with a filename parameter.
};
Similarly, the capture()
method takes an optional properties
parameter of the specified type, influencing the appearance of the captured screenshot file.
type ImageProperties = {
format: "png" | "jpeg" | "webp"; //The image compression format, either "png", "jpeg" or "webp".
quality?: number; // The compression quality from range 0 to 100 (jpeg only).
omitBackground?: boolean; // Hide the default white background and allow generating screenshots with transparency.
width?: number; // The device screen width in pixels (default 800).
height?: number; // The device screen height in pixels (default 600).
clip?: boolean; // Define whether to clip the screenshot according to the device dimensions (default false).
};
Furthermore, alongside the customization options offered by ImageProperties
, the capture()
method accommodates a variety of parameters to expand the versatility of the screenshot process. Below is a comprehensive overview of all parameters available:
type ScreenshotOptions = {
properties?: ImageProperties;
header?: PathLikeOrReadStream;
footer?: PathLikeOrReadStream;
emulatedMediaType?: EmulatedMediaType;
waitDelay?: string; // Duration (e.g, '5s') to wait when loading an HTML document before convertion.
waitForExpression?: string; // JavaScript's expression to wait before converting an HTML document into PDF until it returns true.
extraHttpHeaders?: Record<string, string>;
failOnHttpStatusCodes?: number[]; // Return a 409 Conflict response if the HTTP status code is in the list (default [499,599])
failOnConsoleExceptions?: boolean; // Return a 409 Conflict response if there are exceptions in the Chromium console (default false)
skipNetworkIdleEvent?: boolean; // Do not wait for Chromium network to be idle (default true)
optimizeForSpeed?: boolean; // Define whether to optimize image encoding for speed, not for resulting size.
cookies?: Cookie[]; // Cookies to be written.
downloadFrom?: DownloadFrom; // Download the file from a specific URL. It must return a Content-Disposition header with a filename parameter.
};
The LibreOffice
class comes with a single method convert
. This method interacts with LibreOffice route to convert different documents to PDF files. You can find the file extensions
accepted here.
import { LibreOffice } from "chromiumly";
const buffer = await LibreOffice.convert({
files: [
"path/to/file.docx",
"path/to/file.png",
{ data: xlsxFileBuffer, ext: "xlsx" },
],
});
Similarly to Chromium's route convert
method, this method takes the following optional parameters :
properties
: changes how the PDF generated file will look like. It also includes apassword
parameter to open the source file.pdfa
: PDF format of the conversion resulting file (i.e.PDF/A-1a
,PDF/A-2b
,PDF/A-3b
).pdfUA
: enables PDF for Universal Access for optimal accessibility.merge
: merges all the resulting files from the conversion into an individual PDF file.metadata
: writes metadata to the generated PDF file.lolosslessImageCompression
: allows turning lossless compression on or off to tweak image conversion performance.reduceImageResolution
: allows turning on or off image resolution reduction to tweak image conversion performance.quality
: specifies the quality of the JPG export. The value ranges from 1 to 100, with higher values producing higher-quality images and larger file sizes.maxImageResolution
: specifies if all images will be reduced to the specified DPI value. Possible values are:75
,150
,300
,600
, and1200
.
The PDFEngines
class interacts with Gotenberg's PDF Engines routes to manupilate PDF files.
This method interacts with PDF Engines convertion route to transform PDF files into the requested PDF/A format and/or PDF/UA.
import { PDFEngines } from "chromiumly";
const buffer = await PDFEngines.convert({
files: ["path/to/file_1.pdf", "path/to/file_2.pdf"],
pdfa: PdfFormat.A_2b,
pdfUA: true,
});
This method interacts with PDF Engines merge route which gathers different engines that can manipulate and merge PDF files such as: PDFtk, PDFcpu, QPDF, and UNO.
import { PDFEngines } from "chromiumly";
const buffer = await PDFEngines.merge({
files: ["path/to/file_1.pdf", "path/to/file_2.pdf"],
pdfa: PdfFormat.A_2b,
pdfUA: true,
});
This method reads metadata from the provided PDF files.
import { PDFEngines } from "chromiumly";
const metadataBuffer = await PDFEngines.readMetadata([
"path/to/file_1.pdf",
"path/to/file_2.pdf",
]);
This method writes metadata to the provided PDF files.
import { PDFEngines } from "chromiumly";
const buffer = await PDFEngines.writeMetadata({
files: [
"path/to/file_1.pdf",
"path/to/file_2.pdf",
],
metadata: {
Author: 'Taha Cherfia',
Tite: 'Chromiumly'
Keywords: ['pdf', 'html', 'gotenberg'],
}
});
Please consider referring to ExifTool for a comprehensive list of accessible metadata options.
It is just a generic complementary method that takes the buffer
returned by the convert
method, and a
chosen filename
to generate the PDF file.
Please note that all the PDF files can be found __generated__
folder in the root folder of your project.
The following is a short snippet of how to use the library.
import { PDFEngines, UrlConverter } from "chromiumly";
async function run() {
const urlConverter = new UrlConverter();
const buffer = await urlConverter.convert({
url: "https://gotenberg.dev/",
});
await PDFEngines.generate("gotenberg.pdf", buffer);
}
run();