@jasy/pdf 1.0.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. package/README.md +171 -0
  2. package/dist/api/args.d.ts +10 -0
  3. package/dist/api/args.js +13 -0
  4. package/dist/api/color.d.ts +24 -0
  5. package/dist/api/color.js +215 -0
  6. package/dist/api/content.d.ts +36 -0
  7. package/dist/api/content.js +50 -0
  8. package/dist/api/descriptor.d.ts +25 -0
  9. package/dist/api/descriptor.js +71 -0
  10. package/dist/api/index.d.ts +8 -0
  11. package/dist/api/index.js +27 -0
  12. package/dist/api/insets.d.ts +16 -0
  13. package/dist/api/insets.js +21 -0
  14. package/dist/api/layout.d.ts +72 -0
  15. package/dist/api/layout.js +99 -0
  16. package/dist/api/structure.d.ts +80 -0
  17. package/dist/api/structure.js +125 -0
  18. package/dist/api/table.d.ts +37 -0
  19. package/dist/api/table.js +87 -0
  20. package/dist/api/text.d.ts +28 -0
  21. package/dist/api/text.js +61 -0
  22. package/dist/assets/Courier-Bold.afm +342 -0
  23. package/dist/assets/Courier-BoldOblique.afm +342 -0
  24. package/dist/assets/Courier-Oblique.afm +342 -0
  25. package/dist/assets/Courier.afm +342 -0
  26. package/dist/assets/Helvetica-Bold.afm +2827 -0
  27. package/dist/assets/Helvetica-BoldOblique.afm +2827 -0
  28. package/dist/assets/Helvetica-Oblique.afm +3051 -0
  29. package/dist/assets/Helvetica.afm +3051 -0
  30. package/dist/assets/Symbol.afm +213 -0
  31. package/dist/assets/Times-Bold.afm +2588 -0
  32. package/dist/assets/Times-BoldItalic.afm +2384 -0
  33. package/dist/assets/Times-Italic.afm +2667 -0
  34. package/dist/assets/Times-Roman.afm +2419 -0
  35. package/dist/assets/ZapfDingbats.afm +225 -0
  36. package/dist/assets/agl.txt +695 -0
  37. package/dist/common/color.d.ts +37 -0
  38. package/dist/common/color.js +62 -0
  39. package/dist/constants/page-sizes.d.ts +44 -0
  40. package/dist/constants/page-sizes.js +92 -0
  41. package/dist/constants/pdf-parts.d.ts +5 -0
  42. package/dist/constants/pdf-parts.js +8 -0
  43. package/dist/elements/container-element.d.ts +35 -0
  44. package/dist/elements/container-element.js +91 -0
  45. package/dist/elements/image-element.d.ts +56 -0
  46. package/dist/elements/image-element.js +151 -0
  47. package/dist/elements/index.d.ts +10 -0
  48. package/dist/elements/index.js +28 -0
  49. package/dist/elements/layout/deferred-element.d.ts +19 -0
  50. package/dist/elements/layout/deferred-element.js +33 -0
  51. package/dist/elements/layout/expanded-element.d.ts +30 -0
  52. package/dist/elements/layout/expanded-element.js +68 -0
  53. package/dist/elements/layout/padding-element.d.ts +29 -0
  54. package/dist/elements/layout/padding-element.js +76 -0
  55. package/dist/elements/layout/repeating-header-element.d.ts +29 -0
  56. package/dist/elements/layout/repeating-header-element.js +60 -0
  57. package/dist/elements/layout/sized-container-element.d.ts +14 -0
  58. package/dist/elements/layout/sized-container-element.js +37 -0
  59. package/dist/elements/line-element.d.ts +31 -0
  60. package/dist/elements/line-element.js +44 -0
  61. package/dist/elements/page-element.d.ts +58 -0
  62. package/dist/elements/page-element.js +90 -0
  63. package/dist/elements/pdf-document-element.d.ts +13 -0
  64. package/dist/elements/pdf-document-element.js +22 -0
  65. package/dist/elements/pdf-element.d.ts +67 -0
  66. package/dist/elements/pdf-element.js +55 -0
  67. package/dist/elements/rectangle-element.d.ts +55 -0
  68. package/dist/elements/rectangle-element.js +120 -0
  69. package/dist/elements/row-element.d.ts +42 -0
  70. package/dist/elements/row-element.js +54 -0
  71. package/dist/elements/text-element.d.ts +59 -0
  72. package/dist/elements/text-element.js +137 -0
  73. package/dist/index.d.ts +3 -0
  74. package/dist/index.js +21 -0
  75. package/dist/ir/display-list.d.ts +74 -0
  76. package/dist/ir/display-list.js +2 -0
  77. package/dist/layout/box-constraints.d.ts +56 -0
  78. package/dist/layout/box-constraints.js +73 -0
  79. package/dist/layout/fragmentation.d.ts +42 -0
  80. package/dist/layout/fragmentation.js +61 -0
  81. package/dist/renderer/container-renderer.d.ts +6 -0
  82. package/dist/renderer/container-renderer.js +30 -0
  83. package/dist/renderer/deferred-renderer.d.ts +6 -0
  84. package/dist/renderer/deferred-renderer.js +25 -0
  85. package/dist/renderer/expanded-renderer.d.ts +6 -0
  86. package/dist/renderer/expanded-renderer.js +23 -0
  87. package/dist/renderer/image-renderer.d.ts +6 -0
  88. package/dist/renderer/image-renderer.js +85 -0
  89. package/dist/renderer/index.d.ts +10 -0
  90. package/dist/renderer/index.js +26 -0
  91. package/dist/renderer/line-renderer.d.ts +6 -0
  92. package/dist/renderer/line-renderer.js +30 -0
  93. package/dist/renderer/padding-renderer.d.ts +6 -0
  94. package/dist/renderer/padding-renderer.js +23 -0
  95. package/dist/renderer/page-renderer.d.ts +5 -0
  96. package/dist/renderer/page-renderer.js +81 -0
  97. package/dist/renderer/pdf-backend.d.ts +45 -0
  98. package/dist/renderer/pdf-backend.js +184 -0
  99. package/dist/renderer/pdf-config.d.ts +8 -0
  100. package/dist/renderer/pdf-config.js +17 -0
  101. package/dist/renderer/pdf-document-class.d.ts +42 -0
  102. package/dist/renderer/pdf-document-class.js +118 -0
  103. package/dist/renderer/pdf-document-renderer.d.ts +20 -0
  104. package/dist/renderer/pdf-document-renderer.js +104 -0
  105. package/dist/renderer/pdf-renderer.d.ts +5 -0
  106. package/dist/renderer/pdf-renderer.js +92 -0
  107. package/dist/renderer/rectangle-renderer.d.ts +8 -0
  108. package/dist/renderer/rectangle-renderer.js +61 -0
  109. package/dist/renderer/repeating-header-renderer.d.ts +6 -0
  110. package/dist/renderer/repeating-header-renderer.js +28 -0
  111. package/dist/renderer/row-renderer.d.ts +6 -0
  112. package/dist/renderer/row-renderer.js +30 -0
  113. package/dist/renderer/text-renderer.d.ts +9 -0
  114. package/dist/renderer/text-renderer.js +125 -0
  115. package/dist/text/line-breaker.d.ts +40 -0
  116. package/dist/text/line-breaker.js +106 -0
  117. package/dist/utils/afm-parser.d.ts +12 -0
  118. package/dist/utils/afm-parser.js +91 -0
  119. package/dist/utils/flex-layout.d.ts +53 -0
  120. package/dist/utils/flex-layout.js +119 -0
  121. package/dist/utils/font-metrics.d.ts +12 -0
  122. package/dist/utils/font-metrics.js +2 -0
  123. package/dist/utils/font-path.d.ts +1 -0
  124. package/dist/utils/font-path.js +19 -0
  125. package/dist/utils/image-helper.d.ts +43 -0
  126. package/dist/utils/image-helper.js +206 -0
  127. package/dist/utils/pdf-object-manager.d.ts +97 -0
  128. package/dist/utils/pdf-object-manager.js +645 -0
  129. package/dist/utils/renderer-registry.d.ts +6 -0
  130. package/dist/utils/renderer-registry.js +19 -0
  131. package/dist/utils/ttf-parser.d.ts +29 -0
  132. package/dist/utils/ttf-parser.js +191 -0
  133. package/dist/utils/ttf-subsetter.d.ts +1 -0
  134. package/dist/utils/ttf-subsetter.js +161 -0
  135. package/dist/utils/utf8-to-windows1252-encoder.d.ts +2 -0
  136. package/dist/utils/utf8-to-windows1252-encoder.js +55 -0
  137. package/dist/validators/element-validator.d.ts +8 -0
  138. package/dist/validators/element-validator.js +61 -0
  139. package/package.json +50 -0
@@ -0,0 +1,53 @@
1
+ import { PDFElement, LayoutContext } from "../elements/pdf-element";
2
+ import { BoxConstraints, Offset, Size } from "../layout/box-constraints";
3
+ /** Distribution of the children ALONG the stacking (main) axis when there is leftover
4
+ * space and no flex child to absorb it. */
5
+ export type MainAlign = "start" | "center" | "end" | "between" | "around";
6
+ /** Position/size of each child ACROSS the cross axis. `stretch` fills the cross extent;
7
+ * the others place the child at its natural cross size. */
8
+ export type CrossAlign = "start" | "center" | "end" | "stretch";
9
+ /**
10
+ * Maps the abstract MAIN/CROSS axes onto concrete width/height + x/y, so one flex
11
+ * algorithm drives both a vertical Column (main = height) and a horizontal Row
12
+ * (main = width). "main" is the stacking direction; "cross" is perpendicular.
13
+ */
14
+ export interface FlexAxis {
15
+ mainOf(size: Size): number;
16
+ crossOf(size: Size): number;
17
+ /**
18
+ * Constraints for a fixed child: the main extent is unbounded (it takes its natural
19
+ * size); the cross extent is ALWAYS capped to what the line offers. The cap is a hard
20
+ * ceiling regardless of `cross` alignment - it is what guarantees nothing ever overflows
21
+ * (a paragraph wraps at the column width instead of running one line off the page). A
22
+ * child smaller than the cap keeps its size and is positioned by `crossOffset`; a child
23
+ * that wants to fill (Container, Text) fills the cap. So `stretch` vs `start/center/end`
24
+ * differ only in where a smaller child sits, never in the ceiling.
25
+ */
26
+ measureConstraints(crossAvail: number): BoxConstraints;
27
+ /** Constraints for a flex child (fills the cross axis like a stretched child). */
28
+ flexConstraints(mainExtent: number, crossAvail: number): BoxConstraints;
29
+ /** Absolute offset for a child at main position `mainPos`, cross position `crossPos`. */
30
+ offsetAt(mainPos: number, crossPos: number): Offset;
31
+ }
32
+ export declare const VERTICAL_AXIS: FlexAxis;
33
+ export declare const HORIZONTAL_AXIS: FlexAxis;
34
+ export interface FlexOptions {
35
+ gap?: number;
36
+ main?: MainAlign;
37
+ cross?: CrossAlign;
38
+ }
39
+ export declare class FlexLayoutHelper {
40
+ /**
41
+ * Lays out a flex line along `axis`, IN SOURCE ORDER, and places every child.
42
+ * Fixed children take their natural main extent; flex (`ExpandedElement`) children
43
+ * split the leftover main space by their `flex`. `gap` is inserted between children.
44
+ * `main` distributes any leftover when there is no flex child; `cross` positions/sizes
45
+ * each child across the line. Returns the total main extent consumed and the cross
46
+ * extent occupied. Vertical with `gap 0`, `main start`, `cross stretch` reproduces the
47
+ * previous Column layout exactly.
48
+ */
49
+ static layout(children: PDFElement[], axis: FlexAxis, mainAvail: number, crossAvail: number, mainStart: number, crossOrigin: number, options: FlexOptions, ctx: LayoutContext): {
50
+ mainUsed: number;
51
+ crossUsed: number;
52
+ };
53
+ }
@@ -0,0 +1,119 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FlexLayoutHelper = exports.HORIZONTAL_AXIS = exports.VERTICAL_AXIS = void 0;
4
+ const pdf_element_1 = require("../elements/pdf-element");
5
+ const box_constraints_1 = require("../layout/box-constraints");
6
+ exports.VERTICAL_AXIS = {
7
+ mainOf: (s) => s.height,
8
+ crossOf: (s) => s.width,
9
+ measureConstraints: (crossAvail) => box_constraints_1.BoxConstraints.loose(crossAvail, Infinity),
10
+ flexConstraints: (mainExtent, crossAvail) => box_constraints_1.BoxConstraints.loose(crossAvail, mainExtent),
11
+ offsetAt: (mainPos, crossPos) => ({ x: crossPos, y: mainPos }),
12
+ };
13
+ exports.HORIZONTAL_AXIS = {
14
+ mainOf: (s) => s.width,
15
+ crossOf: (s) => s.height,
16
+ measureConstraints: (crossAvail) => box_constraints_1.BoxConstraints.loose(Infinity, crossAvail),
17
+ flexConstraints: (mainExtent, crossAvail) => box_constraints_1.BoxConstraints.loose(mainExtent, crossAvail),
18
+ offsetAt: (mainPos, crossPos) => ({ x: mainPos, y: crossPos }),
19
+ };
20
+ /** Cross-axis offset of a child of size `childCross` within `crossExtent`. */
21
+ function crossOffset(align, crossExtent, childCross) {
22
+ if (align === "center")
23
+ return Math.max(0, (crossExtent - childCross) / 2);
24
+ if (align === "end")
25
+ return Math.max(0, crossExtent - childCross);
26
+ return 0; // start, stretch (stretch fills, so no offset)
27
+ }
28
+ class FlexLayoutHelper {
29
+ /**
30
+ * Lays out a flex line along `axis`, IN SOURCE ORDER, and places every child.
31
+ * Fixed children take their natural main extent; flex (`ExpandedElement`) children
32
+ * split the leftover main space by their `flex`. `gap` is inserted between children.
33
+ * `main` distributes any leftover when there is no flex child; `cross` positions/sizes
34
+ * each child across the line. Returns the total main extent consumed and the cross
35
+ * extent occupied. Vertical with `gap 0`, `main start`, `cross stretch` reproduces the
36
+ * previous Column layout exactly.
37
+ */
38
+ static layout(children, axis, mainAvail, crossAvail, mainStart, crossOrigin, options, ctx) {
39
+ var _a, _b, _c;
40
+ const gap = (_a = options.gap) !== null && _a !== void 0 ? _a : 0;
41
+ const main = (_b = options.main) !== null && _b !== void 0 ? _b : "start";
42
+ const cross = (_c = options.cross) !== null && _c !== void 0 ? _c : "stretch";
43
+ const count = children.length;
44
+ // Pass 1: measure the fixed children (main extent + cross size) and total the flex.
45
+ let fixedMain = 0;
46
+ let totalFlex = 0;
47
+ let crossUsed = 0;
48
+ const fixedSize = new Map();
49
+ for (const child of children) {
50
+ if (child instanceof pdf_element_1.FlexiblePDFElement) {
51
+ totalFlex += child.getFlex();
52
+ }
53
+ else {
54
+ const size = child.calculateLayout(axis.measureConstraints(crossAvail), axis.offsetAt(mainStart, crossOrigin), ctx);
55
+ fixedMain += axis.mainOf(size);
56
+ crossUsed = Math.max(crossUsed, axis.crossOf(size));
57
+ fixedSize.set(child, size);
58
+ }
59
+ }
60
+ const totalGap = Math.max(0, count - 1) * gap;
61
+ const leftover = mainAvail - fixedMain - totalGap;
62
+ const remaining = Math.max(leftover, 0); // for flex children
63
+ // Main-axis distribution only kicks in with no flex child and bounded, positive space.
64
+ let leadingSpace = 0;
65
+ let betweenSpace = gap;
66
+ if (totalFlex === 0 && mainAvail !== Infinity && leftover > 0) {
67
+ if (main === "center")
68
+ leadingSpace = leftover / 2;
69
+ else if (main === "end")
70
+ leadingSpace = leftover;
71
+ else if (main === "between" && count > 1)
72
+ betweenSpace = gap + leftover / (count - 1);
73
+ else if (main === "around") {
74
+ const unit = leftover / count;
75
+ leadingSpace = unit / 2;
76
+ betweenSpace = gap + unit;
77
+ }
78
+ }
79
+ // Measure flex children too (at their main share) so a tall/wrapping flex cell counts
80
+ // toward the line's cross extent - they're placed in pass 2, but crossExtent needs them now.
81
+ if (totalFlex > 0) {
82
+ for (const child of children) {
83
+ if (child instanceof pdf_element_1.FlexiblePDFElement) {
84
+ const mainExtent = (child.getFlex() / totalFlex) * remaining;
85
+ const size = child.calculateLayout(axis.flexConstraints(mainExtent, crossAvail), axis.offsetAt(mainStart, crossOrigin), ctx);
86
+ crossUsed = Math.max(crossUsed, axis.crossOf(size));
87
+ }
88
+ }
89
+ }
90
+ // The cross extent children align within: the bounded line size, else the tallest child.
91
+ const crossExtent = crossAvail !== Infinity ? crossAvail : crossUsed;
92
+ // `stretch` caps a child's cross to `crossExtent` (not `crossAvail`) so siblings end up
93
+ // equal across the axis. Bounded lines have crossExtent == crossAvail (byte-identical);
94
+ // only an unbounded line (a shrink-wrap Row) now equalises instead of staying natural.
95
+ const stretch = cross === "stretch";
96
+ // Pass 2: place each child at the running main position, offset across by `cross`.
97
+ let mainPos = mainStart + leadingSpace;
98
+ let placedCross = 0;
99
+ children.forEach((child, index) => {
100
+ let mainExtent;
101
+ if (child instanceof pdf_element_1.FlexiblePDFElement) {
102
+ mainExtent = (child.getFlex() / totalFlex) * remaining;
103
+ const size = child.calculateLayout(axis.flexConstraints(mainExtent, stretch ? crossExtent : crossAvail), axis.offsetAt(mainPos, crossOrigin), ctx);
104
+ placedCross = Math.max(placedCross, axis.crossOf(size));
105
+ }
106
+ else {
107
+ const childCross = axis.crossOf(fixedSize.get(child));
108
+ const size = child.calculateLayout(axis.measureConstraints(stretch ? crossExtent : crossAvail), axis.offsetAt(mainPos, crossOrigin + crossOffset(cross, crossExtent, childCross)), ctx);
109
+ mainExtent = axis.mainOf(size);
110
+ placedCross = Math.max(placedCross, axis.crossOf(size));
111
+ }
112
+ mainPos += mainExtent;
113
+ if (index < count - 1)
114
+ mainPos += betweenSpace;
115
+ });
116
+ return { mainUsed: mainPos - mainStart, crossUsed: placedCross };
117
+ }
118
+ }
119
+ exports.FlexLayoutHelper = FlexLayoutHelper;
@@ -0,0 +1,12 @@
1
+ import type { FontStyle } from "./pdf-object-manager";
2
+ /**
3
+ * Read-only font measurement - the slice of the object manager that the layout pass
4
+ * needs. Keeping layout (and, later, fragmentation) behind this interface means those
5
+ * passes depend only on metrics, never on the PDF byte writer. `PDFObjectManager`
6
+ * implements it today; a standalone metrics service can replace it later without
7
+ * touching layout code.
8
+ */
9
+ export interface FontMetrics {
10
+ getStringWidth(text: string, fontFamily: string, fontSize: number, fontStyle: FontStyle): number;
11
+ getCharWidth(char: string, fontSize: number, fullFontName?: string, fontName?: string, fontStyle?: FontStyle): number;
12
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1 @@
1
+ export declare function getFontPath(fontName: string): string;
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getFontPath = getFontPath;
4
+ const os = require("os");
5
+ const path = require("path");
6
+ function getFontPath(fontName) {
7
+ const platform = os.platform();
8
+ let fontPath = "";
9
+ if (platform === "win32") {
10
+ fontPath = path.join("C:\\Windows\\Fonts", fontName);
11
+ }
12
+ else if (platform === "darwin") {
13
+ fontPath = path.join("/Library/Fonts", fontName);
14
+ }
15
+ else if (platform === "linux") {
16
+ fontPath = path.join("/usr/share/fonts", fontName);
17
+ }
18
+ return fontPath;
19
+ }
@@ -0,0 +1,43 @@
1
+ declare global {
2
+ interface DataView {
3
+ getUint24(byteOffset: number, littleEndian?: boolean): number;
4
+ }
5
+ }
6
+ interface ImageDimensions {
7
+ width: number;
8
+ height: number;
9
+ }
10
+ export declare function getImageDimensions(buffer: Buffer): Promise<ImageDimensions>;
11
+ /**
12
+ * Converts the given image to grayscale and returns its binary data.
13
+ * @param imagePath Path to the input image file.
14
+ * @returns Promise that resolves with the binary data of the grayscale image.
15
+ */
16
+ /**
17
+ * Decodes a PNG into raw DeviceRGB samples, Flate-compressed, ready to embed as a PDF
18
+ * image XObject. A PNG file is NOT a valid `/FlateDecode` stream (it's a signature plus
19
+ * chunks of filtered, zlib-compressed scanlines), so it must be decoded first. PDF has
20
+ * no alpha channel for DeviceRGB, so transparent pixels are composited over white.
21
+ */
22
+ export declare function decodePngToRgbFlate(pngBuffer: Buffer): Promise<{
23
+ data: string;
24
+ width: number;
25
+ height: number;
26
+ }>;
27
+ export declare function convertImageToGrayscaleBuffer(imagePath: string): Promise<Buffer>;
28
+ export interface FitResult {
29
+ width: number;
30
+ height: number;
31
+ offsetX: number;
32
+ offsetY: number;
33
+ }
34
+ export declare function applyContainFit(imageWidth: number, imageHeight: number, containerWidth: number, containerHeight: number): FitResult;
35
+ export declare function applyCoverFit(imageWidth: number, imageHeight: number, containerWidth: number, containerHeight: number): FitResult;
36
+ export declare function applyFillFit(containerWidth: number, containerHeight: number): FitResult;
37
+ export declare function applyFitNone(imageWidth: number, imageHeight: number, containerWidth: number, containerHeight: number): {
38
+ width: number;
39
+ height: number;
40
+ offsetX: number;
41
+ offsetY: number;
42
+ };
43
+ export {};
@@ -0,0 +1,206 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.getImageDimensions = getImageDimensions;
13
+ exports.decodePngToRgbFlate = decodePngToRgbFlate;
14
+ exports.convertImageToGrayscaleBuffer = convertImageToGrayscaleBuffer;
15
+ exports.applyContainFit = applyContainFit;
16
+ exports.applyCoverFit = applyCoverFit;
17
+ exports.applyFillFit = applyFillFit;
18
+ exports.applyFitNone = applyFitNone;
19
+ const jimp_1 = require("jimp");
20
+ const zlib_1 = require("zlib");
21
+ // Implement the method to handle 24-bit integers
22
+ DataView.prototype.getUint24 = function (byteOffset, littleEndian = false) {
23
+ const b1 = this.getUint8(byteOffset);
24
+ const b2 = this.getUint8(byteOffset + 1);
25
+ const b3 = this.getUint8(byteOffset + 2);
26
+ return littleEndian ? (b3 << 16) | (b2 << 8) | b1 : (b1 << 16) | (b2 << 8) | b3;
27
+ };
28
+ function getImageDimensions(buffer) {
29
+ return __awaiter(this, void 0, void 0, function* () {
30
+ const dataView = new DataView(buffer.buffer);
31
+ // Check for JPEG (0xFFD8 is the start of JPEG file)
32
+ if (dataView.getUint16(0) === 0xffd8) {
33
+ let offset = 2;
34
+ while (offset < buffer.byteLength) {
35
+ const marker = dataView.getUint16(offset, false);
36
+ offset += 2;
37
+ if (marker === 0xffc0 || marker === 0xffc2) {
38
+ // SOF0 or SOF2
39
+ return {
40
+ height: dataView.getUint16(offset + 3, false),
41
+ width: dataView.getUint16(offset + 5, false),
42
+ };
43
+ }
44
+ else {
45
+ offset += dataView.getUint16(offset, false);
46
+ }
47
+ }
48
+ }
49
+ // Check for PNG (0x89504E47 is the PNG signature)
50
+ if (dataView.getUint32(0) === 0x89504e47) {
51
+ return {
52
+ width: dataView.getUint32(16, false),
53
+ height: dataView.getUint32(20, false),
54
+ };
55
+ }
56
+ // Check for BMP (0x424D is the BMP signature)
57
+ if (dataView.getUint16(0) === 0x424d) {
58
+ return {
59
+ width: dataView.getUint32(18, true),
60
+ height: dataView.getUint32(22, true),
61
+ };
62
+ }
63
+ // Check for WebP (0x52494646 is the WebP signature 'RIFF')
64
+ if (dataView.getUint32(0) === 0x52494646 && dataView.getUint32(8) === 0x57454250) {
65
+ // 'WEBP'
66
+ if (dataView.getUint32(12) === 0x56503820) {
67
+ // 'VP8 '
68
+ return {
69
+ width: dataView.getUint16(26, true),
70
+ height: dataView.getUint16(28, true),
71
+ };
72
+ }
73
+ else if (dataView.getUint32(12) === 0x56503858) {
74
+ // 'VP8X'
75
+ return {
76
+ width: dataView.getUint24(24, true) + 1,
77
+ height: dataView.getUint24(27, true) + 1,
78
+ };
79
+ }
80
+ }
81
+ throw new Error("Unsupported image format");
82
+ });
83
+ }
84
+ /**
85
+ * Converts the given image to grayscale and returns its binary data.
86
+ * @param imagePath Path to the input image file.
87
+ * @returns Promise that resolves with the binary data of the grayscale image.
88
+ */
89
+ /**
90
+ * Decodes a PNG into raw DeviceRGB samples, Flate-compressed, ready to embed as a PDF
91
+ * image XObject. A PNG file is NOT a valid `/FlateDecode` stream (it's a signature plus
92
+ * chunks of filtered, zlib-compressed scanlines), so it must be decoded first. PDF has
93
+ * no alpha channel for DeviceRGB, so transparent pixels are composited over white.
94
+ */
95
+ function decodePngToRgbFlate(pngBuffer) {
96
+ return __awaiter(this, void 0, void 0, function* () {
97
+ const image = yield jimp_1.Jimp.fromBuffer(pngBuffer);
98
+ const { width, height, data: rgba } = image.bitmap;
99
+ const rgb = Buffer.allocUnsafe(width * height * 3);
100
+ for (let i = 0, j = 0; i < rgba.length; i += 4, j += 3) {
101
+ const alpha = rgba[i + 3] / 255;
102
+ rgb[j] = Math.round(rgba[i] * alpha + 255 * (1 - alpha));
103
+ rgb[j + 1] = Math.round(rgba[i + 1] * alpha + 255 * (1 - alpha));
104
+ rgb[j + 2] = Math.round(rgba[i + 2] * alpha + 255 * (1 - alpha));
105
+ }
106
+ // Compress so the existing `/Filter /FlateDecode` XObject path embeds it correctly.
107
+ return { data: (0, zlib_1.deflateSync)(rgb).toString("binary"), width, height };
108
+ });
109
+ }
110
+ function convertImageToGrayscaleBuffer(imagePath) {
111
+ return __awaiter(this, void 0, void 0, function* () {
112
+ // We get the image from the buffer
113
+ const image = yield jimp_1.Jimp.read(imagePath);
114
+ // Get MIME type. If emtpy throw error
115
+ const mime = image.mime;
116
+ if (!mime)
117
+ throw new Error("Cannot read MIME type");
118
+ // We need to check the MIME type (the exact union `getBuffer` accepts).
119
+ let mimeType;
120
+ switch (mime) {
121
+ case jimp_1.JimpMime.png:
122
+ case jimp_1.JimpMime.jpeg:
123
+ case jimp_1.JimpMime.bmp:
124
+ mimeType = mime;
125
+ break;
126
+ default:
127
+ throw new Error("Unsupported MIME type");
128
+ }
129
+ image.greyscale();
130
+ // Convert the image back to buffer with current MIME type
131
+ const grayscaleBuffer = yield image.getBuffer(mimeType);
132
+ return grayscaleBuffer;
133
+ });
134
+ }
135
+ function applyContainFit(imageWidth, imageHeight, containerWidth, containerHeight) {
136
+ const imageAspectRatio = imageWidth / imageHeight;
137
+ const containerAspectRatio = containerWidth / containerHeight;
138
+ let width, height, offsetX, offsetY;
139
+ if (imageAspectRatio > containerAspectRatio) {
140
+ // The images width is bigger than the containers width
141
+ const scaleFactor = containerWidth / imageWidth;
142
+ width = containerWidth;
143
+ height = imageHeight * scaleFactor;
144
+ offsetX = 0;
145
+ offsetY = (containerHeight - height) / 2; // Center vertically
146
+ }
147
+ else {
148
+ // THe images height is bigge rthan the containers height
149
+ const scaleFactor = containerHeight / imageHeight;
150
+ width = imageWidth * scaleFactor;
151
+ height = containerHeight;
152
+ offsetX = (containerWidth - width) / 2; // Center horizontally
153
+ offsetY = 0;
154
+ }
155
+ return {
156
+ width,
157
+ height,
158
+ offsetX,
159
+ offsetY,
160
+ };
161
+ }
162
+ function applyCoverFit(imageWidth, imageHeight, containerWidth, containerHeight) {
163
+ const imageAspectRatio = imageWidth / imageHeight;
164
+ const containerAspectRatio = containerWidth / containerHeight;
165
+ let width, height, offsetX, offsetY;
166
+ if (imageAspectRatio > containerAspectRatio) {
167
+ // The images width is bigger than containers width
168
+ const scaleFactor = containerHeight / imageHeight;
169
+ width = imageWidth * scaleFactor;
170
+ height = containerHeight;
171
+ offsetX = (containerWidth - width) / 2; // Center horizontally
172
+ offsetY = 0;
173
+ }
174
+ else {
175
+ // The images height is bigger than containers height
176
+ const scaleFactor = containerWidth / imageWidth;
177
+ width = containerWidth;
178
+ height = imageHeight * scaleFactor;
179
+ offsetX = 0;
180
+ offsetY = (containerHeight - height) / 2; // Center vertically
181
+ }
182
+ return {
183
+ width,
184
+ height,
185
+ offsetX,
186
+ offsetY,
187
+ };
188
+ }
189
+ function applyFillFit(containerWidth, containerHeight) {
190
+ return {
191
+ width: containerWidth,
192
+ height: containerHeight,
193
+ offsetX: 0,
194
+ offsetY: 0,
195
+ };
196
+ }
197
+ function applyFitNone(imageWidth, imageHeight, containerWidth, containerHeight) {
198
+ const offsetX = (containerWidth - imageWidth) / 2; // Center horizontally
199
+ const offsetY = (containerHeight - imageHeight) / 2; // Center vertically
200
+ return {
201
+ width: imageWidth, // Hold orignal image size
202
+ height: imageHeight,
203
+ offsetX: offsetX > 0 ? offsetX : 0, // Dont move outside the container...
204
+ offsetY: offsetY > 0 ? offsetY : 0,
205
+ };
206
+ }
@@ -0,0 +1,97 @@
1
+ import type { PDFConfig } from "../renderer/pdf-document-class";
2
+ import type { FontMetrics } from "./font-metrics";
3
+ interface FontIndexes {
4
+ fontIndex: number;
5
+ resourceIndex: number;
6
+ fontStyle: FontStyle;
7
+ fullName: string;
8
+ }
9
+ export declare enum FontStyle {
10
+ Normal = "normal",
11
+ Bold = "bold",
12
+ Italic = "italic",
13
+ BoldItalic = "boldItalic"
14
+ }
15
+ export declare class PDFObjectManager implements FontMetrics {
16
+ private objects;
17
+ private objectPositions;
18
+ private parentObjectNumber;
19
+ private fonts;
20
+ private images;
21
+ private extGStates;
22
+ private pdfConfig;
23
+ pageFormat: [number, number];
24
+ private afmParsers;
25
+ private customFonts;
26
+ private customFontEmit;
27
+ private attachments;
28
+ private xmpMetadata?;
29
+ private outputIntent?;
30
+ private pdfVersion;
31
+ private documentId;
32
+ private compress;
33
+ constructor();
34
+ addObject(content: string): number;
35
+ replaceObject(objectNumber: number, content: string): void;
36
+ setCompress(on: boolean): void;
37
+ private stream;
38
+ addContentStream(content: string): number;
39
+ changePDFConfig(config: PDFConfig): void;
40
+ getPDFConfig(): PDFConfig;
41
+ private fillConfigWithStandardValues;
42
+ private getCurrentByteLength;
43
+ setParentObjectNumber(number: number): void;
44
+ getParentObjectNumber(): number;
45
+ registerImage(width: number, height: number, imageType: string, imageData: string): number;
46
+ attachFile(name: string, data: Buffer, opts?: {
47
+ relationship?: string;
48
+ mimeType?: string;
49
+ description?: string;
50
+ }): void;
51
+ getAttachments(): {
52
+ name: string;
53
+ filespec: number;
54
+ }[];
55
+ setXmpMetadata(xml: string): void;
56
+ getXmpMetadata(): string | undefined;
57
+ setOutputIntent(icc: Buffer, opts?: {
58
+ identifier?: string;
59
+ info?: string;
60
+ }): void;
61
+ getOutputIntent(): number | undefined;
62
+ setPdfVersion(version: string): void;
63
+ getPdfVersion(): string;
64
+ getHeader(): string;
65
+ enableDocumentId(): void;
66
+ registerExtGState(fillAlpha: number, strokeAlpha: number): string;
67
+ getAllExtGStatesRaw(): Map<string, number>;
68
+ registerFont(fontName: string, fontStyle?: FontStyle, fullName?: string): FontIndexes;
69
+ registerCustomFont(name: string, data: Buffer, style?: FontStyle): void;
70
+ private ensureEmitted;
71
+ finalizeCustomFonts(): void;
72
+ private subsetTag;
73
+ private customKey;
74
+ private resolveCustomStyle;
75
+ private getCustomFont;
76
+ isCustomFont(name?: string, style?: FontStyle): boolean;
77
+ getCustomFontResource(name: string, style?: FontStyle): FontIndexes | undefined;
78
+ encodeCustomText(name: string, text: string, style?: FontStyle): string;
79
+ private buildFontFile2;
80
+ private buildFontDescriptor;
81
+ private buildCIDFont;
82
+ private buildToUnicode;
83
+ private buildType0;
84
+ getStringWidth(text: string, fontFamily: string, fontSize: number, fontStyle: FontStyle): number;
85
+ private getCharCode;
86
+ private getAVMParserByFont;
87
+ getCharWidth(char: string, fontSize: number, fullFontName?: string, fontName?: string, fontStyle?: FontStyle): number;
88
+ private getKerning;
89
+ getAllFontsRaw(): Map<string, FontIndexes>;
90
+ getAllImagesRaw(): Map<string, number>;
91
+ getRenderedObjects(): string;
92
+ getXRefTable(): string;
93
+ getTrailerAndXRef(startxref: number): string;
94
+ private contentId;
95
+ getObjectCount(): number;
96
+ }
97
+ export {};