@jasy/pdf 1.0.0-beta.3 → 1.0.0-beta.5
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.
- package/dist/api/color.d.ts +1 -24
- package/dist/api/color.js +2 -278
- package/dist/api/content.d.ts +10 -5
- package/dist/api/content.js +29 -13
- package/dist/api/descriptor.js +30 -3
- package/dist/api/flow.d.ts +55 -0
- package/dist/api/flow.js +71 -0
- package/dist/api/font-url.d.ts +1 -2
- package/dist/api/font-url.js +8 -74
- package/dist/api/forms.d.ts +3 -0
- package/dist/api/forms.js +3 -0
- package/dist/api/gradient.d.ts +1 -53
- package/dist/api/gradient.js +2 -97
- package/dist/api/index.d.ts +4 -0
- package/dist/api/index.js +3 -0
- package/dist/api/layout.d.ts +6 -0
- package/dist/api/layout.js +9 -3
- package/dist/api/page-builder.d.ts +4 -0
- package/dist/api/page-builder.js +4 -0
- package/dist/api/structure.d.ts +10 -2
- package/dist/api/structure.js +9 -6
- package/dist/api/table.d.ts +5 -3
- package/dist/api/table.js +101 -22
- package/dist/api/text.d.ts +8 -8
- package/dist/api/text.js +6 -0
- package/dist/canvas/painter.d.ts +2 -2
- package/dist/canvas/painter.js +2 -2
- package/dist/common/color-input.d.ts +24 -0
- package/dist/common/color-input.js +278 -0
- package/dist/common/diagnostics.d.ts +61 -0
- package/dist/common/diagnostics.js +77 -0
- package/dist/common/gradient.d.ts +53 -0
- package/dist/common/gradient.js +97 -0
- package/dist/edit/acroform-reader.js +7 -7
- package/dist/edit/appearance.js +3 -3
- package/dist/edit/attachments.d.ts +52 -0
- package/dist/edit/attachments.js +178 -0
- package/dist/edit/document.d.ts +38 -8
- package/dist/edit/document.js +208 -51
- package/dist/edit/fill.js +8 -23
- package/dist/edit/filters.d.ts +15 -0
- package/dist/edit/filters.js +157 -0
- package/dist/edit/index.d.ts +4 -1
- package/dist/edit/index.js +3 -1
- package/dist/edit/objects.d.ts +3 -4
- package/dist/edit/objects.js +5 -18
- package/dist/elements/canvas-element.d.ts +3 -0
- package/dist/elements/canvas-element.js +14 -3
- package/dist/elements/container-element.d.ts +8 -1
- package/dist/elements/container-element.js +49 -17
- package/dist/elements/forms/checkbox-element.d.ts +2 -0
- package/dist/elements/forms/checkbox-element.js +12 -3
- package/dist/elements/forms/choice-element.d.ts +6 -1
- package/dist/elements/forms/choice-element.js +17 -6
- package/dist/elements/forms/field-font.d.ts +8 -0
- package/dist/elements/forms/field-font.js +5 -0
- package/dist/elements/forms/push-button-element.d.ts +6 -1
- package/dist/elements/forms/push-button-element.js +16 -4
- package/dist/elements/forms/radio-element.d.ts +2 -0
- package/dist/elements/forms/radio-element.js +12 -3
- package/dist/elements/forms/signature-element.d.ts +6 -1
- package/dist/elements/forms/signature-element.js +16 -4
- package/dist/elements/forms/text-field-element.d.ts +6 -1
- package/dist/elements/forms/text-field-element.js +16 -4
- package/dist/elements/image-element.d.ts +70 -21
- package/dist/elements/image-element.js +173 -52
- package/dist/elements/index.d.ts +3 -0
- package/dist/elements/index.js +3 -0
- package/dist/elements/layout/anchor-element.d.ts +8 -10
- package/dist/elements/layout/anchor-element.js +10 -18
- package/dist/elements/layout/bookmark-element.d.ts +9 -11
- package/dist/elements/layout/bookmark-element.js +11 -20
- package/dist/elements/layout/column-break-element.d.ts +17 -0
- package/dist/elements/layout/column-break-element.js +26 -0
- package/dist/elements/layout/default-text-style-element.d.ts +11 -13
- package/dist/elements/layout/default-text-style-element.js +14 -31
- package/dist/elements/layout/deferred-element.d.ts +20 -4
- package/dist/elements/layout/deferred-element.js +41 -9
- package/dist/elements/layout/expanded-element.d.ts +11 -0
- package/dist/elements/layout/expanded-element.js +53 -18
- package/dist/elements/layout/flow-element.d.ts +109 -0
- package/dist/elements/layout/flow-element.js +317 -0
- package/dist/elements/layout/keep-together-element.d.ts +8 -18
- package/dist/elements/layout/keep-together-element.js +33 -45
- package/dist/elements/layout/link-element.d.ts +8 -13
- package/dist/elements/layout/link-element.js +9 -19
- package/dist/elements/layout/padding-element.d.ts +18 -1
- package/dist/elements/layout/padding-element.js +63 -28
- package/dist/elements/layout/page-break-element.d.ts +4 -1
- package/dist/elements/layout/page-break-element.js +6 -1
- package/dist/elements/layout/page-builder-element.d.ts +5 -0
- package/dist/elements/layout/page-builder-element.js +13 -2
- package/dist/elements/layout/positioned-element.d.ts +23 -4
- package/dist/elements/layout/positioned-element.js +42 -12
- package/dist/elements/layout/proxy-element.d.ts +47 -0
- package/dist/elements/layout/proxy-element.js +106 -0
- package/dist/elements/layout/region-element.d.ts +53 -0
- package/dist/elements/layout/region-element.js +108 -0
- package/dist/elements/layout/repeating-header-element.d.ts +9 -0
- package/dist/elements/layout/repeating-header-element.js +55 -13
- package/dist/elements/layout/rotated-box-element.d.ts +6 -0
- package/dist/elements/layout/rotated-box-element.js +27 -14
- package/dist/elements/layout/rotated-element.d.ts +9 -0
- package/dist/elements/layout/rotated-element.js +33 -2
- package/dist/elements/layout/struct-group.d.ts +9 -17
- package/dist/elements/layout/struct-group.js +10 -35
- package/dist/elements/line-element.d.ts +1 -0
- package/dist/elements/line-element.js +6 -0
- package/dist/elements/page-element.d.ts +10 -3
- package/dist/elements/page-element.js +39 -31
- package/dist/elements/pdf-document-element.d.ts +3 -0
- package/dist/elements/pdf-document-element.js +7 -0
- package/dist/elements/pdf-element.d.ts +105 -16
- package/dist/elements/pdf-element.js +118 -19
- package/dist/elements/rectangle-element.d.ts +22 -2
- package/dist/elements/rectangle-element.js +119 -55
- package/dist/elements/row-element.d.ts +17 -12
- package/dist/elements/row-element.js +89 -9
- package/dist/elements/svg-element.d.ts +30 -6
- package/dist/elements/svg-element.js +91 -26
- package/dist/elements/text-element.d.ts +48 -13
- package/dist/elements/text-element.js +161 -116
- package/dist/forms/acroform.d.ts +9 -1
- package/dist/forms/acroform.js +83 -34
- package/dist/forms/appearance.d.ts +17 -6
- package/dist/forms/appearance.js +18 -16
- package/dist/ir/display-list.d.ts +18 -3
- package/dist/layout/box-constraints.d.ts +17 -0
- package/dist/layout/box-constraints.js +31 -0
- package/dist/layout/collect-images.d.ts +6 -4
- package/dist/layout/collect-images.js +14 -8
- package/dist/layout/flex-item.d.ts +11 -0
- package/dist/layout/flex-item.js +51 -0
- package/dist/layout/fragmentation.d.ts +23 -9
- package/dist/layout/fragmentation.js +62 -19
- package/dist/layout/layout-cache.d.ts +53 -0
- package/dist/layout/layout-cache.js +110 -0
- package/dist/platform/browser-fs.d.ts +1 -2
- package/dist/platform/browser-fs.js +3 -6
- package/dist/platform/node-fs.d.ts +0 -1
- package/dist/platform/node-fs.js +0 -4
- package/dist/renderer/anchor-renderer.d.ts +2 -1
- package/dist/renderer/anchor-renderer.js +5 -4
- package/dist/renderer/bookmark-renderer.d.ts +2 -1
- package/dist/renderer/bookmark-renderer.js +5 -4
- package/dist/renderer/canvas-renderer.d.ts +2 -1
- package/dist/renderer/canvas-renderer.js +5 -2
- package/dist/renderer/column-break-renderer.d.ts +8 -0
- package/dist/renderer/column-break-renderer.js +15 -0
- package/dist/renderer/container-renderer.d.ts +2 -1
- package/dist/renderer/container-renderer.js +6 -5
- package/dist/renderer/default-text-style-renderer.d.ts +2 -1
- package/dist/renderer/default-text-style-renderer.js +2 -3
- package/dist/renderer/deferred-renderer.d.ts +2 -1
- package/dist/renderer/deferred-renderer.js +2 -3
- package/dist/renderer/emoji-image.js +3 -1
- package/dist/renderer/expanded-renderer.d.ts +2 -1
- package/dist/renderer/expanded-renderer.js +2 -3
- package/dist/renderer/flow-renderer.d.ts +16 -0
- package/dist/renderer/flow-renderer.js +21 -0
- package/dist/renderer/form-field-renderer.d.ts +2 -1
- package/dist/renderer/form-field-renderer.js +16 -3
- package/dist/renderer/image-renderer.d.ts +2 -1
- package/dist/renderer/image-renderer.js +33 -53
- package/dist/renderer/index.d.ts +2 -0
- package/dist/renderer/index.js +2 -0
- package/dist/renderer/keep-together-renderer.d.ts +2 -1
- package/dist/renderer/keep-together-renderer.js +2 -3
- package/dist/renderer/line-renderer.d.ts +2 -1
- package/dist/renderer/line-renderer.js +7 -2
- package/dist/renderer/link-renderer.d.ts +2 -1
- package/dist/renderer/link-renderer.js +36 -5
- package/dist/renderer/padding-renderer.d.ts +2 -1
- package/dist/renderer/padding-renderer.js +5 -5
- package/dist/renderer/page-break-renderer.d.ts +6 -5
- package/dist/renderer/page-break-renderer.js +14 -7
- package/dist/renderer/page-builder-renderer.d.ts +2 -1
- package/dist/renderer/page-builder-renderer.js +2 -3
- package/dist/renderer/page-renderer.js +30 -10
- package/dist/renderer/pdf-backend.d.ts +4 -3
- package/dist/renderer/pdf-backend.js +14 -7
- package/dist/renderer/pdf-document-renderer.d.ts +1 -8
- package/dist/renderer/pdf-document-renderer.js +17 -17
- package/dist/renderer/pdf-renderer.js +20 -11
- package/dist/renderer/positioned-renderer.d.ts +18 -1
- package/dist/renderer/positioned-renderer.js +43 -6
- package/dist/renderer/rectangle-renderer.d.ts +2 -1
- package/dist/renderer/rectangle-renderer.js +18 -8
- package/dist/renderer/repeating-header-renderer.d.ts +2 -1
- package/dist/renderer/repeating-header-renderer.js +6 -5
- package/dist/renderer/rotated-renderer.d.ts +2 -1
- package/dist/renderer/rotated-renderer.js +9 -5
- package/dist/renderer/row-renderer.d.ts +2 -1
- package/dist/renderer/row-renderer.js +6 -5
- package/dist/renderer/struct-group-renderer.d.ts +2 -1
- package/dist/renderer/struct-group-renderer.js +2 -3
- package/dist/renderer/svg-renderer.d.ts +2 -1
- package/dist/renderer/svg-renderer.js +8 -2
- package/dist/renderer/text-renderer.d.ts +4 -6
- package/dist/renderer/text-renderer.js +114 -127
- package/dist/svg/gradients.js +5 -0
- package/dist/svg/index.d.ts +1 -1
- package/dist/svg/index.js +36 -6
- package/dist/svg/style.d.ts +2 -0
- package/dist/svg/style.js +12 -1
- package/dist/text/advance.d.ts +4 -0
- package/dist/text/advance.js +17 -4
- package/dist/text/bidi.d.ts +0 -2
- package/dist/text/bidi.js +0 -10
- package/dist/text/glyph-coverage.d.ts +1 -1
- package/dist/text/glyph-coverage.js +7 -3
- package/dist/text/hyphen-breaks.d.ts +17 -0
- package/dist/text/hyphen-breaks.js +54 -0
- package/dist/text/line-breaker.d.ts +55 -29
- package/dist/text/line-breaker.js +453 -188
- package/dist/text/line-metrics.d.ts +8 -3
- package/dist/text/line-metrics.js +11 -2
- package/dist/text/pdf-text-string.d.ts +21 -0
- package/dist/text/pdf-text-string.js +114 -0
- package/dist/text/text-decoration.d.ts +5 -5
- package/dist/text/text-decoration.js +5 -5
- package/dist/text/word-splitting.d.ts +15 -2
- package/dist/text/word-splitting.js +45 -13
- package/dist/utils/afm-parser.d.ts +2 -0
- package/dist/utils/afm-parser.js +10 -1
- package/dist/utils/dest-registry.d.ts +1 -1
- package/dist/utils/dest-registry.js +3 -2
- package/dist/utils/fetch-bytes.d.ts +19 -0
- package/dist/utils/fetch-bytes.js +79 -0
- package/dist/utils/flex-layout.d.ts +16 -14
- package/dist/utils/flex-layout.js +427 -217
- package/dist/utils/font-metrics.d.ts +4 -3
- package/dist/utils/image-helper.d.ts +59 -11
- package/dist/utils/image-helper.js +209 -81
- package/dist/utils/pdf-object-manager.d.ts +17 -6
- package/dist/utils/pdf-object-manager.js +70 -20
- package/dist/utils/renderer-registry.d.ts +49 -2
- package/dist/utils/renderer-registry.js +40 -0
- package/dist/utils/struct-tree.d.ts +24 -0
- package/dist/utils/struct-tree.js +61 -9
- package/dist/utils/ttf-parser.d.ts +4 -0
- package/dist/utils/ttf-parser.js +30 -6
- package/dist/validators/element-validator.js +2 -1
- package/package.json +1 -1
- package/dist/elements/layout/sized-container-element.d.ts +0 -14
- package/dist/elements/layout/sized-container-element.js +0 -32
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { FlowElement, FlowPieceElement } from "../elements/layout/flow-element.js";
|
|
2
|
+
import { RegionElement } from "../elements/layout/region-element.js";
|
|
3
|
+
import { PDFObjectManager } from "../utils/pdf-object-manager.js";
|
|
4
|
+
import { IRNode } from "../ir/display-list.js";
|
|
5
|
+
import { type RenderScope } from "../utils/renderer-registry.js";
|
|
6
|
+
/** A Flow draws the page it made (laid out in place, in a box with a height). */
|
|
7
|
+
export declare class FlowRenderer {
|
|
8
|
+
static render(flow: FlowElement, objectManager: PDFObjectManager, scope: RenderScope): Promise<IRNode[]>;
|
|
9
|
+
}
|
|
10
|
+
/** One page of a Flow: its template, whose Regions draw what they hold. */
|
|
11
|
+
export declare class FlowPieceRenderer {
|
|
12
|
+
static render(piece: FlowPieceElement, objectManager: PDFObjectManager, scope: RenderScope): Promise<IRNode[]>;
|
|
13
|
+
}
|
|
14
|
+
export declare class RegionRenderer {
|
|
15
|
+
static render(region: RegionElement, objectManager: PDFObjectManager, scope: RenderScope): Promise<IRNode[]>;
|
|
16
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { RendererRegistry, within } from "../utils/renderer-registry.js";
|
|
2
|
+
/** A Flow draws the page it made (laid out in place, in a box with a height). */
|
|
3
|
+
export class FlowRenderer {
|
|
4
|
+
static async render(flow, objectManager, scope) {
|
|
5
|
+
const { x, y, piece } = flow.getProps();
|
|
6
|
+
return piece ? RendererRegistry.render(piece, objectManager, within(scope, { x, y })) : [];
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
/** One page of a Flow: its template, whose Regions draw what they hold. */
|
|
10
|
+
export class FlowPieceRenderer {
|
|
11
|
+
static async render(piece, objectManager, scope) {
|
|
12
|
+
const { x, y, child } = piece.getProps();
|
|
13
|
+
return RendererRegistry.render(child, objectManager, within(scope, { x, y }));
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export class RegionRenderer {
|
|
17
|
+
static async render(region, objectManager, scope) {
|
|
18
|
+
const { x, y, child } = region.getProps();
|
|
19
|
+
return child ? RendererRegistry.render(child, objectManager, within(scope, { x, y })) : [];
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { RenderScope } from "../utils/renderer-registry.js";
|
|
1
2
|
import { PDFObjectManager } from "../utils/pdf-object-manager.js";
|
|
2
3
|
import { TextFieldElement } from "../elements/forms/text-field-element.js";
|
|
3
4
|
import { CheckboxElement } from "../elements/forms/checkbox-element.js";
|
|
@@ -15,6 +16,6 @@ type FormFieldElement = TextFieldElement | CheckboxElement | RadioElement | Choi
|
|
|
15
16
|
* discriminates downstream).
|
|
16
17
|
*/
|
|
17
18
|
export declare class FormFieldRenderer {
|
|
18
|
-
static render(element: FormFieldElement,
|
|
19
|
+
static render(element: FormFieldElement, objectManager: PDFObjectManager, scope: RenderScope): Promise<IRNode[]>;
|
|
19
20
|
}
|
|
20
21
|
export {};
|
|
@@ -5,8 +5,21 @@
|
|
|
5
5
|
* discriminates downstream).
|
|
6
6
|
*/
|
|
7
7
|
export class FormFieldRenderer {
|
|
8
|
-
static async render(element,
|
|
9
|
-
const
|
|
10
|
-
|
|
8
|
+
static async render(element, objectManager, scope) {
|
|
9
|
+
const props = element.getProps();
|
|
10
|
+
const { x: ownX, y: ownY, width, height, spec, style } = props;
|
|
11
|
+
const font = "font" in props ? props.font : undefined;
|
|
12
|
+
// Its own position is relative to `scope.origin`; the IR wants page coordinates.
|
|
13
|
+
const x = scope.origin.x + (ownX ?? 0);
|
|
14
|
+
const y = scope.origin.y + (ownY ?? 0);
|
|
15
|
+
// Tagged: the widget goes into a /Form element, named by its tooltip (/TU) or else its field name
|
|
16
|
+
// (PDF/UA 7.18.1, 7.18.4). A radio button is one answer of its group.
|
|
17
|
+
const name = spec.kind === "radio" ? `${spec.group}: ${spec.value}` : spec.name;
|
|
18
|
+
const structKey = objectManager.struct.enabled
|
|
19
|
+
? objectManager.struct.openElement(element.structId, "Form", {
|
|
20
|
+
alt: spec.tooltip === undefined ? name : undefined,
|
|
21
|
+
})
|
|
22
|
+
: undefined;
|
|
23
|
+
return [{ type: "formfield", x, y, width, height, field: spec, style, structKey, font }];
|
|
11
24
|
}
|
|
12
25
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import type { RenderScope } from "../utils/renderer-registry.js";
|
|
1
2
|
import { ImageElement } from "../elements/image-element.js";
|
|
2
3
|
import { PDFObjectManager } from "../utils/pdf-object-manager.js";
|
|
3
4
|
import { IRNode } from "../ir/display-list.js";
|
|
4
5
|
export declare class ImageRenderer {
|
|
5
|
-
static render(imageElement: ImageElement, objectManager: PDFObjectManager): Promise<IRNode[]>;
|
|
6
|
+
static render(imageElement: ImageElement, objectManager: PDFObjectManager, scope: RenderScope): Promise<IRNode[]>;
|
|
6
7
|
}
|
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
import { BoxFit } from "../elements/image-element.js";
|
|
2
2
|
import { bytesFromLatin1 } from "../utils/bytes.js";
|
|
3
|
-
import { applyContainFit, applyCoverFit, applyFillFit, applyFitNone, decodePngToRgbFlate, } from "../utils/image-helper.js";
|
|
3
|
+
import { applyContainFit, applyCoverFit, applyFillFit, applyFitNone, decodePngToRgbFlate, jpegColor, naturalSize, } from "../utils/image-helper.js";
|
|
4
4
|
import { isRounded } from "../ir/display-list.js";
|
|
5
5
|
export class ImageRenderer {
|
|
6
|
-
static async render(imageElement, objectManager) {
|
|
6
|
+
static async render(imageElement, objectManager, scope) {
|
|
7
7
|
// Load the image and convert it in a binary string
|
|
8
|
-
|
|
8
|
+
const { x: ownX, y: ownY, width, height, image, fit, radius, align, alt, } = imageElement.getProps();
|
|
9
|
+
// Its own position is relative to `scope.origin`; the IR wants page coordinates.
|
|
10
|
+
const x = scope.origin.x + (ownX ?? 0);
|
|
11
|
+
const y = scope.origin.y + (ownY ?? 0);
|
|
9
12
|
await image.init(); // Load and initialize the image
|
|
10
13
|
const imageType = await image.getImageType(); // For the moment we can handle `png` and `jpg/jpeg` files
|
|
11
14
|
const fileData = await image.getFileData();
|
|
12
15
|
const dimensions = await image.getImageDimensions();
|
|
16
|
+
// Laid out at its own size in points; the pixels only describe the XObject.
|
|
17
|
+
const own = naturalSize(dimensions);
|
|
13
18
|
if (!fileData) {
|
|
14
19
|
throw new Error("File data cannot be `null`");
|
|
15
20
|
}
|
|
@@ -17,71 +22,46 @@ export class ImageRenderer {
|
|
|
17
22
|
// so decode it to raw DeviceRGB samples that the FlateDecode XObject path expects.
|
|
18
23
|
let embedData = fileData;
|
|
19
24
|
let smask;
|
|
25
|
+
// A JPEG is embedded as it is, so it keeps the color space it was saved in; a PNG becomes RGB.
|
|
26
|
+
const color = imageType === "DCTDecode" ? jpegColor(bytesFromLatin1(fileData)) : undefined;
|
|
20
27
|
if (imageType === "FlateDecode") {
|
|
21
28
|
const decoded = await decodePngToRgbFlate(bytesFromLatin1(fileData));
|
|
22
29
|
embedData = decoded.data;
|
|
23
30
|
smask = decoded.smask;
|
|
24
31
|
}
|
|
25
|
-
//
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
width
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
x += fitContainResult.offsetX;
|
|
42
|
-
y += fitContainResult.offsetY;
|
|
43
|
-
width = fitContainResult.width;
|
|
44
|
-
height = fitContainResult.height;
|
|
45
|
-
break;
|
|
46
|
-
case BoxFit.none:
|
|
47
|
-
const fitNoneResult = applyFitNone(dimensions.width, dimensions.height, width ?? 0, height ?? 0);
|
|
48
|
-
x += fitNoneResult.offsetX;
|
|
49
|
-
y += fitNoneResult.offsetY;
|
|
50
|
-
width = fitNoneResult.width;
|
|
51
|
-
height = fitNoneResult.height;
|
|
52
|
-
break;
|
|
53
|
-
case BoxFit.fill:
|
|
54
|
-
const fitFillResult = applyFillFit(width ?? 0, height ?? 0);
|
|
55
|
-
width = fitFillResult.width;
|
|
56
|
-
height = fitFillResult.height;
|
|
57
|
-
}
|
|
58
|
-
// A radius rounds the image BOX (the element frame), so it clips to that frame too -
|
|
59
|
-
// independent of the cover/contain overflow clip.
|
|
60
|
-
const wantsClip = mustCreateOverflowContainer || isRounded(radius);
|
|
32
|
+
// The box laid out for it; `fit` decides what is drawn in it and where.
|
|
33
|
+
const box = {
|
|
34
|
+
x,
|
|
35
|
+
y,
|
|
36
|
+
width: width ?? own.width,
|
|
37
|
+
height: height ?? own.height,
|
|
38
|
+
};
|
|
39
|
+
const fitted = fit === BoxFit.cover
|
|
40
|
+
? applyCoverFit(own.width, own.height, box.width, box.height, align)
|
|
41
|
+
: fit === BoxFit.contain
|
|
42
|
+
? applyContainFit(own.width, own.height, box.width, box.height, align)
|
|
43
|
+
: fit === BoxFit.none
|
|
44
|
+
? applyFitNone(own.width, own.height, box.width, box.height, align)
|
|
45
|
+
: applyFillFit(box.width, box.height);
|
|
46
|
+
// Anything but `fill` may leave the box, so it is clipped to it; a radius rounds the box too.
|
|
47
|
+
const wantsClip = fit !== BoxFit.fill || isRounded(radius);
|
|
61
48
|
// The fitted geometry becomes a display-list primitive; the backend registers
|
|
62
49
|
// the XObject and emits the placement (+ clip, rounded when a radius is set).
|
|
63
50
|
const node = {
|
|
64
51
|
type: "image",
|
|
65
|
-
x,
|
|
66
|
-
y,
|
|
67
|
-
width: width,
|
|
68
|
-
height: height,
|
|
52
|
+
x: x + fitted.offsetX,
|
|
53
|
+
y: y + fitted.offsetY,
|
|
54
|
+
width: fitted.width,
|
|
55
|
+
height: fitted.height,
|
|
69
56
|
intrinsicWidth: dimensions.width,
|
|
70
57
|
intrinsicHeight: dimensions.height,
|
|
71
58
|
data: embedData,
|
|
72
59
|
imageType,
|
|
60
|
+
...(color ? { color } : {}),
|
|
61
|
+
...(dimensions.orientation ? { orientation: dimensions.orientation } : {}),
|
|
73
62
|
...(smask ? { smask } : {}),
|
|
74
63
|
...(radius ? { radius } : {}),
|
|
75
|
-
...(wantsClip
|
|
76
|
-
? {
|
|
77
|
-
clip: {
|
|
78
|
-
x: containerDimensions.x,
|
|
79
|
-
y: containerDimensions.y,
|
|
80
|
-
width: containerDimensions.width,
|
|
81
|
-
height: containerDimensions.height,
|
|
82
|
-
},
|
|
83
|
-
}
|
|
84
|
-
: {}),
|
|
64
|
+
...(wantsClip ? { clip: box } : {}),
|
|
85
65
|
};
|
|
86
66
|
// Accessible tagging: an image WITH alt text is a Figure; without, it stays untagged and the backend
|
|
87
67
|
// treats it as decoration (an Artifact). One struct element per image.
|
package/dist/renderer/index.d.ts
CHANGED
package/dist/renderer/index.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { KeepTogetherElement } from "../elements/layout/keep-together-element.js";
|
|
2
2
|
import { PDFObjectManager } from "../utils/pdf-object-manager.js";
|
|
3
3
|
import { IRNode } from "../ir/display-list.js";
|
|
4
|
+
import { type RenderScope } from "../utils/renderer-registry.js";
|
|
4
5
|
/**
|
|
5
6
|
* A `keepTogether` is layout-transparent: it just renders its child. All of its work happens in the
|
|
6
7
|
* layout pass (`fragment`), never here.
|
|
7
8
|
*/
|
|
8
9
|
export declare class KeepTogetherRenderer {
|
|
9
|
-
static render(group: KeepTogetherElement, objectManager: PDFObjectManager): Promise<IRNode[]>;
|
|
10
|
+
static render(group: KeepTogetherElement, objectManager: PDFObjectManager, scope: RenderScope): Promise<IRNode[]>;
|
|
10
11
|
}
|
|
@@ -4,9 +4,8 @@ import { RendererRegistry } from "../utils/renderer-registry.js";
|
|
|
4
4
|
* layout pass (`fragment`), never here.
|
|
5
5
|
*/
|
|
6
6
|
export class KeepTogetherRenderer {
|
|
7
|
-
static async render(group, objectManager) {
|
|
7
|
+
static async render(group, objectManager, scope) {
|
|
8
8
|
const { child } = group.getProps();
|
|
9
|
-
|
|
10
|
-
return renderer(child, objectManager);
|
|
9
|
+
return RendererRegistry.render(child, objectManager, scope);
|
|
11
10
|
}
|
|
12
11
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import type { RenderScope } from "../utils/renderer-registry.js";
|
|
1
2
|
import { PDFObjectManager } from "../utils/pdf-object-manager.js";
|
|
2
3
|
import { LineElement } from "../elements/index.js";
|
|
3
4
|
import { IRNode } from "../ir/display-list.js";
|
|
4
5
|
export declare class LineRenderer {
|
|
5
|
-
static render(lineElement: LineElement, _objectManager: PDFObjectManager): Promise<IRNode[]>;
|
|
6
|
+
static render(lineElement: LineElement, _objectManager: PDFObjectManager, scope: RenderScope): Promise<IRNode[]>;
|
|
6
7
|
}
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
export class LineRenderer {
|
|
2
|
-
static async render(lineElement, _objectManager) {
|
|
3
|
-
const { x, y, xEnd, yEnd, color, strokeWidth } = lineElement.getProps();
|
|
2
|
+
static async render(lineElement, _objectManager, scope) {
|
|
3
|
+
const { x: ownX, y: ownY, xEnd: ownXEnd, yEnd: ownYEnd, color, strokeWidth, } = lineElement.getProps();
|
|
4
|
+
// Its own position is relative to `scope.origin`; the IR wants page coordinates.
|
|
5
|
+
const x = scope.origin.x + (ownX ?? 0);
|
|
6
|
+
const y = scope.origin.y + (ownY ?? 0);
|
|
7
|
+
const xEnd = scope.origin.x + (ownXEnd ?? 0);
|
|
8
|
+
const yEnd = scope.origin.y + (ownYEnd ?? 0);
|
|
4
9
|
const node = {
|
|
5
10
|
type: "line",
|
|
6
11
|
x1: x,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { PDFObjectManager } from "../utils/pdf-object-manager.js";
|
|
2
2
|
import { LinkElement } from "../elements/layout/link-element.js";
|
|
3
|
+
import { type RenderScope } from "../utils/renderer-registry.js";
|
|
3
4
|
import { IRNode } from "../ir/display-list.js";
|
|
4
5
|
export declare class LinkRenderer {
|
|
5
|
-
static render(element: LinkElement, objectManager: PDFObjectManager): Promise<IRNode[]>;
|
|
6
|
+
static render(element: LinkElement, objectManager: PDFObjectManager, scope: RenderScope): Promise<IRNode[]>;
|
|
6
7
|
}
|
|
@@ -1,11 +1,42 @@
|
|
|
1
1
|
import { RendererRegistry } from "../utils/renderer-registry.js";
|
|
2
|
+
import { TextElement } from "../elements/text-element.js";
|
|
3
|
+
/** The text a link covers, as read - not run by run, where a justified line is one run per word. */
|
|
4
|
+
function textOf(element) {
|
|
5
|
+
if (element instanceof TextElement) {
|
|
6
|
+
return [
|
|
7
|
+
element
|
|
8
|
+
.getProps()
|
|
9
|
+
.spans.map((s) => s.content)
|
|
10
|
+
.join(""),
|
|
11
|
+
];
|
|
12
|
+
}
|
|
13
|
+
return element.layoutChildren().flatMap(textOf);
|
|
14
|
+
}
|
|
2
15
|
export class LinkRenderer {
|
|
3
|
-
static async render(element, objectManager) {
|
|
4
|
-
const { href, dest, child, x, y, width, height } = element.getProps();
|
|
5
|
-
|
|
6
|
-
const
|
|
16
|
+
static async render(element, objectManager, scope) {
|
|
17
|
+
const { href, dest, child, x: ownX, y: ownY, width, height } = element.getProps();
|
|
18
|
+
// Its own position is relative to `scope.origin`; the IR wants page coordinates.
|
|
19
|
+
const x = scope.origin.x + (ownX ?? 0);
|
|
20
|
+
const y = scope.origin.y + (ownY ?? 0);
|
|
21
|
+
const renderChild = () => RendererRegistry.render(child, objectManager, scope);
|
|
7
22
|
// The child draws normally; a Link IR node carries the clickable rect + target (external href or
|
|
8
23
|
// internal dest) for the page renderer to emit as a /Link annotation (no content-stream ops itself).
|
|
9
|
-
|
|
24
|
+
if (!objectManager.struct.enabled) {
|
|
25
|
+
return [...(await renderChild()), { type: "link", x, y, width, height, href, dest }];
|
|
26
|
+
}
|
|
27
|
+
// Tagged: the link's content sits in a /Link element, which also takes the annotation, and the
|
|
28
|
+
// annotation describes itself by the text it covers (PDF/UA 7.18.5). A split link is ONE element.
|
|
29
|
+
const struct = objectManager.struct;
|
|
30
|
+
const structKey = struct.openElement(element.structId, "Link");
|
|
31
|
+
struct.push(structKey);
|
|
32
|
+
let childNodes;
|
|
33
|
+
try {
|
|
34
|
+
childNodes = await renderChild();
|
|
35
|
+
}
|
|
36
|
+
finally {
|
|
37
|
+
struct.pop();
|
|
38
|
+
}
|
|
39
|
+
const alt = textOf(child).join(" ").replace(/\s+/g, " ").trim() || (href ?? dest ?? "");
|
|
40
|
+
return [...childNodes, { type: "link", x, y, width, height, href, dest, structKey, alt }];
|
|
10
41
|
}
|
|
11
42
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { PDFObjectManager } from "../utils/pdf-object-manager.js";
|
|
2
|
+
import { type RenderScope } from "../utils/renderer-registry.js";
|
|
2
3
|
import { PaddingElement } from "../elements/layout/padding-element.js";
|
|
3
4
|
import { IRNode } from "../ir/display-list.js";
|
|
4
5
|
export declare class PaddingRenderer {
|
|
5
|
-
static render(paddingElement: PaddingElement, objectManager: PDFObjectManager): Promise<IRNode[]>;
|
|
6
|
+
static render(paddingElement: PaddingElement, objectManager: PDFObjectManager, scope: RenderScope): Promise<IRNode[]>;
|
|
6
7
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { RendererRegistry } from "../utils/renderer-registry.js";
|
|
1
|
+
import { RendererRegistry, within } from "../utils/renderer-registry.js";
|
|
2
2
|
export class PaddingRenderer {
|
|
3
|
-
static async render(paddingElement, objectManager) {
|
|
4
|
-
const { child } = paddingElement.getProps();
|
|
5
|
-
|
|
6
|
-
return
|
|
3
|
+
static async render(paddingElement, objectManager, scope) {
|
|
4
|
+
const { x, y, child } = paddingElement.getProps();
|
|
5
|
+
// Its child is placed relative to its own top-left, inset by the margins.
|
|
6
|
+
return RendererRegistry.render(child, objectManager, within(scope, { x, y }));
|
|
7
7
|
}
|
|
8
8
|
}
|
|
@@ -1,14 +1,15 @@
|
|
|
1
|
+
import type { RenderScope } from "../utils/renderer-registry.js";
|
|
1
2
|
import { PDFObjectManager } from "../utils/pdf-object-manager.js";
|
|
2
3
|
import { PageBreakElement } from "../elements/layout/page-break-element.js";
|
|
3
4
|
import { IRNode } from "../ir/display-list.js";
|
|
4
5
|
/**
|
|
5
6
|
* A `PageBreak` draws nothing - the pagination packer consumes it at the cut, so in a vertical flow it
|
|
6
7
|
* never reaches this pass. Reaching it therefore means the break was ineffective: it sat somewhere that
|
|
7
|
-
* does not paginate
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* needs a special case.
|
|
8
|
+
* does not paginate - inside a horizontal `Row` (one line; CSS and react-pdf ignore a forced break there
|
|
9
|
+
* too), or inside a `PageBuilder`, whose content is built for the page it lands on and placed whole. We
|
|
10
|
+
* degrade to drawing nothing, but warn so the mistake is not silent. This one choke-point catches every
|
|
11
|
+
* ineffective break; no element needs a special case.
|
|
11
12
|
*/
|
|
12
13
|
export declare class PageBreakRenderer {
|
|
13
|
-
static render(
|
|
14
|
+
static render(element: PageBreakElement, objectManager: PDFObjectManager, _scope: RenderScope): Promise<IRNode[]>;
|
|
14
15
|
}
|
|
@@ -1,15 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* A `PageBreak` draws nothing - the pagination packer consumes it at the cut, so in a vertical flow it
|
|
3
3
|
* never reaches this pass. Reaching it therefore means the break was ineffective: it sat somewhere that
|
|
4
|
-
* does not paginate
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* needs a special case.
|
|
4
|
+
* does not paginate - inside a horizontal `Row` (one line; CSS and react-pdf ignore a forced break there
|
|
5
|
+
* too), or inside a `PageBuilder`, whose content is built for the page it lands on and placed whole. We
|
|
6
|
+
* degrade to drawing nothing, but warn so the mistake is not silent. This one choke-point catches every
|
|
7
|
+
* ineffective break; no element needs a special case.
|
|
8
8
|
*/
|
|
9
9
|
export class PageBreakRenderer {
|
|
10
|
-
static async render(
|
|
11
|
-
|
|
12
|
-
"
|
|
10
|
+
static async render(element, objectManager, _scope) {
|
|
11
|
+
objectManager.diagnostics.report({
|
|
12
|
+
code: "page-break-ignored",
|
|
13
|
+
severity: "warning",
|
|
14
|
+
message: "PageBreak had no effect: it is not in a paginating flow - it is inside a Row (a single " +
|
|
15
|
+
"horizontal line) or a PageBuilder (built for one page and placed whole, Columns inside it " +
|
|
16
|
+
"included). Move the break out, into a Column that flows across pages.",
|
|
17
|
+
about: element,
|
|
18
|
+
page: element.page,
|
|
19
|
+
});
|
|
13
20
|
return [];
|
|
14
21
|
}
|
|
15
22
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { PDFObjectManager } from "../utils/pdf-object-manager.js";
|
|
2
2
|
import { PageBuilderElement } from "../elements/layout/page-builder-element.js";
|
|
3
|
+
import { type RenderScope } from "../utils/renderer-registry.js";
|
|
3
4
|
import { IRNode } from "../ir/display-list.js";
|
|
4
5
|
export declare class PageBuilderRenderer {
|
|
5
|
-
static render(element: PageBuilderElement, objectManager: PDFObjectManager): Promise<IRNode[]>;
|
|
6
|
+
static render(element: PageBuilderElement, objectManager: PDFObjectManager, scope: RenderScope): Promise<IRNode[]>;
|
|
6
7
|
}
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { RendererRegistry } from "../utils/renderer-registry.js";
|
|
2
2
|
export class PageBuilderRenderer {
|
|
3
|
-
static async render(element, objectManager) {
|
|
3
|
+
static async render(element, objectManager, scope) {
|
|
4
4
|
// `composed` is whatever the closure built for THIS page during the render pass's layout.
|
|
5
5
|
const { composed } = element.getProps();
|
|
6
6
|
if (!composed)
|
|
7
7
|
return [];
|
|
8
|
-
|
|
9
|
-
return renderer(composed, objectManager);
|
|
8
|
+
return RendererRegistry.render(composed, objectManager, scope);
|
|
10
9
|
}
|
|
11
10
|
}
|
|
@@ -1,10 +1,19 @@
|
|
|
1
1
|
import { pageFormats, PageSize } from "../constants/page-sizes.js";
|
|
2
|
+
import { resolvePageContentBox } from "../elements/page-element.js";
|
|
2
3
|
import { RendererRegistry } from "../utils/renderer-registry.js";
|
|
3
4
|
import { Orientation } from "./pdf-config.js";
|
|
4
5
|
import { PdfBackend } from "./pdf-backend.js";
|
|
6
|
+
import { PositionedRenderer } from "./positioned-renderer.js";
|
|
5
7
|
export class PageRenderer {
|
|
6
8
|
static async render(page, objectManager) {
|
|
7
9
|
const { children, config, header, footer } = page.getProps();
|
|
10
|
+
RendererRegistry.beginPage(objectManager); // an element may be drawn once per page
|
|
11
|
+
// A page is the outermost box: its children's offsets are page coordinates. Its content box is the
|
|
12
|
+
// frame a `Positioned` with no `relative` ancestor was placed against.
|
|
13
|
+
const scope = {
|
|
14
|
+
origin: { x: 0, y: 0 },
|
|
15
|
+
frame: resolvePageContentBox(config).origin, // config is resolved by layout
|
|
16
|
+
};
|
|
8
17
|
// Header (top band) and footer (bottom band) sit around the body and repeat on every
|
|
9
18
|
// physical page; they are placed by `PageElement.calculateLayout` / the page driver.
|
|
10
19
|
const renderables = [...(header ? [header] : []), ...children, ...(footer ? [footer] : [])];
|
|
@@ -18,11 +27,8 @@ export class PageRenderer {
|
|
|
18
27
|
// Collect the whole page as a display list (top-left coordinates), flip it to PDF
|
|
19
28
|
// coordinates at this one seam, then serialize once. Serializing registers the
|
|
20
29
|
// fonts/images used below, so it must run before the resource section.
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
const renderer = RendererRegistry.getRenderer(element);
|
|
24
|
-
nodes.push(...(await renderer(element, objectManager)));
|
|
25
|
-
}
|
|
30
|
+
// The page is the outermost stacking context: header, body and footer share one paint order.
|
|
31
|
+
const nodes = await PositionedRenderer.paintStacked(renderables, objectManager, scope);
|
|
26
32
|
// Accessible tagging: one struct context per page (allocates its StructParents index), threaded into
|
|
27
33
|
// serialize so each drawable node is wrapped in marked content. Undefined = tagging off (byte-identical).
|
|
28
34
|
const structCtx = objectManager.struct.enabled ? objectManager.struct.beginPage() : undefined;
|
|
@@ -72,21 +78,35 @@ export class PageRenderer {
|
|
|
72
78
|
const num = (n) => Number(n.toFixed(2));
|
|
73
79
|
const annotRefs = [];
|
|
74
80
|
for (const node of flipped) {
|
|
81
|
+
if (node.type !== "link" && node.type !== "formfield")
|
|
82
|
+
continue;
|
|
83
|
+
// Tagged, every annotation names its structure element (PDF/UA 7.18).
|
|
84
|
+
const structKey = structCtx ? node.structKey : undefined;
|
|
85
|
+
const structParent = structKey === undefined ? undefined : objectManager.struct.annotationParent(structKey);
|
|
86
|
+
const tag = (obj) => {
|
|
87
|
+
if (structKey !== undefined) {
|
|
88
|
+
objectManager.struct.linkAnnotation(structKey, obj, structCtx.structParents);
|
|
89
|
+
}
|
|
90
|
+
};
|
|
75
91
|
// A form field: build its Widget annotation + register it as an /AcroForm field (the logic lives in
|
|
76
92
|
// forms/acroform.ts), then reference it here in the page /Annots - the same side channel as a link.
|
|
77
93
|
if (node.type === "formfield") {
|
|
78
|
-
|
|
94
|
+
const widget = objectManager.acroform.addField(node, objectManager, structParent);
|
|
95
|
+
tag(widget);
|
|
96
|
+
annotRefs.push(`${widget} 0 R`);
|
|
79
97
|
continue;
|
|
80
98
|
}
|
|
81
|
-
if (node.type !== "link")
|
|
82
|
-
continue;
|
|
83
99
|
const rect = `[${num(node.x)} ${num(node.y)} ${num(node.x + node.width)} ${num(node.y + node.height)}]`;
|
|
84
100
|
// Either an external URL (/URI) or an internal named destination (/GoTo, resolved via /Names /Dests).
|
|
85
101
|
// The Link IR guarantees exactly one is set; prefer `dest` when present.
|
|
86
102
|
const action = node.dest !== undefined
|
|
87
103
|
? `/A << /S /GoTo /D ${objectManager.pdfString(node.dest)} >>`
|
|
88
|
-
: `/A << /S /URI /URI ${objectManager.
|
|
89
|
-
const
|
|
104
|
+
: `/A << /S /URI /URI ${objectManager.pdfUri(node.href ?? "")} >>`;
|
|
105
|
+
const tagged = structParent === undefined
|
|
106
|
+
? ""
|
|
107
|
+
: ` /StructParent ${structParent} /Contents ${objectManager.pdfString(node.alt ?? "")}`;
|
|
108
|
+
const annot = objectManager.addObject(`<< /Type /Annot /Subtype /Link /Rect ${rect} /Border [0 0 0] ${action}${tagged} >>`);
|
|
109
|
+
tag(annot);
|
|
90
110
|
annotRefs.push(`${annot} 0 R`);
|
|
91
111
|
}
|
|
92
112
|
const annotsCode = annotRefs.length > 0 ? ` /Annots [${annotRefs.join(" ")}]` : "";
|
|
@@ -70,9 +70,10 @@ export declare class PdfBackend {
|
|
|
70
70
|
*/
|
|
71
71
|
private static roundedRectPath;
|
|
72
72
|
/**
|
|
73
|
-
* Clamp the four radii into the box
|
|
74
|
-
*
|
|
75
|
-
* folding back on itself.
|
|
73
|
+
* Clamp the four radii into the box: two radii sharing an edge are scaled down together when they
|
|
74
|
+
* would overlap - the CSS rule (css-backgrounds-3, corner overlap), and what keeps the path from
|
|
75
|
+
* folding back on itself. A single corner is NOT capped at half the box: on a 200x40 box a lone
|
|
76
|
+
* 30pt corner stays 30, as in CSS; equal corners still end at half the short side.
|
|
76
77
|
*/
|
|
77
78
|
private static clampRadii;
|
|
78
79
|
/**
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { isRounded, } from "../ir/display-list.js";
|
|
2
2
|
import { Color } from "../common/color.js";
|
|
3
|
+
import { ORIENTATION_MATRIX } from "../utils/image-helper.js";
|
|
3
4
|
/**
|
|
4
5
|
* PDF backend - turns display-list primitives into content-stream operators.
|
|
5
6
|
*
|
|
@@ -279,14 +280,14 @@ export class PdfBackend {
|
|
|
279
280
|
`h`);
|
|
280
281
|
}
|
|
281
282
|
/**
|
|
282
|
-
* Clamp the four radii into the box
|
|
283
|
-
*
|
|
284
|
-
* folding back on itself.
|
|
283
|
+
* Clamp the four radii into the box: two radii sharing an edge are scaled down together when they
|
|
284
|
+
* would overlap - the CSS rule (css-backgrounds-3, corner overlap), and what keeps the path from
|
|
285
|
+
* folding back on itself. A single corner is NOT capped at half the box: on a 200x40 box a lone
|
|
286
|
+
* 30pt corner stays 30, as in CSS; equal corners still end at half the short side.
|
|
285
287
|
*/
|
|
286
288
|
static clampRadii(radius, w, h) {
|
|
287
289
|
const n = typeof radius === "number" ? radius : 0;
|
|
288
|
-
const
|
|
289
|
-
const at = (v) => Math.max(0, Math.min(v ?? n, cap));
|
|
290
|
+
const at = (v) => Math.max(0, v ?? n);
|
|
290
291
|
const r = typeof radius === "number"
|
|
291
292
|
? { tl: at(radius), tr: at(radius), br: at(radius), bl: at(radius) }
|
|
292
293
|
: { tl: at(radius.tl), tr: at(radius.tr), br: at(radius.br), bl: at(radius.bl) };
|
|
@@ -416,8 +417,14 @@ export class PdfBackend {
|
|
|
416
417
|
case "image": {
|
|
417
418
|
// The backend owns PDF resource creation: register the XObject (using the
|
|
418
419
|
// source pixel dimensions) and then place it with a scaling matrix.
|
|
419
|
-
const ref = om.registerImage(node.intrinsicWidth, node.intrinsicHeight, node.imageType, node.data, node.smask);
|
|
420
|
-
|
|
420
|
+
const ref = om.registerImage(node.intrinsicWidth, node.intrinsicHeight, node.imageType, node.data, node.smask, node.color);
|
|
421
|
+
// The placement scales the unit square to the box; an orientation turns the pixels inside it.
|
|
422
|
+
const upright = node.orientation
|
|
423
|
+
? `${ORIENTATION_MATRIX[node.orientation].join(" ")} cm\n`
|
|
424
|
+
: "";
|
|
425
|
+
const draw = `q\n${node.width} 0 0 ${node.height} ${node.x} ${node.y} cm\n` +
|
|
426
|
+
upright +
|
|
427
|
+
`/IM${ref} Do\nQ\n`;
|
|
421
428
|
if (!node.clip)
|
|
422
429
|
return draw;
|
|
423
430
|
// Clip to the frame (re … W n); rounded when a radius is set. The rectangular
|
|
@@ -3,14 +3,7 @@ import { LayoutContext } from "../elements/pdf-element.js";
|
|
|
3
3
|
import { PDFObjectManager } from "../utils/pdf-object-manager.js";
|
|
4
4
|
export declare class PDFDocumentRenderer {
|
|
5
5
|
static render(document: PDFDocumentElement, objectManager: PDFObjectManager, ctx: LayoutContext): Promise<number>;
|
|
6
|
-
/**
|
|
7
|
-
* The page geometry a physical page will use. `PageElement.calculateLayout` has already folded the
|
|
8
|
-
* document defaults into every page's config by the time we get here (`PDFRenderer` lays the document
|
|
9
|
-
* out before it calls us, and it is our only caller). Merging again is therefore a no-op today - it is
|
|
10
|
-
* here so this stays correct BY CONSTRUCTION rather than by call order: were that order ever changed,
|
|
11
|
-
* an unmerged config would otherwise make `resolvePageSize` fall back to A4 and quietly report the
|
|
12
|
-
* wrong page size.
|
|
13
|
-
*/
|
|
6
|
+
/** The page geometry a physical page will use: resolved, never read back from an earlier layout. */
|
|
14
7
|
private static configOf;
|
|
15
8
|
/**
|
|
16
9
|
* Splits one logical page into the physical pages it will occupy, without rendering.
|