- Introduction
- Motivations
- Supported versions
- Prerequisites
- Installation
- Installation options
- Usage
- API
- Security
- Development
- Troubleshooting
- Docker
- Code of conduct
- Team
- Acknowledgements
- License
Ghostscript is a suite of software based on an interpreter for Adobe Systems' PostScript and Portable Document Format (PDF) page description languages. Its main purposes are the rasterization or rendering of such page description language files, for the display or printing of document pages, and the conversion between PostScript and PDF files.
Ghostscript can be used as a raster image processor (RIP) for raster computer printers, for instance as an input filter of a line printer daemon, or as the RIP engine behind PostScript and PDF viewers.
Ghostscript can also be used as a file format converter, such as a PostScript to PDF converter. The ps2pdf conversion program, which comes with the Ghostscript distribution, is described by its documentation as a "work-alike for nearly all the functionality (but not the user interface) of Adobe's Acrobat Distiller product". This converter is basically a thin wrapper around Ghostscript's pdfwrite output device, which supports PDF/A and PDF/X output.
Ghostscript can also serve as the back-end for PDF to raster image (png, tiff, jpeg, etc.) converters; this is often combined with a PostScript printer driver in "virtual printer" PDF creators.
As it takes the form of a language interpreter, Ghostscript can also be used as a general purpose programming environment.
When I created this module I was not able to find any module on npm that executes Ghostscript commands through its C API; the existing modules called Ghostscript by executing the corresponding shell command. This is a good way to start using a library from Node.js, but it has the following drawbacks:
-
Performance - Calling a shell command takes more time and more resources than calling a C or C++ API directly from Node.js.
-
Error handling - Sometimes you cannot intercept and handle errors in a good and proper way.
To fit all needs Ghostscript4JS has sync and async methods, so it can be used in a web application where it's very important to not block the event loop, so all requests will be served without any delay originated by your application.
Understanding Node.js event loop
| Component | Supported versions |
|---|---|
| Ghostscript | from 9.19 to 10.08 |
| Node.js | 20 or later |
| Operating systems | Linux, macOS and Windows (x64 and arm64) |
The supported Ghostscript range is also exposed at runtime by the
MIN_SUPPORTED_REVISION and MAX_SUPPORTED_REVISION properties. Ghostscript encodes
its version as a revision number: for example version 10.08.0 has revision 10080.
Before installing Ghostscript4JS make sure you have the following prerequisites:
-
Node.js 20 or later, see: Installing Node.js via package manager
-
Ghostscript with its shared library for your operating system, as described below.
On the most common platforms the installation downloads a prebuilt binary of the addon. Otherwise the
native addon is compiled during installation by Marmotta, which uses
Zig as compiler toolchain, so Python, make or a C++ compiler are not required. If Zig is not
available on PATH, Marmotta downloads it automatically. When downloads are not allowed, set the environment variable
MARMOTTA_ZIG_DIR to the folder of an existing Zig installation.
Install Ghostscript and its development package, then set GS4JS_HOME to the folder containing libgs.so
when it is not the default /usr/lib/x86_64-linux-gnu. The development package and GS4JS_HOME are needed only to
build the addon: the prebuilt binaries only need the Ghostscript library, for example the libgs10 package on Debian
and Ubuntu or the ghostscript package on Alpine.
| Distribution | Install command | GS4JS_HOME |
|---|---|---|
| Debian / Ubuntu (x64) | apt-get install ghostscript libgs-dev |
not needed |
| Debian / Ubuntu (arm64) | apt-get install ghostscript libgs-dev |
/usr/lib/aarch64-linux-gnu |
| Red Hat / Fedora | dnf install ghostscript ghostscript-devel |
/usr/lib64 |
| Arch Linux | pacman -S ghostscript |
/usr/lib |
| Alpine | apk add ghostscript ghostscript-dev |
/usr/lib |
In general, set GS4JS_HOME to the folder containing the libgs.so library for your distribution and architecture.
-
Download the latest Ghostscript release for your platform from the official download page.
-
Install Ghostscript. By default the installer uses a folder like
C:\Program Files\gs\gs10.08.0. -
Set the environment variable GS4JS_HOME to the
binfolder of your Ghostscript installation, which containsgsdll64.dllandgsdll64.lib, for exampleC:\Program Files\gs\gs10.08.0\bin. It is not needed when Ghostscript is installed inC:\gs, becauseC:\gs\binis the default.
During the build the Ghostscript DLL is copied next to the addon, so it is found at runtime without changing PATH.
-
Install Homebrew following the official guide.
-
Install Ghostscript:
brew install ghostscriptThe library is found automatically in /usr/local/lib or in the Homebrew installation of Ghostscript. If it is installed
elsewhere, set GS4JS_HOME to the folder containing libgs.dylib, for example:
export GS4JS_HOME="$(brew --prefix ghostscript)/lib"npm install ghostscript4jsGhostscript must be installed first. The installation uses a prebuilt binary when one is available for the platform, and otherwise builds the addon from source.
Each release includes prebuilt binaries of the addon. During the installation the binary for the current platform is downloaded from the GitHub release of the installed version and loaded once to check that it works with the installed Ghostscript. The binaries contain only the addon: Ghostscript is not included.
| Platform | Requirements |
|---|---|
| Linux x64 and arm64 with glibc | glibc 2.28 or later and the Ghostscript 10 library (libgs.so.10) |
| Linux x64 and arm64 with musl, such as Alpine | the Ghostscript 10 library (libgs.so.10) |
| macOS x64 and arm64 | macOS 13 or later and libgs.dylib in /opt/homebrew/lib, /usr/local/lib or /opt/local/lib, as installed by Homebrew or MacPorts |
| Windows x64 | gsdll64.dll in the GS4JS_HOME folder (C:/gs/bin by default), which is copied next to the addon |
The addon is built from source, as described in Prerequisites, when:
- there is no binary for the platform, or it cannot be downloaded;
- the binary cannot be loaded, for example because Ghostscript is not installed or, on Linux, its version is 9;
- GS4JS_BUILD_FROM_SOURCE or npm's
--build-from-sourceoption is set; - GS4JS_LIB or GS4JS_DLL is set, because they choose the library to link;
- the package is installed from a clone of the repository.
Run npm install --foreground-scripts to see whether the prebuilt binary was used and, if not, why.
The following options change how the addon is installed and where the Ghostscript library is searched during the build.
Each option can be passed to npm install or set as an environment variable with the same name; the environment
variable is used when both are set.
| Option | Description | Default |
|---|---|---|
| GS4JS_HOME | Folder containing the Ghostscript library | Linux: /usr/lib/x86_64-linux-gnuWindows: C:/gs/binmacOS: detected automatically |
| GS4JS_LIB | File name of the Ghostscript library | Linux: libgs.soWindows: gsdll64.lib (gsdll32.lib on 32-bit)macOS: libgs.dylib |
| GS4JS_DLL | File name of the Ghostscript DLL, only on Windows | gsdll64.dll (gsdll32.dll on 32-bit) |
| GS4JS_BUILD_FROM_SOURCE | Build the addon from source instead of downloading the prebuilt binary | not set |
| GS4JS_BINARY_HOST | URL the prebuilt binaries are downloaded from, for example a mirror of the GitHub releases. The binary is downloaded from <GS4JS_BINARY_HOST>/<version>/ghostscript4js-<version>-<platform>.node.gz |
https://github.com/NickNaso/ghostscript4js/releases/download |
For example:
npm install ghostscript4js --GS4JS_HOME="C:/Program Files/gs/gs10.08.0/bin"GS4JS_HOME=/usr/lib64 npm install ghostscript4js'use strict'
const gs = require('ghostscript4js')
try {
// Take decision based on Ghostscript version
const version = gs.version()
console.log(version)
gs.executeSync('-sDEVICE=pngalpha -o my.png -r144 my.pdf')
} catch (err) {
// Handle error
throw err
}version() returns an object that contains information about the version of the Ghostscript library installed on the system. It is useful when you have to take decisions based on different versions. The returned data is similar to the example below:
{
product: 'GPL Ghostscript',
copyright: 'Copyright (C) 2026 Artifex Software, Inc. All rights reserved.',
revision: 10080,
revisiondate: 20260908
}This is a synchronous method that returns the version info or throws an Error to indicate that something went wrong during its execution.
'use strict'
const gs = require('ghostscript4js')
try {
const version = gs.version()
console.log(version)
// Take decision based on Ghostscript version
if (version.revision >= 10000) {
// ... Ghostscript 10 or later
} else {
// ... other stuff
}
} catch (err) {
// Handle error
throw err
}executeSync(cmd) takes the Ghostscript command parameters as a string or an array of strings and executes them synchronously. If something goes wrong an Error with description and error code is thrown.
Use an array of strings when a parameter contains spaces, for example a file name, because a string is split on spaces.
'use strict'
const gs = require('ghostscript4js')
try {
gs.executeSync('-sDEVICE=pngalpha -o my.png -r144 my.pdf')
gs.executeSync(['-sDEVICE=pngalpha', '-o', 'my image.png', '-r144', 'my document.pdf'])
} catch (err) {
// Handle error
throw err
}execute(cmd, callback) takes the Ghostscript command parameters as a string or an array of strings and an optional callback. The execution is asynchronous, so it does not block the Node.js event loop: this is the method to use in a web application. If a callback is provided, a possible error is passed to it; otherwise the method returns a Promise that is resolved or rejected as shown in the following examples.
'use strict'
const gs = require('ghostscript4js')
const cmd = '-sDEVICE=pngalpha -o my.png -r144 my.pdf'
gs.execute(cmd, function (err) {
if (err) {
console.log("Ooops... something wrong happened")
}
})'use strict'
const gs = require('ghostscript4js')
const cmd = '-sDEVICE=pngalpha -o my.png -r144 my.pdf'
gs.execute(cmd)
.then(() => {
console.log("All is ok")
})
.catch((err) => {
console.log("Ooops... something wrong happened")
})The errors raised by ghostscript4js in all of its methods are instances of Error with a message that describes what happened and contains the Ghostscript error code, so you can inspect what happened in a better way. See Ghostscript return codes for the list of Ghostscript error codes.
By default Ghostscript tries to process damaged PDF files anyway: it substitutes missing fonts, repairs or ignores invalid
content and completes successfully, printing only a summary such as This file had errors that were repaired or ignored.
In that case no error is raised, exactly as the gs command line program exits with code 0.
To make the execution fail, and get an Error, pass one of these options to Ghostscript:
- -dPDFSTOPONERROR stops on errors in the PDF file, for example invalid operators in a page content.
- -dPDFSTOPONWARNING stops on warnings too. Since Ghostscript 10.07.0 this also covers the problems that Ghostscript repairs, such as a text object that is not closed; with earlier versions these problems are still ignored.
'use strict'
const gs = require('ghostscript4js')
gs.execute('-dPDFSTOPONERROR -sDEVICE=pngalpha -o my.png -r144 my.pdf')
.then(() => {
console.log("The PDF was processed without errors")
})
.catch((err) => {
console.log("The PDF is damaged:", err.message)
})This module is built on the Ghostscript C API, which is compatible with specific versions. The module has two properties, MIN_SUPPORTED_REVISION and MAX_SUPPORTED_REVISION, which respectively indicate the minimum and maximum supported Ghostscript revision (see Supported versions).
'use strict'
const gs = require('ghostscript4js')
console.log(gs.MIN_SUPPORTED_REVISION) // 919
console.log(gs.MAX_SUPPORTED_REVISION) // 10080
const { revision } = gs.version()
if (revision < gs.MIN_SUPPORTED_REVISION || revision > gs.MAX_SUPPORTED_REVISION) {
console.warn(`Ghostscript revision ${revision} has not been tested with ghostscript4js`)
}Ghostscript interprets PostScript and PDF, which are programming languages, so processing files from untrusted sources
is a risk. Keep Ghostscript updated, because new releases often fix security issues, and do not disable the SAFER mode,
which is enabled by default since Ghostscript 9.50 and restricts file system access from documents. Avoid the -dNOSAFER
option when you process files you do not control.
Clone the repository, install Ghostscript as described in Prerequisites and run:
npm install # installs the dependencies and builds the addon with Marmotta, never using a prebuilt binary
npm test # runs the test suite
npm run debug # rebuilds the addon without optimizations and with debug informationThe build is described in marmotta.config.js, and the addon is written to build/Release/ghostscript4js.node.
You can also call Marmotta directly, for example npx marmotta rebuild. See the
Marmotta documentation for all commands and options, such as
MARMOTTA_HOME to change where Zig and the temporary build files are stored.
Every pull request and every push to master are built and tested on Linux, macOS and Windows. When a release is
published, the Release workflow builds the prebuilt binaries, attaches them to the release as
ghostscript4js-<version>-<platform>.node.gz and then installs the package on each platform to check that they are
downloaded and loaded. The release tag must be the version in package.json, for example 3.3.0, because the
installation downloads the binaries from that tag. Publish the package to npm after the workflow has completed,
otherwise the first installations build the addon from source. The workflow can also be run manually to build and test
the binaries without a release.
-
Ghostscript library not foundduring the installation: the library is not in the folder used for the build. Set GS4JS_HOME (and GS4JS_LIB if the file name is different) as described in Installation options. -
The addon cannot be loaded on Linux with an error about
libgs.so: the Ghostscript shared library is not installed or not in the library search path. Install the Ghostscript library package of your distribution. -
The addon cannot be loaded on Windows: check that the Ghostscript DLL is in the
build/Releasefolder of the module. The DLL also needs the Microsoft Visual C++ Redistributable, which is installed together with Ghostscript. -
A damaged PDF file is processed without errors: Ghostscript repairs the file and completes successfully. Pass
-dPDFSTOPONERRORor-dPDFSTOPONWARNINGto get an error instead, as described in Damaged PDF files. -
Zig cannot be downloaded: install Zig separately and add it to
PATH, or set MARMOTTA_ZIG_DIR. -
The prebuilt binary cannot be downloaded, for example behind a proxy: the addon is built from source instead. Set GS4JS_BINARY_HOST to a mirror of the GitHub releases, or set GS4JS_BUILD_FROM_SOURCE to skip the download.
Check out the example Dockerfile in examples/docker. It creates an image based on Node.js 24 and Debian bookworm.
To build the image do:
cd examples/docker
docker build -t ghostscript4js .Now you can run the image. By default it does npm start (which is node index.js) and exits.
docker run ghostscript4jsRunning the container should output something like:
{
product: 'GPL Ghostscript',
copyright: 'Copyright (C) 2022 Artifex Software, Inc. All rights reserved.',
revision: 10000,
revisiondate: 20220921
}If you want to look around in the container you can get a shell like:
docker run -it ghostscript4js /bin/bash
gs --versionhttps://www.npmjs.com/~nicknaso
https://www.npmjs.com/~mauro-d
https://twitter.com/maurodoganieri
Thank you to all people that encourage me every day.
Licensed under Apache license V2
