From eacd5322d338cc4938c700c0cac0d61c7c7ebc9b Mon Sep 17 00:00:00 2001 From: Elvanos Date: Wed, 19 May 2021 13:38:32 +0200 Subject: [PATCH] PDFkit stupid types that bug like hell added --- .github/workflows/build.yml | 4 +- package-lock.json | 129 -------- package.json | 2 - quasar.conf.js | 32 -- src/components/dialogs/ExportProject.vue | 7 +- src/globals.d.ts | 2 +- src/interfaces/I_PDFKitDocument.ts | 372 +++++++++++++++++++++++ 7 files changed, 380 insertions(+), 168 deletions(-) create mode 100644 src/interfaces/I_PDFKitDocument.ts diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 274059c..a3e455b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -17,7 +17,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-18.04, windows-latest, macOS-latest] + os: [ubuntu-latest, windows-latest, macOS-latest] steps: - name: Check out the code @@ -33,7 +33,7 @@ jobs: npm run build - name: Upload Linux Artifact - if: ${{ matrix.os == 'ubuntu-18.04' }} + if: ${{ matrix.os == 'ubuntu-latest' }} uses: actions/upload-artifact@v2.2.3 with: # Artifact name diff --git a/package-lock.json b/package-lock.json index fdf36ab..27010a2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14544,86 +14544,6 @@ "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=" }, - "string-replace-webpack-plugin": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/string-replace-webpack-plugin/-/string-replace-webpack-plugin-0.1.3.tgz", - "integrity": "sha1-c8ZX51nWbP6Arh4M8JGqJW0OcVw=", - "requires": { - "async": "~0.2.10", - "css-loader": "^0.9.1", - "file-loader": "^0.8.1", - "loader-utils": "~0.2.3", - "style-loader": "^0.8.3" - }, - "dependencies": { - "async": { - "version": "0.2.10", - "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", - "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=" - }, - "big.js": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz", - "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==" - }, - "css-loader": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-0.9.1.tgz", - "integrity": "sha1-LhqgDOfjDvLGp6SzAKCAp8l54Nw=", - "optional": true, - "requires": { - "csso": "1.3.x", - "loader-utils": "~0.2.2", - "source-map": "~0.1.38" - } - }, - "csso": { - "version": "1.3.12", - "resolved": "https://registry.npmjs.org/csso/-/csso-1.3.12.tgz", - "integrity": "sha1-/GKGlKLTiTiqrEmWdTIY/TEc254=", - "optional": true - }, - "emojis-list": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", - "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=" - }, - "file-loader": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-0.8.5.tgz", - "integrity": "sha1-knXQMf54DyfUf19K8CvUNxPMFRs=", - "optional": true, - "requires": { - "loader-utils": "~0.2.5" - } - }, - "json5": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", - "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=" - }, - "loader-utils": { - "version": "0.2.17", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.17.tgz", - "integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=", - "requires": { - "big.js": "^3.1.3", - "emojis-list": "^2.0.0", - "json5": "^0.5.0", - "object-assign": "^4.0.1" - } - }, - "source-map": { - "version": "0.1.43", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", - "integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=", - "optional": true, - "requires": { - "amdefine": ">=0.0.4" - } - } - } - }, "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", @@ -14710,47 +14630,6 @@ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" }, - "style-loader": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-0.8.3.tgz", - "integrity": "sha1-9Pkut9tjdodI8VBlzWcA9aHIU1c=", - "optional": true, - "requires": { - "loader-utils": "^0.2.5" - }, - "dependencies": { - "big.js": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz", - "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==", - "optional": true - }, - "emojis-list": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", - "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=", - "optional": true - }, - "json5": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", - "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", - "optional": true - }, - "loader-utils": { - "version": "0.2.17", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.17.tgz", - "integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=", - "optional": true, - "requires": { - "big.js": "^3.1.3", - "emojis-list": "^2.0.0", - "json5": "^0.5.0", - "object-assign": "^4.0.1" - } - } - } - }, "stylehacks": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-4.0.3.tgz", @@ -15289,14 +15168,6 @@ "universalify": "^0.1.2" } }, - "transform-loader": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/transform-loader/-/transform-loader-0.2.4.tgz", - "integrity": "sha1-5ch4d7qW1R0/IlNoWHtG4ibRzsk=", - "requires": { - "loader-utils": "^1.0.2" - } - }, "truncate-utf8-bytes": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz", diff --git a/package.json b/package.json index 968416a..1b9cefb 100644 --- a/package.json +++ b/package.json @@ -32,8 +32,6 @@ "pouchdb-replication-stream": "^1.2.9", "quasar": "^1.15.0", "quasar-app-extension-qdraggabletree": "0.0.5", - "string-replace-webpack-plugin": "^0.1.3", - "transform-loader": "^0.2.4", "vue-apexcharts": "^1.6.0", "vue-class-component": "^7.2.2", "vue-codemirror": "^4.0.6", diff --git a/quasar.conf.js b/quasar.conf.js index 8166ca2..07724c0 100644 --- a/quasar.conf.js +++ b/quasar.conf.js @@ -8,7 +8,6 @@ /* eslint-env node */ /* eslint-disable @typescript-eslint/no-var-requires */ const { configure } = require("quasar/wrappers") -const StringReplacePlugin = require("string-replace-webpack-plugin"); module.exports = configure(function (ctx) { return { @@ -86,37 +85,6 @@ module.exports = configure(function (ctx) { } }) } - - cfg.module.rules.push({ - enforce: 'pre', - test: /unicode-properties[\/\\]unicode-properties/, - loader: StringReplacePlugin.replace({ - replacements: [ - { - pattern: "var fs = _interopDefault(require('fs'));", - replacement: function () { - return "var fs = require('fs');"; - } - } - ] - }) - }) - cfg.module.rules.push({test: /unicode-properties[\/\\]unicode-properties/, loader: "transform-loader?brfs"}) - cfg.module.rules.push({test: /pdfkit[/\\]js[/\\]/, loader: "transform-loader?brfs"}) - cfg.module.rules.push({test: /fontkit[\/\\]index.js$/, loader: "transform-loader?brfs"}) - cfg.module.rules.push({test: /linebreak[\/\\]src[\/\\]linebreaker.js/, loader: "transform-loader?brfs"} ) - - cfg.plugins = [ - ...cfg.plugins - ,new StringReplacePlugin() - ] - - cfg.resolve.alias = { - ...cfg.resolve.alias, - 'unicode-properties': 'unicode-properties/unicode-properties.cjs.js', - 'pdfkit': 'pdfkit/js/pdfkit.js' - } - } }, diff --git a/src/components/dialogs/ExportProject.vue b/src/components/dialogs/ExportProject.vue index f013bc4..13c1aac 100644 --- a/src/components/dialogs/ExportProject.vue +++ b/src/components/dialogs/ExportProject.vue @@ -240,7 +240,8 @@ import { remote } from "electron" import { retrieveCurrentProjectName } from "src/scripts/projectManagement/projectManagent" // @ts-ignore import json2md from "json2md/lib/index.js" -import PDFkit from "pdfkit" +// @ts-ignore +import PDFkit from "pdfkit/js/pdfkit.standalone.js" // @ts-ignore import htmlParseStringify from "html-parse-stringify/dist/html-parse-stringify.modern.js" import DialogBase from "src/components/dialogs/_DialogBase" @@ -251,6 +252,7 @@ import documentPreview from "src/components/DocumentPreview.vue" import { I_ExportObject } from "src/interfaces/I_ExportObject" import { I_ShortenedDocument } from "src/interfaces/I_OpenedDocument" import { I_Blueprint } from "src/interfaces/I_Blueprint" +import { I_PDFKitDocument } from "src/interfaces/I_PDFKitDocument" import { I_HtmlParserNode } from "src/interfaces/I_HtmlParserNode" import { advancedDocumentFilter } from "src/scripts/utilities/advancedDocumentFilter" @@ -845,7 +847,8 @@ export default class ExportProject extends DialogBase { paragraphGap: 8 } - const doc = new PDFkit({ size: "A4" }) + // eslint-disable-next-line @typescript-eslint/no-unsafe-call + const doc: I_PDFKitDocument = new PDFkit({ size: "A4" }) // Start stream doc.pipe(fs.createWriteStream(`${documentDirectory}/${exportFileName}.pdf`)) diff --git a/src/globals.d.ts b/src/globals.d.ts index 0bdda51..44e30ef 100644 --- a/src/globals.d.ts +++ b/src/globals.d.ts @@ -1,6 +1,6 @@ declare module "*.md"{ const content: string - export default content + export default content } declare module "*.png"{ diff --git a/src/interfaces/I_PDFKitDocument.ts b/src/interfaces/I_PDFKitDocument.ts new file mode 100644 index 0000000..c7a38f6 --- /dev/null +++ b/src/interfaces/I_PDFKitDocument.ts @@ -0,0 +1,372 @@ +export interface I_PDFKitDocument extends NodeJS.ReadableStream, + PDFAnnotation, + PDFColor, + PDFImage, + PDFText, + PDFVector, + PDFFont, + PDFAcroForm { + /** + * PDF Version + */ + version: number; + /** + * Wheter streams should be compressed + */ + compress: boolean; + /** + * PDF document Metadata + */ + info: DocumentInfo; + /** + * Options for the document + */ + options: PDFDocumentOptions; + /** + * Represent the current page. + */ + page: PDFPage; + + x: number; + y: number; + + addPage(options?: PDFDocumentOptions): I_PDFKitDocument; + bufferedPageRange(): { start: number; count: number }; + switchToPage(n?: number): PDFPage; + flushPages(): void; + ref(data: {}): PDFKitReference; + addContent(data: any): I_PDFKitDocument; + /** + * Deprecated + */ + write(fileName: string, fn: any): void; + /** + * Deprecated. Throws exception + */ + output(fn: any): void; + end(): void; + toString(): string; +} + +interface DocumentInfo { + Producer?: string; + Creator?: string; + CreationDate?: Date; + Title?: string; + Author?: string; + Keywords?: string; + ModDate?: Date; +} + +interface PDFDocumentOptions { + compress?: boolean; + info?: DocumentInfo; + userPassword?: string; + ownerPassword?: string; + permissions?: DocumentPermissions; + pdfVersion?: "1.3" | "1.4" | "1.5" | "1.6" | "1.7" | "1.7ext3"; + autoFirstPage?: boolean; + size?: number[] | string; + margin?: number; + margins?: { top: number; left: number; bottom: number; right: number }; + layout?: "portrait" | "landscape"; + + bufferPages?: boolean; +} + +interface DocumentPermissions { + modifying?: boolean; + copying?: boolean; + annotating?: boolean; + fillingForms?: boolean; + contentAccessibility?: boolean; + documentAssembly?: boolean; + printing?: "lowResolution" | "highResolution"; +} + +interface PDFPage { + size: string; + layout: string; + margins: { top: number; left: number; bottom: number; right: number }; + width: number; + height: number; + document: I_PDFKitDocument; + content: PDFKitReference; + + /** + * The page dictionnary + */ + dictionary: PDFKitReference; + + fonts: any; + xobjects: any; + ext_gstates: any; + patterns: any; + annotations: any; + + maxY(): number; + write(chunk: any): void; + end(): void; +} + +interface PDFKitReference { + id: number; + gen: number; + deflate: any; + compress: boolean; + uncompressedLength: number; + chunks: any[]; + data: { Font?: any; XObject?: any; ExtGState?: any; Pattern: any; Annots: any }; + document: I_PDFKitDocument; + + initDeflate(): void; + write(chunk: any): void; + end(chunk: any): void; + finalize(): void; + toString(): string; +} + +interface PDFAnnotation { + annotate(x: number, y: number, w: number, h: number, option: AnnotationOption): this; + note(x: number, y: number, w: number, h: number, content: string, option?: AnnotationOption): this; + goTo(x: number, y: number, w: number, h: number, name: string, options?: AnnotationOption): this; + link(x: number, y: number, w: number, h: number, url: string, option?: AnnotationOption): this; + highlight(x: number, y: number, w: number, h: number, option?: AnnotationOption): this; + underline(x: number, y: number, w: number, h: number, option?: AnnotationOption): this; + strike(x: number, y: number, w: number, h: number, option?: AnnotationOption): this; + lineAnnotation(x1: number, y1: number, x2: number, y2: number, option?: AnnotationOption): this; + rectAnnotation(x: number, y: number, w: number, h: number, option?: AnnotationOption): this; + ellipseAnnotation(x: number, y: number, w: number, h: number, option?: AnnotationOption): this; + textAnnotation(x: number, y: number, w: number, h: number, text: string, option?: AnnotationOption): this; +} + +interface AnnotationOption { + Type?: string; + Rect?: any; + Border?: Array; + SubType?: string; + Contents?: string; + Name?: string; + color?: string; + QuadPoints?: Array; + + A?: any; + B?: any; + C?: any; + L?: any; + DA?: string; +} +interface PDFColor { + fillColor(color: ColorValue, opacity?: number): this; + strokeColor(color: ColorValue, opacity?: number): this; + opacity(opacity: number): this; + fillOpacity(opacity: number): this; + strokeOpacity(opacity: number): this; + linearGradient(x1: number, y1: number, x2: number, y2: number): PDFLinearGradient; + radialGradient(x1: number, y1: number, r1: number, x2: number, y2: number, r2: number): PDFRadialGradient; +} + +type ColorValue = string | PDFGradient | [number, number, number] | [number, number, number, number]; + +interface PDFGradient { + stop(pos: number, color?: string | PDFGradient, opacity?: number): PDFGradient; + embed(): void; + apply(): void; +} + +interface PDFLinearGradient extends PDFGradient { + shader(fn: () => any): any; + opacityGradient(): PDFLinearGradient; +} + +interface PDFRadialGradient extends PDFGradient { + shader(fn: () => any): any; + opacityGradient(): PDFRadialGradient; +} + +interface PDFImage { + /** + * Draw an image in PDFKit document. + */ + image(src: any, x?: number, y?: number, options?: ImageOption): this; + image(src: any, options?: ImageOption): this; +} + +interface ImageOption { + width?: number; + height?: number; + /** Scale percentage */ + scale?: number; + /** Two elements array specifying dimensions(w,h) */ + fit?: [number, number]; + cover?: [number, number]; + align?: "center" | "right"; + valign?: "center" | "bottom"; + link?: AnnotationOption; + goTo?: AnnotationOption; + destination?: string; +} +interface TextOptions { + /** Set to false to disable line wrapping all together */ + lineBreak?: boolean; + /** The width that text should be wrapped to (by default, the page width minus the left and right margin) */ + width?: number; + /** The maximum height that text should be clipped to */ + height?: number; + /** The character to display at the end of the text when it is too long. Set to true to use the default character. */ + ellipsis?: boolean | string; + /** the number of columns to flow the text into */ + columns?: number; + /** the amount of space between each column (1/4 inch by default) */ + columnGap?: number; + /** The amount in PDF points (72 per inch) to indent each paragraph of text */ + indent?: number; + /** the amount of space between each paragraph of text */ + paragraphGap?: number; + /** the amount of space between each line of text */ + lineGap?: number; + /** the amount of space between each word in the text */ + wordSpacing?: number; + /** the amount of space between each character in the text */ + characterSpacing?: number; + /** whether to fill the text (true by default) */ + fill?: boolean; + /** whether to stroke the text */ + stroke?: boolean; + /** A URL to link this text to (shortcut to create an annotation) */ + link?: string; + /** whether to underline the text */ + underline?: boolean; + /** whether to strike out the text */ + strike?: boolean; + /** whether the text segment will be followed immediately by another segment. Useful for changing styling in the middle of a paragraph. */ + continued?: boolean; + /** whether to slant the text (angle in degrees or true) */ + oblique?: boolean | number; + /** the alignment of the text (center, justify, left, right) */ + // TODO check this + align?: "center" | "justify" | "left" | "right" | string; + /** the vertical alignment of the text with respect to its insertion point */ + baseline?: number | "svg-middle" | "middle" | "svg-central" | "bottom" | "ideographic" | "alphabetic" | "mathematical" | "hanging" | "top"; + /** an array of OpenType feature tags to apply. If not provided, a set of defaults is used. */ + features?: OpenTypeFeatures[]; +} +// Text option opentype features as listed at https://docs.microsoft.com/en-us/typography/opentype/spec/featurelist + type OpenTypeFeatures = + | "aalt" | "abvf" | "abvm" | "abvs" | "afrc" | "akhn" | "blwf" | "blwm" | "blws" | "calt" | "case" + | "cfar" | "cjct" | "clig" | "cpct" | "cpsp" | "cswh" | "curs" | "cv01" | "cv02" | "cv03" | "cv04" + | "cv05" | "cv06" | "cv07" | "cv08" | "cv09" | "cv10" | "cv11" | "cv12" | "cv13" | "cv14" | "cv15" + | "cv16" | "cv17" | "cv18" | "cv19" | "cv20" | "cv21" | "cv22" | "cv23" | "cv24" | "cv25" | "cv26" + | "cv27" | "cv28" | "cv29" | "cv30" | "cv31" | "cv32" | "cv33" | "cv34" | "cv35" | "cv36" | "cv37" + | "cv38" | "cv39" | "cv40" | "cv41" | "cv42" | "cv43" | "cv44" | "cv45" | "cv46" | "cv47" | "cv48" + | "cv49" | "cv50" | "cv51" | "cv52" | "cv53" | "cv54" | "cv55" | "cv56" | "cv57" | "cv58" | "cv59" + | "cv60" | "cv61" | "cv62" | "cv63" | "cv64" | "cv65" | "cv66" | "cv67" | "cv68" | "cv69" | "cv70" + | "cv71" | "cv72" | "cv73" | "cv74" | "cv75" | "cv76" | "cv77" | "cv78" | "cv79" | "cv80" | "cv81" + | "cv82" | "cv83" | "cv84" | "cv85" | "cv86" | "cv87" | "cv88" | "cv89" | "cv90" | "cv91" | "cv92" + | "cv93" | "cv94" | "cv95" | "cv96" | "cv97" | "cv98" | "cv99" | "c2pc" | "c2sc" | "dist" | "ccmp" + | "dlig" | "dnom" | "dtls" | "expt" | "falt" | "fin2" | "fin3" | "fina" | "flac" | "frac" | "fwid" + | "half" | "haln" | "halt" | "hist" | "hkna" | "hlig" | "hngl" | "hojo" | "hwid" | "init" | "isol" + | "ital" | "jalt" | "jp78" | "jp83" | "jp90" | "jp04" | "kern" | "lfbd" | "liga" | "ljmo" | "lnum" + | "locl" | "ltra" | "ltrm" | "mark" | "med2" | "medi" | "mgrk" | "mkmk" | "mset" | "nalt" | "nlck" + | "nukt" | "numr" | "onum" | "opbd" | "ordn" | "ornm" | "palt" | "pcap" | "pkna" | "pnum" | "pref" + | "pres" | "pstf" | "psts" | "pwid" | "qwid" | "rand" | "rclt" | "rkrf" | "rlig" | "rphf" | "rtbd" + | "rtla" | "rtlm" | "ruby" | "rvrn" | "salt" | "sinf" | "size" | "smcp" | "smpl" | "ss01" | "ss02" + | "ss03" | "ss04" | "ss05" | "ss06" | "ss07" | "ss08" | "ss09" | "ss10" | "ss11" | "ss12" | "ss13" + | "ss14" | "ss15" | "ss16" | "ss17" | "ss18" | "ss19" | "ss20" | "ssty" | "stch" | "subs" | "sups" + | "swsh" | "titl" | "tjmo" | "tnam" | "tnum" | "trad" | "twid" | "unic" | "valt" | "vatu" | "vert" + | "vhal" | "vjmo" | "vkna" | "vkrn" | "vpal" | "vrt2" | "vrtr" | "zero"; + +interface PDFText { + lineGap(lineGap: number): this; + moveDown(line?: number): this; + moveUp(line?: number): this; + text(text: string, x?: number, y?: number, options?: TextOptions): this; + text(text: string, options?: TextOptions): this; + widthOfString(text: string, options?: TextOptions): number; + heightOfString(text: string, options?: TextOptions): number; + list(list: Array, x?: number, y?: number, options?: TextOptions): this; + list(list: Array, options?: TextOptions): this; +} + +interface PDFVector { + save(): this; + restore(): this; + closePath(): this; + lineWidth(w: number): this; + lineCap(c: string): this; + lineJoin(j: string): this; + miterLimit(m: any): this; + dash(length: number, option: any): this; + undash(): this; + moveTo(x: number, y: number): this; + lineTo(x: number, y: number): this; + bezierCurveTo(cp1x: number, cp1y: number, cp2x: number, cp2y: number, x: number, y: number): this; + quadraticCurveTo(cpx: number, cpy: number, x: number, y: number): this; + rect(x: number, y: number, w: number, h: number): this; + roundedRect(x: number, y: number, w: number, h: number, r?: number): this; + ellipse(x: number, y: number, r1: number, r2?: number): this; + circle(x: number, y: number, raduis: number): this; + polygon(...points: number[][]): this; + path(path: string): this; + fill(color?: ColorValue, rule?: RuleValue): this; + fill(rule: RuleValue): this; + stroke(color?: ColorValue): this; + fillAndStroke(fillColor?: ColorValue, strokeColor?: ColorValue, rule?: RuleValue): this; + fillAndStroke(fillColor: ColorValue, rule?: RuleValue): this; + fillAndStroke(rule: RuleValue): this; + clip(rule?: RuleValue): this; + transform(m11: number, m12: number, m21: number, m22: number, dx: number, dy: number): this; + translate(x: number, y: number): this; + rotate(angle: number, options?: { origin?: number[] }): this; + scale(xFactor: number, yFactor?: number, options?: { origin?: number[] }): this; +} + + // The winding / filling rule accepted by PDFKit: + type RuleValue = "even-odd" | "evenodd" | "non-zero" | "nonzero"; + + type PDFFontSource = string | Buffer | Uint8Array | ArrayBuffer; + +interface PDFFont { + font(buffer: Buffer): this; + font(src: string, family?: string, size?: number): this; + fontSize(size: number): this; + currentLineHeight(includeGap?: boolean): number; + registerFont(name: string, src?: PDFFontSource, family?: string): this; +} + +interface PDFAcroForm { + /** + * Must call if adding AcroForms to a document. Must also call font() before + * this method to set the default font. + */ + initForm(): this; + + /** + * Called automatically by document.js + */ + endAcroForm(): this; + + /** + * Creates and adds a form field to the document. Form fields are intermediate + * nodes in a PDF form that are used to specify form name heirarchy and form + * value defaults. + * @param name - field name (T attribute in field dictionary) + * @param options - other attributes to include in field dictionary + */ + formField(name: string, options?: Record): PDFKitReference; + + /** + * Creates and adds a Form Annotation to the document. Form annotations are + * called Widget annotations internally within a PDF file. + * @param name - form field name (T attribute of widget annotation + * dictionary) + */ + formAnnotation(name: string, type: string, x: number, y: number, w: number, h: number, options?: object): this; + + formText(name: string, x: number, y: number, w: number, h: number, options?: object): this; + formPushButton(name: string, x: number, y: number, w: number, h: number, options?: object): this; + formCombo(name: string, x: number, y: number, w: number, h: number, options?: object): this; + formList(name: string, x: number, y: number, w: number, h: number, options?: object): this; + formRadioButton(name: string, x: number, y: number, w: number, h: number, options?: object): this; + formCheckbox(name: string, x: number, y: number, w: number, h: number, options?: object): this; +}