This is the TypeScript version of the Deuterium library.
Deuterium is a "document as code" library, which allows you to create format-independent documents, which then are converted into a specific format using the three components DocFrame, docPIPE and docTYPE.
The following output formats are supported:
- HTML
- PDF (including PDF/UA support)
- Plaintext
- Images (BMP, PNG and more)
- PostScript
Before using the library, you need to configure your docPIPE API connection. Create a .env file in your project root:
cp .env.example .envThen edit the .env file and set your docPIPE API credentials:
# The URL of your docPIPE API server
DOCPIPE_URL=http://localhost:8080
# Your docPIPE API authentication token
DOCPIPE_TOKEN=your-token-hereNote: The .env file is already included in .gitignore to prevent accidentally committing sensitive credentials.
This is a small example creating a document with the content "Hello World" as PDF:
import * as fs from "fs";
import Deuterium from "ts-d2";
new Deuterium.Content.Document("Hello World")
.convertTo(Deuterium.Output.OutputFormat.PDF)
.then(async (buffer) => {
// save blob to file
fs.writeFileSync("output.pdf", Buffer.from(await buffer.arrayBuffer()));
});Both convertTo and convertToPDF accept an optional jobParams argument — a free-form object that is merged into the request metadata sent to the docPIPE server:
new Deuterium.Content.Document("Hello World")
.convertTo(Deuterium.Output.OutputFormat.PDF, undefined, { locale: "en-US" })
.then(async (buffer) => {
fs.writeFileSync("output.pdf", Buffer.from(await buffer.arrayBuffer()));
});These job parameters are available in docPIPE as job variables.
By default, the library uses the connection credentials from your .env file. If you need to use different credentials for a specific conversion, you can create a custom Connection instance:
import Deuterium from "ts-d2";
// Create a custom connection with different credentials
const customConnection = new Deuterium.Connection(
"https://api.example.com",
"custom-token-here"
);
// Use the custom connection for conversion
const doc = new Deuterium.Content.Document("Hello World");
customConnection.convertTo(Deuterium.Output.OutputFormat.PDF, doc)
.then(async (buffer) => {
fs.writeFileSync("output.pdf", Buffer.from(await buffer.arrayBuffer()));
});Documents are divided into DocumentElements, which are the smallest part of a document (like text, vertical space, etc.).
DocumentElements also may be branch elements and therefore have child-elements (like tables, paragraphs, etc.).
DocumentElements may be grouped together to a document, which then may be converted to the desired output format.
All the supported DocumentElements are placed in the package Deuterium.Content.
Leaf elements have no children. The following leaf elements are supported:
- Barcode -- renders a barcode (QR, Code128, etc.) with configurable position, size and rotation
- Linebreak -- inserts a line break
- Image -- embeds an image with support for scaling, cropping, flipping, rotation and absolute positioning
- Pagebreak -- inserts a page break
- Rule -- draws a horizontal or vertical line with configurable style (solid, dashed, dotted, double, etc.), color and thickness
- SpaceVertically -- inserts vertical whitespace of a given height
- Tag -- inserts a named tag with optional parameters
- Text -- renders a plain text string
- Variable -- inserts a dynamic variable (data path, page number, date, etc.)
Any leaf element may be added to multiple branch elements (there is no connection from a leaf element to its parent element).
To create a text element you may use the following code:
new Deuterium.Content.Text("Hello World!")The text may then be added to any branch element.
When creating branch elements, you may also pass strings directly in order to create a text element.
new Deuterium.Content.Span("Hello World!", {
bold: true
});new Deuterium.Content.Image({
/* Currently only images located on the docPIPE server are supported. */
src: "logo.png",
alt: "Company Logo",
width: new Deuterium.Measure.AbsoluteMeasure(200, "pt"),
height: new Deuterium.Measure.AbsoluteMeasure(100, "pt"),
scaleType: "absolute",
});Variables can display dynamic data or special values like page numbers:
// Data variable
new Deuterium.Content.Variable({ path: "customer.name" });
// Page number
new Deuterium.Content.Variable({ specialType: "cur-page" });
// Total page count
new Deuterium.Content.Variable({ specialType: "page-count" });new Deuterium.Content.Rule({
width: new Deuterium.Measure.AbsoluteMeasure(400, "pt"),
thickness: new Deuterium.Measure.AbsoluteMeasure(1, "pt"),
color: Deuterium.Color.Colors.black,
style: "solid",
});import Proto from "docframe-types";
new Deuterium.Content.Barcode({
type: Proto.ProtoBarcodeType.QRCODE,
data: "https://example.com",
x: new Deuterium.Measure.AbsoluteMeasure(0, "pt"),
y: new Deuterium.Measure.AbsoluteMeasure(0, "pt"),
width: new Deuterium.Measure.AbsoluteMeasure(100, "pt"),
height: new Deuterium.Measure.AbsoluteMeasure(100, "pt"),
referencePoint: "top-left",
rotation: 0,
positionAbsolute: false,
});Branch elements have two functionalities:
- Group elements together (like Directory)
- Apply formatting/properties to their child elements.
The following branch elements are supported:
- AdjustHorizontally -- adjusts font size within min/max bounds to fit content horizontally
- AdvancedIllustrationArea -- a positioned area for illustrations with text flow control
- CarryOver -- defines content carried over when a table breaks across pages
- Condition -- conditionally includes content based on a code expression
- Directory -- groups elements with optional name, editability and semantic type
- Document -- the root element; holds page/column definitions, paragraph formats and all content
- Footer -- defines page footer content with configurable mode (append, extend, replace)
- Header -- defines page header content with configurable mode (append, extend, replace)
- Indentation -- applies left/right indentation to its children
- Link -- wraps content in a hyperlink
- Loop -- iterates over a data path, rendering children for each entry
- LoopEntry -- represents a single entry inside a Loop
- PageCondition -- conditionally includes content evaluated per page
- Paragraph -- groups inline content under a named paragraph format with optional overrides
- Section -- defines a document section, optionally with its own column definition
- Selection -- groups selectable entries (single or multi-select)
- SelectionEntry -- a single option inside a Selection
- Span -- applies inline formatting (bold, italic, underline, strikethrough, color, sub/superscript)
- SubTotal -- defines a sub-total area for tables (e.g. running totals)
- Table -- a table element with configurable width, offset and repeating headers
- TableCell -- a table cell with alignment, background color, borders, padding, margin and rotation
- TableContentGroup -- groups table rows (e.g. header group, body group, footer group)
- TableRow -- a table row with optional minimum height
- WsArea -- wraps content to control widow/orphan and page-split behavior
When creating branch document elements, the first parameter is the so called "content" parameter, which is used to define the child elements of the new branch document element.
The content parameter may be one of the following:
- string -> Creates a Text Document Element for the given string
- DocumentElement -> Just uses the passed DocumentElement
- (DocumentElement | string)[] -> Uses all the passed DocumentElements (and converts passed strings to Text objects)
Especially the first variant of the content parameter can result in small code:
new Deuterium.Content.Footer("...");new Deuterium.Content.Span("Important!", {
bold: true,
italic: true,
color: Deuterium.Color.Color.rgb(255, 0, 0),
underline: true,
});new Deuterium.Content.Link("Click here", "https://example.com");new Deuterium.Content.Table(
new Deuterium.Content.TableRow([
new Deuterium.Content.TableCell("Column 1", {
border: new Deuterium.Border.SideBorders({
bottom: new Deuterium.Border.Border(
new Deuterium.Measure.AbsoluteMeasure(1, "pt"),
Deuterium.Color.Colors.black,
),
}),
}),
new Deuterium.Content.TableCell("Column 2"),
]),
{ repeatHeader: 1 },
);new Deuterium.Content.Header("Page header content", { mode: "replace" });
new Deuterium.Content.Footer("Page footer content", { mode: "append" });new Deuterium.Content.Condition(
"This is only shown when the condition is true",
{ code: "data.showSection === true", result: true },
);new Deuterium.Content.Loop(
new Deuterium.Content.Variable({ path: "item.name" }),
{ path: "items" },
);new Deuterium.Content.Indentation(
"This text is indented",
{ left: new Deuterium.Measure.AbsoluteMeasure(30, "pt") },
);In addition to the document elements, the library provides several support classes:
- Deuterium.Alignment -- predefined horizontal (Left, Center, Right, Justify, FullJustify) and vertical (Top, Middle, Bottom) alignment values
- Deuterium.Border --
Border(weight + color) andSideBorders(top/right/bottom/left) - Deuterium.Color --
Color.rgb(),Color.cmyk(),Color.fromHex()factory methods and presetColors(black, white) - Deuterium.Font --
Fontclass andStandardFonts(Helvetica) - Deuterium.Measure --
AbsoluteMeasure(pt, cm, mm, in, px),Measure(also supports %),SideMeasuresandSides - Deuterium.ParagraphFormat -- defines named paragraph formats with font, size, line feed, spacing, alignment, bold/italic and indentation
For page-based output formats (PDF, PostScript), you can configure page size and column layout:
const doc = new Deuterium.Content.Document("Content", {
pageDefinition: new Deuterium.Content.PageDefinition(
new Deuterium.Measure.AbsoluteMeasure(595, "pt"),
new Deuterium.Measure.AbsoluteMeasure(842, "pt"),
),
columnDefinition: new Deuterium.Content.ColumnDefinition({
position: Deuterium.Content.ColumnPosition.Center,
interColumnSpace: new Deuterium.Measure.AbsoluteMeasure(0, "pt"),
positionOffset: new Deuterium.Measure.AbsoluteMeasure(70, "pt"),
width: new Deuterium.Measure.AbsoluteMeasure(490, "pt"),
}),
});Predefined page sizes are available via PageDefinitions (A3, A4, A5) and column presets via ColumnDefinitions.
Contributions to this project are very welcome. If you want to contribute, please create a pull request with your changes and a description of what you have done.
To build the project, you need to have Node.js and npm installed. Then you can run the following command in the project directory:
npm ci
npm run buildTo run the tests, you can use the following command:
npm run test