Types
types
PdfEngineOptions
type PdfEngineOptions = {
/** How much more a pdf being read as it downloads is pulled in before the
* reader looks again for the page it wants */
chunk_size: Bytes
/** The bleed a page is rasterized with round its trim: a raster is the trim
* grown by it, whatever the page's own boxes say */
file_bleed: Margins<Distance>
/** Directory path for file caching */
file_cache: string
/** DPI for rasterizing PDF pages */
image_dpi: Pixel
/** Longest edge of a rasterized page, in pixels: lowers image_dpi for pages
* that would exceed it. Past ~2k a page preview costs memory and upload time
* for detail no screen shows (300dpi A4 is 2480x3508).
*/
max_size: Pixel
/** Stroke width for vector rendering */
stroke_width: Distance
/** Chunk size for tracking operations */
tracking_chunk_size: Bytes
/** Unit to pixel conversion factor */
unit_to_px: Pixel
}PDF engine configuration options โ defaults in CreatePdfEngineOptions.
PageOrder
type PageOrder = { page_order: number }BinaryPagePdf
type BinaryPagePdf = Omit<SinglePageTask, "colors" | "transparency"> & {
colors?: string[]
enum: VirtualFileType.BINARY_PAGE_PDF
page_count: PageNumber
page_number: PageNumber
source: VirtualFile
source_page: PageNumber
transparency?: boolean
} & MetaFile &
PageOrderMultiPagePdf
type MultiPagePdf = {
content?: RemoteFile
enum: VirtualFileType.MULTI_PAGE_PDF
pages: SinglePagePdf[]
} & MetaFilePlottedPagePdf
type PlottedPagePdf = {
content?: RemoteFile
context: FilePlottingContext
enum: VirtualFileType.PLOTTED_PAGE_PDF
guid: StringGUID
page: Page
page_count: PageNumber
page_number: PageNumber
} & Media &
MetaFile &
PageOrderRemoteFile
type RemoteFile = {
enum: VirtualFileType.REMOTE_FILE
guid: StringGUID
// What the bytes behind the mirrors are, when somebody has already looked:
// a file written by this engine knows its own size, etag and write time, a
// url somebody pasted knows none of it until it is fetched. Absent or whole
// โ never half of it, so a reader that has it needs nothing else.
info?: FileInfo
mirrors: string[]
type: ContentType
} & MetaFileSinglePageImage
type SinglePageImage = SinglePageTask & {
dpi: Pixel
enum: VirtualFileType.SINGLE_PAGE_IMAGE
source: SinglePagePdf
} & MetaFileZipFile
type ZipFile = {
content?: RemoteFile
enum: VirtualFileType.ZIP_FILE
files: Record<FileName, VirtualFile>
} & MetaFileGeneratedContent
type GeneratedContent = Partial<MetaFile> & {
type: ContentType
emit?: (task: TrackingStatus) => void
guid?: StringGUID
}What has to be settled about content before it is written: what it is, who hears about a write worth waiting for, and what it will be called.
The name is the one thing a caller may already know โ a task names what it produces after the file it makes (see FileContentGUID), so a re-run lands the bytes back where every reference to them still points. A caller with nothing to name it by leaves it out and gets a uuid.
MetaFile
type MetaFile = {
file_meta: Record<string, string>
}SinglePagePdf
type SinglePagePdf = BinaryPagePdf | PlottedPagePdf
SinglePageTask
type SinglePageTask = {
content: RemoteFile
// what the page draws with: rgb/cmyk/gray/lab and spot colorants by name โ
// a plot's, the colors it sets and its media's as split reads them
colors: string[]
// whether anything it draws is transparent: a color below full alpha, or a
// media placed that is
transparency: boolean
} & MediaVirtualFile
type VirtualFile = BinaryPagePdf | MultiPagePdf | PlottedPagePdf | RemoteFile | SinglePageImage | ZipFile
NetworkTrackingCallback
type NetworkTrackingCallback = (info: { done: number; total: number }) => voidCallback for tracking network transfer progress.
Receives current progress info (bytes done and total).
import type { NetworkTrackingCallback } from "@pdfking/pdfengine"
const track: NetworkTrackingCallback = ({ done, total }) => {
console.log(`${done}/${total} bytes`)
}
track({ done: 512, total: 1024 }) // 512/1024 bytesNetworkProgress
type NetworkProgress = {
download?: NetworkTrackingCallback
upload?: NetworkTrackingCallback
}Progress tracking configuration for network requests.
Optional callbacks for monitoring upload and download progress.
import type { NetworkProgress } from "@pdfking/pdfengine"
import { ProgressFetch } from "@pdfking/pdfengine"
const progress: NetworkProgress = {
download: ({ done, total }) => console.log(`Downloaded: ${done}/${total}`)
}
await (await ProgressFetch("data:text/plain,hello", progress)).text() // "hello"Matrix
type Matrix<T extends number> = [number, number, number, number, T, T]
An affine transform in PDF's own layout, [a b c d e f]:
x' = aยทx + cยทy + e
y' = bยทx + dยทy + f
The same six numbers PDF's cm, SVG's matrix() and IDML's ItemTransform
take, so every backend can hand one straight to its output.
T is the unit the transform moves things in โ Matrix<Distance> in the
plot's own space, Matrix<Pixel> once a backend has converted. Only e and
f carry it: aโd scale and turn, so they are ratios, and a Distance
times one of them is still a Distance. Writing them as T too would be a
lie the compiler cannot catch, which is exactly the mistake this type exists
to prevent.
Layer
type Layer = {
/** shown when the pdf opens */
visible: boolean
printable: boolean
name?: string
locked: boolean
idml_color?: string
idml_merge_with?: LayerID
}ExtendedColor
type ExtendedColor = Color & {
idml_model?: "Process" | "Spot" | "Registration"
idml_reserved?: "Paper" | "Black" | "Registration" | "Cyan" | "Magenta" | "Yellow"
// A pdf plots it as an ink of its own, a Separation of this name, its CMYK
// only what shows wherever the ink is not. Apart from `idml_model`: a Spot
// swatch drawn on a printed layer must stay process in the pdf.
spot_name?: string
}PageNumber
type PageNumber = Float<"PageNumber", "i64">
ColorID
type ColorID = String<"ColorID">
PathPoint
type PathPoint<T = Distance> = Point<T> & {
before: Point<T>
after: Point<T>
}A path's anchor and the Bรฉzier handles of the segments either side of it:
before pulls the segment arriving, after the one leaving. Both are
absolute points in the anchor's own space, not offsets; a handle on its
anchor pulls nothing, and a segment with both of its handles on their
anchors is a straight line.
Media
type Media<T = Distance> = {
trim: Rectangle<T>
bleed: Margins<T>
}A page as whoever places it sees it, the same shape a plotted page has: its TrimBox โ the graphic and the cut โ and the bleed round it, each edge by its own. An uploaded page's bleed is how far its MediaBox reaches past the trim; a raster's is what it was drawn with. Where the boxes sit in the pdf stays with pdfium, which reads them off the page itself.
GroupTransform
type GroupTransform = Partial<{
origin: Point<Distance>
rotation: Degree
scale: Point<Percentage>
translate: Point<Distance>
}>A transform as an author spells it, for GroupMatrix to turn into a
matrix: whatever it leaves out is the identity.
LayerMap
type LayerMap = Record<LayerID, Layer>
ColorMap
type ColorMap = Record<ColorID, ExtendedColor>
MediaEntry
type MediaEntry = {
matrix: Matrix<Distance>
}What a file_map entry carries besides its page: the file's own matrix,
how the caller scales a file into every box it fills. Written about the
page's centre โ the origin is the centre of whichever box shows it โ and
applied before the media's own media_matrix.
LayerID
type LayerID = String<"LayerID">
RequestRaster
type RequestRaster = ( filename: FileName, page_number: PageNumber ) => Promise<string | undefined>
PDFReaderOptions
type PDFReaderOptions = {
// how much more a reader that reads as the bytes arrive pulls in before it
// looks again
chunk_size: Bytes
icc?: string
password?: string
size: Bytes
stream: StreamInput
type: string
}BasePlotObjectData
type BasePlotObjectData = {
layer: LayerID
}PrintLayer
type PrintLayer = EnumUnion<{
overlay: {
order: number
guide_color?: CMYKColor
print_color: CMYKColor
print_roughness?: number
}
print: {
order: number
}
// Covers the whole sheet (lamination): drawn from no file, the media's own
// extent is the mask.
coating: {
order: number
print_color: CMYKColor
print_roughness?: number
}
}>PDFConvertFunction
type PDFConvertFunction = ( input: PDFReaderOptions, resolution: Pixel ) => Promise<Required<PDFSplitResult>>
PlotPath
type PlotPath = EnumType<
PlotFunction.PLOT_PATH,
ConcretePlotObjectData & {
closed: boolean
points: PathPoint[]
}
>CompletePage
type CompletePage = Readonly<
{
/** How far the page is plotted beyond its box, side by side. */
bleed: Margins<Distance>
shapes: PlotShape[]
} & SpatialRectangle<Distance>
>PlotRect
type PlotRect = EnumType<
PlotFunction.PLOT_RECT,
ConcretePlotObjectData & {
position: SpatialRectangle<Distance>
}
>PDFSplitResult
type PDFSplitResult = {
stream: StreamInput
// what the page draws with: rgb/cmyk/gray/lab and spot colorants by
// name, each once โ only a backend that reads the content knows
colors?: string[]
// whether anything it draws is transparent: without, gs -dNOTRANSPARENCY
// draws it the same โ known as colors is
transparency?: boolean
} & Media<Pixel>PlotGroup
type PlotGroup = EnumType<
PlotFunction.PLOT_GROUP,
Omit<BasePlotObjectData, "layer"> & {
matrix: Matrix<Distance>
shapes: PlotShape[]
}
>An affine transform around a list of shapes โ the only way anything rotates, scales or moves as a unit.
matrix maps a point of a child, written in the group's own coordinates,
into the space the group sits in. Groups nest: a child group's matrix
applies before its parent's. Build one with GroupMatrix.
No layer: each child keeps its own, so one group may span layers.
PDFPageMeta
type PDFPageMeta = Media<Pixel> & {
colors?: string[]
transparency?: boolean
page_number: PageNumber
page_count: PageNumber
}ConcretePlotObjectData
type ConcretePlotObjectData = BasePlotObjectData & {
fill_color: ColorID
stroke_color: ColorID
stroke_width: Distance
}PlottingContext
type PlottingContext<T = unknown> = {
color_map: ColorMap
/** Media pages by `PlotMedia.filename` then `page_number`. A missing page
* plots blank. */
file_map: Record<FileName, Record<PageNumber, T>>
font_family: string
font_size: Pixel
horizontal_align: HorizontalAlign
image_dpi: Pixel
layer_map: LayerMap
page_bleed: Margins<Distance>
stroke_width: Distance
unit_to_px: Pixel
vertical_align: VerticalAlign
}PDFMediaEntry
type PDFMediaEntry = MediaEntry & { stream: StreamInput }A media page as the PDF plotters read it: the single-page PDF stream and the file's matrix.
PlotText
type PlotText = EnumType<
PlotFunction.PLOT_TEXT,
ConcretePlotObjectData & {
font_name: string
font_size: Pixel
horizontal_align: HorizontalAlign
position: SpatialRectangle<Distance>
text: string
text_color: ColorID
vertical_align: VerticalAlign
}
>PageShape
type PageShape = PlotShape extends infer T
? T extends PlotGroup
? Partial<Omit<PlotGroup, "shapes">> & Pick<PlotGroup, "enum"> & { shapes: PageShape[] }
: T extends PlotShape
? Partial<T> & Pick<T, "enum">
: never
: neverA shape with only its enum required: whatever it leaves out is completed
with the defaults when the page is plotted. A group's children likewise.
PlotMedia
type PlotMedia = EnumType<
PlotFunction.PLOT_MEDIA,
BasePlotObjectData & {
media_matrix: Matrix<Distance>
position: SpatialRectangle<Distance>
mask: Margins<Distance>
filename: FileName
page_number: PageNumber
print_layer: PrintLayer
}
>A page of a source file placed in a box.
The source page's trim box centre lands on the position centre, and the
page then goes through media_matrix, written in the same space position
is. That is how the page is scaled, turned, mirrored or moved inside its box.
mask is what stays visible: position grown per edge, signed โ positive
shows the page beyond its box (bleed), negative crops it. The mask belongs
to the box, not to the page: media_matrix moves the page under it and
leaves it where it is.
filename and page_number look the page up in the context's file_map.
PlotShape
type PlotShape = PlotGroup | PlotMedia | PlotPath | PlotRect | PlotText
PDFPlotRaster
type PDFPlotRaster = {
dpi: Pixel
bleed: Margins<Pixel>
}A plot drawn straight to pixels instead of written as a pdf: at dpi, over
the trim grown by bleed whatever the page's own bleed.
PDFMergeInput
type PDFMergeInput = PDFReaderOptions & { meta: PDFPageMeta }PDFSplitFunction
type PDFSplitFunction = ( input: PDFReaderOptions, rangeFn?: (page_count: number) => Sequence<number> ) => AsyncGenerator<PDFSplitResult>
PDFMergeFunction
type PDFMergeFunction = (pages: AsyncSequence<PDFMergeInput>) => AsyncGenerator<StreamInput>
PDFPlotResult
type PDFPlotResult = {
stream: StreamInput
type: ContentType.PDF | ImageContentType
colors: string[]
transparency: boolean
}A plotted page: its single-page PDF โ or, plotted with a raster, its image in the format the platform's encoder wrote (webp in the browser, png on node) โ and what it draws with: rgb/cmyk for the colors set and the colors of the media placed, each once; and whether any of it is transparent, a color below full alpha or a media placed that is.
Page
type Page = Readonly<
Partial<
{
bleed: Margins<Distance>
/** The page's identity, when the caller already knows it: the engine
* keys the plot on it instead of hashing the whole page and its context.
* It must change whenever anything that draws the page does. */
page_id: StringGUID
shapes: PageShape[]
} & SpatialRectangle<Distance>
>
>PDFPlotFunction
type PDFPlotFunction<T = PDFMediaEntry, R = PDFPlotResult> = ( pages: CompletePage[], context: PlottingContext<T>, raster?: PDFPlotRaster ) => AsyncGenerator<R>
FileIdmlPlottingContext
type FileIdmlPlottingContext = Expand<Partial<Parameters<typeof IDMLPlot>[1]>>
FileMediaEntry
type FileMediaEntry = MediaEntry & { page: SinglePagePdf }A media page as the engine plots it: the split page, fetched only when a plotted media references it, and the file's matrix.
FilePlottingContext
type FilePlottingContext = Expand<Partial<PlottingContext<FileMediaEntry>>>
PlotSpec
type PlotSpec = Readonly<[Page, FilePlottingContext?]>
methods
PlannedFile
type PlannedFile = Exclude<VirtualFile, RemoteFile>
Every file but a url has a plan: a url is only ever read.
FilePlanOutput
type FilePlanOutput<F extends PlannedFile> = F extends MultiPagePdf | ZipFile
? RemoteFile
: F extends PlottedPagePdf | SinglePageImage
? SinglePageTask
: FWhat a file's plan yields: a merge or a zip its bytes, a plot or an image the page task holding them (a plot's with the colors it plotted), a split page itself.
engine
PdfEngine
type PdfEngine = {
config: PdfEngineOptions
CreateRemoteFile: (file: Partial<RemoteFile>) => RemoteFile
GenerateFile: (stream: StreamInput, content: GeneratedContent) => Promise<RemoteFile>
MergePdf: (files: Sequence<VirtualFile | PlotSpec>) => Promise<MultiPagePdf>
PlotIdml: (plots: Page[], context?: Partial<FileIdmlPlottingContext>) => Promise<RemoteFile>
PlotPdf: (plot: Page, context?: Partial<FilePlottingContext>) => Promise<PlottedPagePdf>
RasterizePdf: (files: Sequence<VirtualFile>) => AsyncGenerator<SinglePageImage>
RequestFile: (
file: VirtualFile,
emit?: (status: TrackingStatus) => void
) => Promise<StandardResponse>
SplitPdf: (files: Sequence<VirtualFile>) => AsyncGenerator<SinglePagePdf>
ZipFiles: (files: Sequence<[string, VirtualFile]>) => Promise<ZipFile>
}