@cj-tech-master/excelts 9.6.1 → 10.0.0
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/README.md +18 -3
- package/README_zh.md +18 -3
- package/dist/browser/modules/excel/cell.d.ts +4 -0
- package/dist/browser/modules/excel/note.js +5 -1
- package/dist/browser/modules/excel/row.js +35 -2
- package/dist/browser/modules/excel/stream/workbook-writer.browser.d.ts +8 -1
- package/dist/browser/modules/excel/stream/workbook-writer.browser.js +22 -2
- package/dist/browser/modules/excel/types.d.ts +81 -0
- package/dist/browser/modules/excel/utils/drawing-utils.d.ts +8 -0
- package/dist/browser/modules/excel/utils/drawing-utils.js +19 -2
- package/dist/browser/modules/excel/workbook.browser.d.ts +16 -0
- package/dist/browser/modules/excel/workbook.browser.js +32 -2
- package/dist/browser/modules/excel/worksheet.d.ts +31 -1
- package/dist/browser/modules/excel/worksheet.js +83 -0
- package/dist/browser/modules/excel/xlsx/xform/comment/vml-shape-xform.d.ts +7 -0
- package/dist/browser/modules/excel/xlsx/xform/comment/vml-shape-xform.js +42 -8
- package/dist/browser/modules/excel/xlsx/xform/core/content-types-xform.js +3 -1
- package/dist/browser/modules/excel/xlsx/xform/drawing/absolute-anchor-xform.js +5 -0
- package/dist/browser/modules/excel/xlsx/xform/drawing/base-cell-anchor-xform.js +18 -1
- package/dist/browser/modules/excel/xlsx/xform/drawing/blip-xform.d.ts +6 -0
- package/dist/browser/modules/excel/xlsx/xform/drawing/blip-xform.js +38 -11
- package/dist/browser/modules/excel/xlsx/xform/drawing/one-cell-anchor-xform.d.ts +1 -0
- package/dist/browser/modules/excel/xlsx/xform/drawing/one-cell-anchor-xform.js +5 -0
- package/dist/browser/modules/excel/xlsx/xform/drawing/pic-xform.d.ts +2 -0
- package/dist/browser/modules/excel/xlsx/xform/drawing/pic-xform.js +2 -1
- package/dist/browser/modules/excel/xlsx/xform/drawing/shape-xform.d.ts +47 -0
- package/dist/browser/modules/excel/xlsx/xform/drawing/shape-xform.js +109 -0
- package/dist/browser/modules/excel/xlsx/xform/drawing/two-cell-anchor-xform.js +10 -1
- package/dist/browser/modules/excel/xlsx/xform/sheet/worksheet-xform.js +64 -1
- package/dist/browser/modules/pdf/builder/document-builder.js +22 -49
- package/dist/browser/modules/pdf/builder/pdf-editor.js +1 -1
- package/dist/browser/modules/pdf/core/pdf-stream.d.ts +28 -1
- package/dist/browser/modules/pdf/core/pdf-stream.js +38 -2
- package/dist/browser/modules/pdf/font/font-manager.d.ts +26 -0
- package/dist/browser/modules/pdf/font/font-manager.js +35 -18
- package/dist/browser/modules/pdf/render/page-renderer.d.ts +51 -3
- package/dist/browser/modules/pdf/render/page-renderer.js +111 -18
- package/dist/browser/modules/word/advanced/field-engine.js +45 -20
- package/dist/browser/modules/word/advanced/glossary.d.ts +10 -36
- package/dist/browser/modules/word/advanced/glossary.js +8 -9
- package/dist/browser/modules/word/advanced/math-convert.js +94 -12
- package/dist/browser/modules/word/advanced/ole-objects.d.ts +28 -0
- package/dist/browser/modules/word/advanced/ole-objects.js +122 -19
- package/dist/browser/modules/word/advanced/style-map.js +31 -10
- package/dist/browser/modules/word/builder/run-builders.d.ts +7 -1
- package/dist/browser/modules/word/builder/run-builders.js +7 -1
- package/dist/browser/modules/word/constants.d.ts +4 -0
- package/dist/browser/modules/word/constants.js +5 -1
- package/dist/browser/modules/word/convert/docx-to-semantic.d.ts +2 -1
- package/dist/browser/modules/word/convert/docx-to-semantic.js +135 -1
- package/dist/browser/modules/word/convert/html/html-import.d.ts +32 -1
- package/dist/browser/modules/word/convert/html/html-import.js +167 -14
- package/dist/browser/modules/word/convert/html/html.d.ts +2 -2
- package/dist/browser/modules/word/convert/html/html.js +1 -1
- package/dist/browser/modules/word/convert/markdown/markdown-import.d.ts +48 -18
- package/dist/browser/modules/word/convert/markdown/markdown-import.js +279 -69
- package/dist/browser/modules/word/convert/markdown/markdown.d.ts +1 -1
- package/dist/browser/modules/word/convert/odt/odt.js +407 -56
- package/dist/browser/modules/word/html.d.ts +2 -2
- package/dist/browser/modules/word/html.js +1 -1
- package/dist/browser/modules/word/index.base.d.ts +3 -3
- package/dist/browser/modules/word/index.base.js +1 -1
- package/dist/browser/modules/word/layout/layout-full.js +326 -19
- package/dist/browser/modules/word/layout/render-page.js +35 -8
- package/dist/browser/modules/word/markdown.d.ts +1 -1
- package/dist/browser/modules/word/query/compat.d.ts +10 -2
- package/dist/browser/modules/word/query/compat.js +29 -21
- package/dist/browser/modules/word/reader/docx-reader.js +105 -2
- package/dist/browser/modules/word/reader/math-parser.js +8 -2
- package/dist/browser/modules/word/security/cfb-reader.js +5 -5
- package/dist/browser/modules/word/types.d.ts +96 -1
- package/dist/browser/modules/word/writer/docx-packager.js +108 -2
- package/dist/browser/modules/word/writer/glossary-writer.d.ts +28 -0
- package/dist/browser/modules/word/writer/glossary-writer.js +121 -0
- package/dist/browser/modules/word/writer/header-footer-writer.js +105 -20
- package/dist/browser/modules/word/writer/math-writer.js +7 -2
- package/dist/browser/utils/font-metrics.d.ts +8 -0
- package/dist/browser/utils/font-metrics.js +43 -0
- package/dist/browser/utils/theme-colors.js +4 -1
- package/dist/cjs/modules/excel/note.js +5 -1
- package/dist/cjs/modules/excel/row.js +35 -2
- package/dist/cjs/modules/excel/stream/workbook-writer.browser.js +22 -2
- package/dist/cjs/modules/excel/utils/drawing-utils.js +19 -2
- package/dist/cjs/modules/excel/workbook.browser.js +31 -1
- package/dist/cjs/modules/excel/worksheet.js +83 -0
- package/dist/cjs/modules/excel/xlsx/xform/comment/vml-shape-xform.js +42 -8
- package/dist/cjs/modules/excel/xlsx/xform/core/content-types-xform.js +3 -1
- package/dist/cjs/modules/excel/xlsx/xform/drawing/absolute-anchor-xform.js +5 -0
- package/dist/cjs/modules/excel/xlsx/xform/drawing/base-cell-anchor-xform.js +18 -1
- package/dist/cjs/modules/excel/xlsx/xform/drawing/blip-xform.js +38 -11
- package/dist/cjs/modules/excel/xlsx/xform/drawing/one-cell-anchor-xform.js +5 -0
- package/dist/cjs/modules/excel/xlsx/xform/drawing/pic-xform.js +2 -1
- package/dist/cjs/modules/excel/xlsx/xform/drawing/shape-xform.js +112 -0
- package/dist/cjs/modules/excel/xlsx/xform/drawing/two-cell-anchor-xform.js +10 -1
- package/dist/cjs/modules/excel/xlsx/xform/sheet/worksheet-xform.js +64 -1
- package/dist/cjs/modules/pdf/builder/document-builder.js +21 -48
- package/dist/cjs/modules/pdf/builder/pdf-editor.js +1 -1
- package/dist/cjs/modules/pdf/core/pdf-stream.js +38 -2
- package/dist/cjs/modules/pdf/font/font-manager.js +35 -18
- package/dist/cjs/modules/pdf/render/page-renderer.js +112 -18
- package/dist/cjs/modules/word/advanced/field-engine.js +45 -20
- package/dist/cjs/modules/word/advanced/glossary.js +8 -9
- package/dist/cjs/modules/word/advanced/math-convert.js +94 -12
- package/dist/cjs/modules/word/advanced/ole-objects.js +123 -19
- package/dist/cjs/modules/word/advanced/style-map.js +31 -10
- package/dist/cjs/modules/word/builder/run-builders.js +7 -1
- package/dist/cjs/modules/word/constants.js +5 -1
- package/dist/cjs/modules/word/convert/docx-to-semantic.js +135 -1
- package/dist/cjs/modules/word/convert/html/html-import.js +168 -14
- package/dist/cjs/modules/word/convert/html/html.js +2 -1
- package/dist/cjs/modules/word/convert/markdown/markdown-import.js +279 -69
- package/dist/cjs/modules/word/convert/odt/odt.js +407 -56
- package/dist/cjs/modules/word/html.js +2 -1
- package/dist/cjs/modules/word/index.base.js +4 -3
- package/dist/cjs/modules/word/layout/layout-full.js +325 -18
- package/dist/cjs/modules/word/layout/render-page.js +35 -8
- package/dist/cjs/modules/word/query/compat.js +29 -21
- package/dist/cjs/modules/word/reader/docx-reader.js +104 -1
- package/dist/cjs/modules/word/reader/math-parser.js +8 -2
- package/dist/cjs/modules/word/security/cfb-reader.js +5 -5
- package/dist/cjs/modules/word/writer/docx-packager.js +108 -2
- package/dist/cjs/modules/word/writer/glossary-writer.js +124 -0
- package/dist/cjs/modules/word/writer/header-footer-writer.js +105 -20
- package/dist/cjs/modules/word/writer/math-writer.js +7 -2
- package/dist/cjs/utils/font-metrics.js +44 -0
- package/dist/cjs/utils/theme-colors.js +4 -1
- package/dist/esm/modules/excel/note.js +5 -1
- package/dist/esm/modules/excel/row.js +35 -2
- package/dist/esm/modules/excel/stream/workbook-writer.browser.js +22 -2
- package/dist/esm/modules/excel/utils/drawing-utils.js +19 -2
- package/dist/esm/modules/excel/workbook.browser.js +32 -2
- package/dist/esm/modules/excel/worksheet.js +83 -0
- package/dist/esm/modules/excel/xlsx/xform/comment/vml-shape-xform.js +42 -8
- package/dist/esm/modules/excel/xlsx/xform/core/content-types-xform.js +3 -1
- package/dist/esm/modules/excel/xlsx/xform/drawing/absolute-anchor-xform.js +5 -0
- package/dist/esm/modules/excel/xlsx/xform/drawing/base-cell-anchor-xform.js +18 -1
- package/dist/esm/modules/excel/xlsx/xform/drawing/blip-xform.js +38 -11
- package/dist/esm/modules/excel/xlsx/xform/drawing/one-cell-anchor-xform.js +5 -0
- package/dist/esm/modules/excel/xlsx/xform/drawing/pic-xform.js +2 -1
- package/dist/esm/modules/excel/xlsx/xform/drawing/shape-xform.js +109 -0
- package/dist/esm/modules/excel/xlsx/xform/drawing/two-cell-anchor-xform.js +10 -1
- package/dist/esm/modules/excel/xlsx/xform/sheet/worksheet-xform.js +64 -1
- package/dist/esm/modules/pdf/builder/document-builder.js +22 -49
- package/dist/esm/modules/pdf/builder/pdf-editor.js +1 -1
- package/dist/esm/modules/pdf/core/pdf-stream.js +38 -2
- package/dist/esm/modules/pdf/font/font-manager.js +35 -18
- package/dist/esm/modules/pdf/render/page-renderer.js +111 -18
- package/dist/esm/modules/word/advanced/field-engine.js +45 -20
- package/dist/esm/modules/word/advanced/glossary.js +8 -9
- package/dist/esm/modules/word/advanced/math-convert.js +94 -12
- package/dist/esm/modules/word/advanced/ole-objects.js +122 -19
- package/dist/esm/modules/word/advanced/style-map.js +31 -10
- package/dist/esm/modules/word/builder/run-builders.js +7 -1
- package/dist/esm/modules/word/constants.js +5 -1
- package/dist/esm/modules/word/convert/docx-to-semantic.js +135 -1
- package/dist/esm/modules/word/convert/html/html-import.js +167 -14
- package/dist/esm/modules/word/convert/html/html.js +1 -1
- package/dist/esm/modules/word/convert/markdown/markdown-import.js +279 -69
- package/dist/esm/modules/word/convert/odt/odt.js +407 -56
- package/dist/esm/modules/word/html.js +1 -1
- package/dist/esm/modules/word/index.base.js +1 -1
- package/dist/esm/modules/word/layout/layout-full.js +326 -19
- package/dist/esm/modules/word/layout/render-page.js +35 -8
- package/dist/esm/modules/word/query/compat.js +29 -21
- package/dist/esm/modules/word/reader/docx-reader.js +105 -2
- package/dist/esm/modules/word/reader/math-parser.js +8 -2
- package/dist/esm/modules/word/security/cfb-reader.js +5 -5
- package/dist/esm/modules/word/writer/docx-packager.js +108 -2
- package/dist/esm/modules/word/writer/glossary-writer.js +121 -0
- package/dist/esm/modules/word/writer/header-footer-writer.js +105 -20
- package/dist/esm/modules/word/writer/math-writer.js +7 -2
- package/dist/esm/utils/font-metrics.js +43 -0
- package/dist/esm/utils/theme-colors.js +4 -1
- package/dist/iife/excelts.iife.js +496 -59
- package/dist/iife/excelts.iife.js.map +1 -1
- package/dist/iife/excelts.iife.min.js +39 -39
- package/dist/types/modules/excel/cell.d.ts +4 -0
- package/dist/types/modules/excel/stream/workbook-writer.browser.d.ts +8 -1
- package/dist/types/modules/excel/types.d.ts +81 -0
- package/dist/types/modules/excel/utils/drawing-utils.d.ts +8 -0
- package/dist/types/modules/excel/workbook.browser.d.ts +16 -0
- package/dist/types/modules/excel/worksheet.d.ts +31 -1
- package/dist/types/modules/excel/xlsx/xform/comment/vml-shape-xform.d.ts +7 -0
- package/dist/types/modules/excel/xlsx/xform/drawing/blip-xform.d.ts +6 -0
- package/dist/types/modules/excel/xlsx/xform/drawing/one-cell-anchor-xform.d.ts +1 -0
- package/dist/types/modules/excel/xlsx/xform/drawing/pic-xform.d.ts +2 -0
- package/dist/types/modules/excel/xlsx/xform/drawing/shape-xform.d.ts +47 -0
- package/dist/types/modules/pdf/core/pdf-stream.d.ts +28 -1
- package/dist/types/modules/pdf/font/font-manager.d.ts +26 -0
- package/dist/types/modules/pdf/render/page-renderer.d.ts +51 -3
- package/dist/types/modules/word/advanced/glossary.d.ts +10 -36
- package/dist/types/modules/word/advanced/ole-objects.d.ts +28 -0
- package/dist/types/modules/word/builder/run-builders.d.ts +7 -1
- package/dist/types/modules/word/constants.d.ts +4 -0
- package/dist/types/modules/word/convert/docx-to-semantic.d.ts +2 -1
- package/dist/types/modules/word/convert/html/html-import.d.ts +32 -1
- package/dist/types/modules/word/convert/html/html.d.ts +2 -2
- package/dist/types/modules/word/convert/markdown/markdown-import.d.ts +48 -18
- package/dist/types/modules/word/convert/markdown/markdown.d.ts +1 -1
- package/dist/types/modules/word/html.d.ts +2 -2
- package/dist/types/modules/word/index.base.d.ts +3 -3
- package/dist/types/modules/word/markdown.d.ts +1 -1
- package/dist/types/modules/word/query/compat.d.ts +10 -2
- package/dist/types/modules/word/types.d.ts +96 -1
- package/dist/types/modules/word/writer/glossary-writer.d.ts +28 -0
- package/dist/types/utils/font-metrics.d.ts +8 -0
- package/package.json +3 -1
|
@@ -6,6 +6,7 @@ const base_cell_anchor_xform_1 = require("./base-cell-anchor-xform.js");
|
|
|
6
6
|
const ext_xform_1 = require("./ext-xform.js");
|
|
7
7
|
const graphic_frame_xform_1 = require("./graphic-frame-xform.js");
|
|
8
8
|
const pic_xform_1 = require("./pic-xform.js");
|
|
9
|
+
const shape_xform_1 = require("./shape-xform.js");
|
|
9
10
|
const static_xform_1 = require("../static-xform.js");
|
|
10
11
|
/** https://en.wikipedia.org/wiki/Office_Open_XML_file_formats#DrawingML */
|
|
11
12
|
const EMU_PER_PIXEL_AT_96_DPI = 9525;
|
|
@@ -73,6 +74,7 @@ class AbsoluteAnchorXform extends base_cell_anchor_xform_1.BaseCellAnchorXform {
|
|
|
73
74
|
// `<xdr:absoluteAnchor><xdr:pos/><xdr:ext/><xdr:clientData/></xdr:absoluteAnchor>`
|
|
74
75
|
// with no chart reference, so the anchor was ignored on open.
|
|
75
76
|
"xdr:graphicFrame": new graphic_frame_xform_1.GraphicFrameXform(),
|
|
77
|
+
"xdr:userShape": new shape_xform_1.ShapeXform(),
|
|
76
78
|
"xdr:clientData": new static_xform_1.StaticXform({ tag: "xdr:clientData" })
|
|
77
79
|
};
|
|
78
80
|
}
|
|
@@ -97,6 +99,9 @@ class AbsoluteAnchorXform extends base_cell_anchor_xform_1.BaseCellAnchorXform {
|
|
|
97
99
|
else if (model.graphicFrame) {
|
|
98
100
|
this.map["xdr:graphicFrame"].render(xmlStream, model.graphicFrame);
|
|
99
101
|
}
|
|
102
|
+
else if (model.shape?.kind === "userShape") {
|
|
103
|
+
this.map["xdr:userShape"].render(xmlStream, model.shape);
|
|
104
|
+
}
|
|
100
105
|
this.map["xdr:clientData"].render(xmlStream, {});
|
|
101
106
|
xmlStream.closeNode();
|
|
102
107
|
}
|
|
@@ -50,8 +50,25 @@ class BaseCellAnchorXform extends base_xform_1.BaseXform {
|
|
|
50
50
|
const name = match[1];
|
|
51
51
|
const mediaId = options.mediaIndex[name];
|
|
52
52
|
const medium = options.media[mediaId];
|
|
53
|
+
if (!medium) {
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
// Resolve an SVG companion (asvg:svgBlip extension) back to its media
|
|
57
|
+
// index and record it on the raster media entry itself, so callers that
|
|
58
|
+
// look the image up by id (e.g. Workbook.getImage) surface the vector
|
|
59
|
+
// companion alongside the raster fallback.
|
|
60
|
+
if (model.svgRId) {
|
|
61
|
+
const svgRel = options.rels[model.svgRId];
|
|
62
|
+
const svgMatch = svgRel && svgRel.Target.match(/.*\/media\/(.+[.][a-zA-Z]{3,4})/);
|
|
63
|
+
if (svgMatch) {
|
|
64
|
+
const svgMediaId = options.mediaIndex[svgMatch[1]];
|
|
65
|
+
if (svgMediaId !== undefined) {
|
|
66
|
+
medium.svgMediaId = svgMediaId;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
53
70
|
// Preserve alphaModFix (transparency) from the picture model if present
|
|
54
|
-
if (
|
|
71
|
+
if (model.alphaModFix !== undefined) {
|
|
55
72
|
return { ...medium, alphaModFix: model.alphaModFix };
|
|
56
73
|
}
|
|
57
74
|
return medium;
|
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.BlipXform = void 0;
|
|
4
4
|
const base_xform_1 = require("../base-xform.js");
|
|
5
|
+
/** OOXML extension URI for the SVG blip (Office 2016 SVG feature). */
|
|
6
|
+
const SVG_BLIP_EXT_URI = "{96DAC541-7B7A-43D3-8B79-37D633B846F1}";
|
|
7
|
+
/** Namespace for the asvg:svgBlip element. */
|
|
8
|
+
const SVG_BLIP_NS = "http://schemas.microsoft.com/office/drawing/2016/SVG/main";
|
|
9
|
+
const REL_NS = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
|
|
5
10
|
class BlipXform extends base_xform_1.BaseXform {
|
|
6
11
|
constructor() {
|
|
7
12
|
super();
|
|
@@ -13,23 +18,37 @@ class BlipXform extends base_xform_1.BaseXform {
|
|
|
13
18
|
render(xmlStream, model) {
|
|
14
19
|
// External (linked) images use `r:link`; embedded images use `r:embed`.
|
|
15
20
|
const relAttr = model.external ? "r:link" : "r:embed";
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
21
|
+
const hasAlpha = model.alphaModFix !== undefined && model.alphaModFix < 100000;
|
|
22
|
+
const hasSvg = model.svgRId !== undefined;
|
|
23
|
+
// A bare blip can be a leaf node; an alpha modulation or an SVG extension
|
|
24
|
+
// both require child elements, so switch to the open/close form.
|
|
25
|
+
if (!hasAlpha && !hasSvg) {
|
|
26
|
+
xmlStream.leafNode(this.tag, {
|
|
27
|
+
"xmlns:r": REL_NS,
|
|
20
28
|
[relAttr]: model.rId,
|
|
21
29
|
cstate: "print"
|
|
22
30
|
});
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
xmlStream.openNode(this.tag, {
|
|
34
|
+
"xmlns:r": REL_NS,
|
|
35
|
+
[relAttr]: model.rId,
|
|
36
|
+
cstate: "print"
|
|
37
|
+
});
|
|
38
|
+
if (hasAlpha) {
|
|
23
39
|
xmlStream.leafNode("a:alphaModFix", { amt: String(model.alphaModFix) });
|
|
24
|
-
xmlStream.closeNode();
|
|
25
40
|
}
|
|
26
|
-
|
|
27
|
-
xmlStream.
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
41
|
+
if (hasSvg) {
|
|
42
|
+
xmlStream.openNode("a:extLst");
|
|
43
|
+
xmlStream.openNode("a:ext", { uri: SVG_BLIP_EXT_URI });
|
|
44
|
+
xmlStream.leafNode("asvg:svgBlip", {
|
|
45
|
+
"xmlns:asvg": SVG_BLIP_NS,
|
|
46
|
+
"r:embed": model.svgRId
|
|
31
47
|
});
|
|
48
|
+
xmlStream.closeNode(); // a:ext
|
|
49
|
+
xmlStream.closeNode(); // a:extLst
|
|
32
50
|
}
|
|
51
|
+
xmlStream.closeNode(); // a:blip
|
|
33
52
|
}
|
|
34
53
|
parseOpen(node) {
|
|
35
54
|
switch (node.name) {
|
|
@@ -49,6 +68,14 @@ class BlipXform extends base_xform_1.BaseXform {
|
|
|
49
68
|
this.model.alphaModFix = parseInt(node.attributes.amt, 10);
|
|
50
69
|
}
|
|
51
70
|
return true;
|
|
71
|
+
case "asvg:svgBlip": {
|
|
72
|
+
// Capture the SVG companion's relationship id for round-trip.
|
|
73
|
+
const embed = node.attributes["r:embed"];
|
|
74
|
+
if (embed !== undefined && this.model) {
|
|
75
|
+
this.model.svgRId = embed;
|
|
76
|
+
}
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
52
79
|
default:
|
|
53
80
|
return true;
|
|
54
81
|
}
|
|
@@ -59,7 +86,7 @@ class BlipXform extends base_xform_1.BaseXform {
|
|
|
59
86
|
case this.tag:
|
|
60
87
|
return false;
|
|
61
88
|
default:
|
|
62
|
-
// unprocessed internal nodes
|
|
89
|
+
// unprocessed internal nodes (a:extLst / a:ext / alphaModFix)
|
|
63
90
|
return true;
|
|
64
91
|
}
|
|
65
92
|
}
|
|
@@ -6,6 +6,7 @@ const cell_position_xform_1 = require("./cell-position-xform.js");
|
|
|
6
6
|
const ext_xform_1 = require("./ext-xform.js");
|
|
7
7
|
const graphic_frame_xform_1 = require("./graphic-frame-xform.js");
|
|
8
8
|
const pic_xform_1 = require("./pic-xform.js");
|
|
9
|
+
const shape_xform_1 = require("./shape-xform.js");
|
|
9
10
|
const static_xform_1 = require("../static-xform.js");
|
|
10
11
|
class OneCellAnchorXform extends base_cell_anchor_xform_1.BaseCellAnchorXform {
|
|
11
12
|
constructor() {
|
|
@@ -14,6 +15,7 @@ class OneCellAnchorXform extends base_cell_anchor_xform_1.BaseCellAnchorXform {
|
|
|
14
15
|
"xdr:from": new cell_position_xform_1.CellPositionXform({ tag: "xdr:from" }),
|
|
15
16
|
"xdr:ext": new ext_xform_1.ExtXform({ tag: "xdr:ext" }),
|
|
16
17
|
"xdr:pic": new pic_xform_1.PicXform(),
|
|
18
|
+
"xdr:userShape": new shape_xform_1.ShapeXform(),
|
|
17
19
|
"xdr:graphicFrame": new graphic_frame_xform_1.GraphicFrameXform(),
|
|
18
20
|
"xdr:clientData": new static_xform_1.StaticXform({ tag: "xdr:clientData" })
|
|
19
21
|
};
|
|
@@ -39,6 +41,9 @@ class OneCellAnchorXform extends base_cell_anchor_xform_1.BaseCellAnchorXform {
|
|
|
39
41
|
else if (model.graphicFrame) {
|
|
40
42
|
this.map["xdr:graphicFrame"].render(xmlStream, model.graphicFrame);
|
|
41
43
|
}
|
|
44
|
+
else if (model.shape?.kind === "userShape") {
|
|
45
|
+
this.map["xdr:userShape"].render(xmlStream, model.shape);
|
|
46
|
+
}
|
|
42
47
|
this.map["xdr:clientData"].render(xmlStream, {});
|
|
43
48
|
xmlStream.closeNode();
|
|
44
49
|
}
|
|
@@ -28,7 +28,8 @@ class PicXform extends base_xform_1.BaseXform {
|
|
|
28
28
|
this.map["xdr:blipFill"].render(xmlStream, {
|
|
29
29
|
rId: model.rId,
|
|
30
30
|
alphaModFix: model.alphaModFix,
|
|
31
|
-
external: model.external
|
|
31
|
+
external: model.external,
|
|
32
|
+
svgRId: model.svgRId
|
|
32
33
|
});
|
|
33
34
|
this.map["xdr:spPr"].render(xmlStream, model);
|
|
34
35
|
xmlStream.closeNode();
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ShapeXform = void 0;
|
|
4
|
+
const base_xform_1 = require("../base-xform.js");
|
|
5
|
+
const EMU_PER_POINT = 12700;
|
|
6
|
+
/**
|
|
7
|
+
* Normalize a user-supplied colour to the bare 6-digit RGB hex that OOXML's
|
|
8
|
+
* `<a:srgbClr val="...">` requires:
|
|
9
|
+
* - strips a leading `#`
|
|
10
|
+
* - accepts 8-digit ARGB (the form excelts uses for cell fills) and drops the
|
|
11
|
+
* leading alpha byte, since `srgbClr` carries no alpha channel
|
|
12
|
+
* - upper-cases
|
|
13
|
+
*
|
|
14
|
+
* Anything that isn't a 6- or 8-digit hex string is passed through unchanged so
|
|
15
|
+
* a caller using a less common form is not silently broken.
|
|
16
|
+
*/
|
|
17
|
+
function normalizeColor(color) {
|
|
18
|
+
const hex = color.startsWith("#") ? color.slice(1) : color;
|
|
19
|
+
if (/^[0-9a-fA-F]{8}$/.test(hex)) {
|
|
20
|
+
// ARGB → RGB: drop the alpha byte (srgbClr has no alpha component).
|
|
21
|
+
return hex.slice(2).toUpperCase();
|
|
22
|
+
}
|
|
23
|
+
if (/^[0-9a-fA-F]{6}$/.test(hex)) {
|
|
24
|
+
return hex.toUpperCase();
|
|
25
|
+
}
|
|
26
|
+
return hex;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Renders a user-visible drawing shape. Geometry/position is governed by the
|
|
30
|
+
* enclosing anchor (`xfrm` is written as zero, matching how Excel anchors a
|
|
31
|
+
* shape to a cell range), while preset geometry, fill, outline and text are
|
|
32
|
+
* taken from the model. Write-only: shapes are not parsed back on read (the
|
|
33
|
+
* same limitation that already applies to all non-chart drawing content).
|
|
34
|
+
*/
|
|
35
|
+
class ShapeXform extends base_xform_1.BaseXform {
|
|
36
|
+
get tag() {
|
|
37
|
+
return "xdr:sp";
|
|
38
|
+
}
|
|
39
|
+
render(xmlStream, model) {
|
|
40
|
+
xmlStream.openNode("xdr:sp", { macro: "", textlink: "" });
|
|
41
|
+
// --- Non-visual shape properties ---
|
|
42
|
+
xmlStream.openNode("xdr:nvSpPr");
|
|
43
|
+
xmlStream.leafNode("xdr:cNvPr", { id: model.cNvPrId, name: model.name });
|
|
44
|
+
xmlStream.leafNode("xdr:cNvSpPr", {});
|
|
45
|
+
xmlStream.closeNode(); // xdr:nvSpPr
|
|
46
|
+
// --- Shape properties ---
|
|
47
|
+
xmlStream.openNode("xdr:spPr");
|
|
48
|
+
// Position/size is driven by the anchor; emit a zero xfrm placeholder.
|
|
49
|
+
xmlStream.openNode("a:xfrm");
|
|
50
|
+
xmlStream.leafNode("a:off", { x: 0, y: 0 });
|
|
51
|
+
xmlStream.leafNode("a:ext", { cx: 0, cy: 0 });
|
|
52
|
+
xmlStream.closeNode(); // a:xfrm
|
|
53
|
+
xmlStream.openNode("a:prstGeom", { prst: model.shapeType });
|
|
54
|
+
xmlStream.leafNode("a:avLst");
|
|
55
|
+
xmlStream.closeNode(); // a:prstGeom
|
|
56
|
+
// Fill: a colour produces a solidFill, otherwise an explicit noFill.
|
|
57
|
+
if (model.fill && model.fill.color) {
|
|
58
|
+
xmlStream.openNode("a:solidFill");
|
|
59
|
+
xmlStream.leafNode("a:srgbClr", { val: normalizeColor(model.fill.color) });
|
|
60
|
+
xmlStream.closeNode(); // a:solidFill
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
xmlStream.leafNode("a:noFill");
|
|
64
|
+
}
|
|
65
|
+
// Line: an `a:ln` with width (pt → EMU) and/or a solid colour. When width
|
|
66
|
+
// is given without a colour, Excel applies its default outline colour at
|
|
67
|
+
// that width. When neither colour nor width is supplied, emit an explicit
|
|
68
|
+
// noFill line (no visible outline).
|
|
69
|
+
if (model.line && (model.line.color || model.line.width !== undefined)) {
|
|
70
|
+
const lnAttrs = {};
|
|
71
|
+
if (model.line.width !== undefined) {
|
|
72
|
+
lnAttrs.w = Math.round(model.line.width * EMU_PER_POINT);
|
|
73
|
+
}
|
|
74
|
+
xmlStream.openNode("a:ln", lnAttrs);
|
|
75
|
+
if (model.line.color) {
|
|
76
|
+
xmlStream.openNode("a:solidFill");
|
|
77
|
+
xmlStream.leafNode("a:srgbClr", { val: normalizeColor(model.line.color) });
|
|
78
|
+
xmlStream.closeNode(); // a:solidFill
|
|
79
|
+
}
|
|
80
|
+
xmlStream.closeNode(); // a:ln
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
xmlStream.openNode("a:ln");
|
|
84
|
+
xmlStream.leafNode("a:noFill");
|
|
85
|
+
xmlStream.closeNode(); // a:ln
|
|
86
|
+
}
|
|
87
|
+
xmlStream.closeNode(); // xdr:spPr
|
|
88
|
+
// --- Text body ---
|
|
89
|
+
xmlStream.openNode("xdr:txBody");
|
|
90
|
+
xmlStream.leafNode("a:bodyPr", { vertOverflow: "clip", wrap: "square", anchor: "ctr" });
|
|
91
|
+
xmlStream.leafNode("a:lstStyle");
|
|
92
|
+
xmlStream.openNode("a:p");
|
|
93
|
+
xmlStream.openNode("a:pPr", { algn: "ctr" });
|
|
94
|
+
xmlStream.closeNode(); // a:pPr
|
|
95
|
+
if (model.text) {
|
|
96
|
+
xmlStream.openNode("a:r");
|
|
97
|
+
xmlStream.openNode("a:rPr", { lang: "en-US" });
|
|
98
|
+
xmlStream.closeNode(); // a:rPr
|
|
99
|
+
xmlStream.openNode("a:t");
|
|
100
|
+
xmlStream.writeText(model.text);
|
|
101
|
+
xmlStream.closeNode(); // a:t
|
|
102
|
+
xmlStream.closeNode(); // a:r
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
xmlStream.leafNode("a:endParaRPr", { lang: "en-US" });
|
|
106
|
+
}
|
|
107
|
+
xmlStream.closeNode(); // a:p
|
|
108
|
+
xmlStream.closeNode(); // xdr:txBody
|
|
109
|
+
xmlStream.closeNode(); // xdr:sp
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
exports.ShapeXform = ShapeXform;
|
|
@@ -5,6 +5,7 @@ const base_cell_anchor_xform_1 = require("./base-cell-anchor-xform.js");
|
|
|
5
5
|
const cell_position_xform_1 = require("./cell-position-xform.js");
|
|
6
6
|
const graphic_frame_xform_1 = require("./graphic-frame-xform.js");
|
|
7
7
|
const pic_xform_1 = require("./pic-xform.js");
|
|
8
|
+
const shape_xform_1 = require("./shape-xform.js");
|
|
8
9
|
const sp_xform_1 = require("./sp-xform.js");
|
|
9
10
|
const static_xform_1 = require("../static-xform.js");
|
|
10
11
|
class TwoCellAnchorXform extends base_cell_anchor_xform_1.BaseCellAnchorXform {
|
|
@@ -27,6 +28,7 @@ class TwoCellAnchorXform extends base_cell_anchor_xform_1.BaseCellAnchorXform {
|
|
|
27
28
|
"xdr:to": new cell_position_xform_1.CellPositionXform({ tag: "xdr:to" }),
|
|
28
29
|
"xdr:pic": new pic_xform_1.PicXform(),
|
|
29
30
|
"xdr:sp": new sp_xform_1.SpXform(),
|
|
31
|
+
"xdr:userShape": new shape_xform_1.ShapeXform(),
|
|
30
32
|
"xdr:graphicFrame": new graphic_frame_xform_1.GraphicFrameXform(),
|
|
31
33
|
"xdr:clientData": new static_xform_1.StaticXform({ tag: "xdr:clientData" })
|
|
32
34
|
};
|
|
@@ -128,7 +130,14 @@ class TwoCellAnchorXform extends base_cell_anchor_xform_1.BaseCellAnchorXform {
|
|
|
128
130
|
this.map["xdr:graphicFrame"].render(xmlStream, model.graphicFrame);
|
|
129
131
|
}
|
|
130
132
|
else if (model.shape) {
|
|
131
|
-
|
|
133
|
+
// A user-visible shape routes to the dedicated ShapeXform; the legacy
|
|
134
|
+
// form-control shape (no `kind`) stays on the SpXform path.
|
|
135
|
+
if (model.shape.kind === "userShape") {
|
|
136
|
+
this.map["xdr:userShape"].render(xmlStream, model.shape);
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
this.map["xdr:sp"].render(xmlStream, model.shape);
|
|
140
|
+
}
|
|
132
141
|
}
|
|
133
142
|
this.map["xdr:clientData"].render(xmlStream, {});
|
|
134
143
|
xmlStream.closeNode(); // xdr:twoCellAnchor
|
|
@@ -501,7 +501,70 @@ class WorkSheetXform extends base_xform_1.BaseXform {
|
|
|
501
501
|
});
|
|
502
502
|
}
|
|
503
503
|
}
|
|
504
|
-
// Handle
|
|
504
|
+
// Handle user-drawn shapes — anchored drawing parts with no media/rel.
|
|
505
|
+
const shapes = model.shapes ?? [];
|
|
506
|
+
if (shapes.length > 0) {
|
|
507
|
+
let { drawing } = model;
|
|
508
|
+
if (!drawing) {
|
|
509
|
+
drawing = model.drawing = {
|
|
510
|
+
rId: nextRid(rels),
|
|
511
|
+
name: `drawing${++options.drawingsCount}`,
|
|
512
|
+
anchors: [],
|
|
513
|
+
rels: []
|
|
514
|
+
};
|
|
515
|
+
options.drawings.push(drawing);
|
|
516
|
+
rels.push({
|
|
517
|
+
Id: drawing.rId,
|
|
518
|
+
Type: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing",
|
|
519
|
+
Target: (0, ooxml_paths_1.drawingRelTargetFromWorksheet)(drawing.name)
|
|
520
|
+
});
|
|
521
|
+
}
|
|
522
|
+
for (const shape of shapes) {
|
|
523
|
+
const anchorRange = shape.anchorRange;
|
|
524
|
+
if (!anchorRange) {
|
|
525
|
+
continue;
|
|
526
|
+
}
|
|
527
|
+
// Mirror the three image anchoring modes. `getAnchorType` (drawing
|
|
528
|
+
// xform) dispatches on `pos`/`br`: absolute when `pos` is present,
|
|
529
|
+
// two-cell when `br` is present, one-cell otherwise (needs `ext`).
|
|
530
|
+
let range;
|
|
531
|
+
if (anchorRange.pos) {
|
|
532
|
+
range = { pos: anchorRange.pos, ext: anchorRange.ext, editAs: "absolute" };
|
|
533
|
+
}
|
|
534
|
+
else if (anchorRange.br) {
|
|
535
|
+
range = {
|
|
536
|
+
tl: anchorRange.tl,
|
|
537
|
+
br: anchorRange.br,
|
|
538
|
+
editAs: anchorRange.editAs ?? "oneCell"
|
|
539
|
+
};
|
|
540
|
+
}
|
|
541
|
+
else {
|
|
542
|
+
range = {
|
|
543
|
+
tl: anchorRange.tl,
|
|
544
|
+
ext: anchorRange.ext,
|
|
545
|
+
editAs: anchorRange.editAs ?? "oneCell"
|
|
546
|
+
};
|
|
547
|
+
}
|
|
548
|
+
// Allocate a cNvPr id from the same monotonic space as the anchor's
|
|
549
|
+
// position in the drawing so it never collides with image/chart ids
|
|
550
|
+
// (which derive from the anchor index).
|
|
551
|
+
const cNvPrId = drawing.anchors.length + 1;
|
|
552
|
+
drawing.anchors.push({
|
|
553
|
+
range,
|
|
554
|
+
shape: {
|
|
555
|
+
kind: "userShape",
|
|
556
|
+
cNvPrId,
|
|
557
|
+
name: shape.name ?? `Shape ${cNvPrId}`,
|
|
558
|
+
shapeType: shape.shapeType,
|
|
559
|
+
fill: shape.fillColor ? { color: shape.fillColor } : undefined,
|
|
560
|
+
line: shape.lineColor !== undefined || shape.lineWidth !== undefined
|
|
561
|
+
? { color: shape.lineColor, width: shape.lineWidth }
|
|
562
|
+
: undefined,
|
|
563
|
+
text: shape.text
|
|
564
|
+
}
|
|
565
|
+
});
|
|
566
|
+
}
|
|
567
|
+
}
|
|
505
568
|
if (headerImageMedia.length > 0) {
|
|
506
569
|
const medium = headerImageMedia[0]; // Only one header image per sheet
|
|
507
570
|
const bookImage = options.media[medium.imageId];
|
|
@@ -132,56 +132,29 @@ class PdfPageBuilder {
|
|
|
132
132
|
const bold = options.bold ?? false;
|
|
133
133
|
const italic = options.italic ?? false;
|
|
134
134
|
const fontFamily = options.fontFamily ?? "Helvetica";
|
|
135
|
-
// Resolve
|
|
135
|
+
// Resolve the provisional Type1 resource and record the run's code
|
|
136
|
+
// points. The text is emitted as a deferred block so anchor alignment,
|
|
137
|
+
// word wrapping, and glyph encoding are all computed at build time —
|
|
138
|
+
// after fonts are finalised (a non-WinAnsi run may trigger a build-time
|
|
139
|
+
// auto-embed of a system CIDFont). Measuring against the provisional
|
|
140
|
+
// metrics here would misplace anchored text and break lines wrongly.
|
|
136
141
|
const resourceName = this._fontManager.resolveFont(fontFamily, bold, italic);
|
|
137
142
|
this._fontManager.trackText(text);
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
: options.
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
const lines = (0, page_renderer_1.wrapTextLines)(text, measure, options.maxWidth);
|
|
154
|
-
const leading = fontSize * lineHeightFactor;
|
|
155
|
-
this._stream.save();
|
|
156
|
-
this._applyAlpha(color.a);
|
|
157
|
-
this._stream.setFillColor(color);
|
|
158
|
-
for (let i = 0; i < lines.length; i++) {
|
|
159
|
-
const lineY = options.y - i * leading;
|
|
160
|
-
(0, page_renderer_1.emitTextWithMatrix)(this._stream, lines[i], 1, 0, 0, 1, options.x, lineY, resourceName, fontSize, this._fontManager, useType3);
|
|
161
|
-
}
|
|
162
|
-
this._stream.restore();
|
|
163
|
-
}
|
|
164
|
-
else {
|
|
165
|
-
// Single line
|
|
166
|
-
this._stream.save();
|
|
167
|
-
this._applyAlpha(color.a);
|
|
168
|
-
this._stream.setFillColor(color);
|
|
169
|
-
const rotation = options.rotation ?? 0;
|
|
170
|
-
if (rotation === 0) {
|
|
171
|
-
(0, page_renderer_1.emitTextWithMatrix)(this._stream, text, 1, 0, 0, 1, resolvedX, options.y, resourceName, fontSize, this._fontManager, useType3);
|
|
172
|
-
}
|
|
173
|
-
else {
|
|
174
|
-
// Build the rotation matrix around (x, y). `emitTextWithMatrix`
|
|
175
|
-
// accepts the full 2×3 text matrix, so we pre-multiply the
|
|
176
|
-
// rotation with the translation so one call positions and
|
|
177
|
-
// rotates the glyph sequence in a single Tm op.
|
|
178
|
-
const theta = (rotation * Math.PI) / 180;
|
|
179
|
-
const cos = Math.cos(theta);
|
|
180
|
-
const sin = Math.sin(theta);
|
|
181
|
-
(0, page_renderer_1.emitTextWithMatrix)(this._stream, text, cos, sin, -sin, cos, resolvedX, options.y, resourceName, fontSize, this._fontManager, useType3);
|
|
182
|
-
}
|
|
183
|
-
this._stream.restore();
|
|
184
|
-
}
|
|
143
|
+
this._stream.save();
|
|
144
|
+
this._applyAlpha(color.a);
|
|
145
|
+
this._stream.setFillColor(color);
|
|
146
|
+
(0, page_renderer_1.emitTextBlock)(this._stream, {
|
|
147
|
+
text,
|
|
148
|
+
x: options.x,
|
|
149
|
+
y: options.y,
|
|
150
|
+
type1ResourceName: resourceName,
|
|
151
|
+
fontSize,
|
|
152
|
+
anchor: options.anchor ?? "start",
|
|
153
|
+
maxWidth: options.maxWidth,
|
|
154
|
+
lineHeightFactor,
|
|
155
|
+
rotation: options.rotation ?? 0
|
|
156
|
+
}, this._fontManager);
|
|
157
|
+
this._stream.restore();
|
|
185
158
|
return this;
|
|
186
159
|
}
|
|
187
160
|
/**
|
|
@@ -180,7 +180,7 @@ class PdfEditorPage {
|
|
|
180
180
|
}
|
|
181
181
|
/** @internal */
|
|
182
182
|
_hasOverlay() {
|
|
183
|
-
return (this._overlay._stream.
|
|
183
|
+
return (this._overlay._stream.hasContent() ||
|
|
184
184
|
this._overlay._images.length > 0 ||
|
|
185
185
|
this._overlay._builderAnnotations.length > 0 ||
|
|
186
186
|
this._overlay._formFields.length > 0);
|
|
@@ -28,6 +28,16 @@ const pdf_object_1 = require("./pdf-object");
|
|
|
28
28
|
*/
|
|
29
29
|
class PdfContentStream {
|
|
30
30
|
constructor() {
|
|
31
|
+
/**
|
|
32
|
+
* Content stream fragments in draw order. Most entries are plain operator
|
|
33
|
+
* strings produced eagerly. A function entry is a *deferred* fragment:
|
|
34
|
+
* its body is only evaluated at serialization time. This is required for
|
|
35
|
+
* text whose final byte encoding depends on font decisions (embedded
|
|
36
|
+
* CIDFont vs. Type1/WinAnsi vs. Type3 fallback) that are not finalised
|
|
37
|
+
* until `PdfDocumentBuilder.build()`. Deferring keeps the fragment at its
|
|
38
|
+
* exact draw-order position (preserving z-order) while letting the actual
|
|
39
|
+
* encoding run after the font manager's state is settled.
|
|
40
|
+
*/
|
|
31
41
|
this.parts = [];
|
|
32
42
|
}
|
|
33
43
|
// ===========================================================================
|
|
@@ -41,6 +51,17 @@ class PdfContentStream {
|
|
|
41
51
|
this.parts.push(operator);
|
|
42
52
|
return this;
|
|
43
53
|
}
|
|
54
|
+
/**
|
|
55
|
+
* Append a deferred fragment whose body is evaluated only at serialization
|
|
56
|
+
* time. Used by text drawing so the final byte encoding can be chosen after
|
|
57
|
+
* the document's fonts are resolved at build time. The fragment occupies its
|
|
58
|
+
* draw-order slot immediately, so z-order relative to other operators is
|
|
59
|
+
* preserved.
|
|
60
|
+
*/
|
|
61
|
+
deferred(produce) {
|
|
62
|
+
this.parts.push(produce);
|
|
63
|
+
return this;
|
|
64
|
+
}
|
|
44
65
|
// ===========================================================================
|
|
45
66
|
// Graphics State
|
|
46
67
|
// ===========================================================================
|
|
@@ -440,10 +461,25 @@ class PdfContentStream {
|
|
|
440
461
|
// Serialization
|
|
441
462
|
// ===========================================================================
|
|
442
463
|
/**
|
|
443
|
-
*
|
|
464
|
+
* Whether any fragment has been appended. Unlike `toString().length > 0`,
|
|
465
|
+
* this does NOT evaluate deferred fragments, so it is safe to call before
|
|
466
|
+
* fonts are resolved (e.g. when probing for overlay content during an
|
|
467
|
+
* editor save, prior to `writeFontResources`). A deferred text fragment
|
|
468
|
+
* counts as content even though its bytes are not produced yet.
|
|
469
|
+
*/
|
|
470
|
+
hasContent() {
|
|
471
|
+
return this.parts.length > 0;
|
|
472
|
+
}
|
|
473
|
+
/**
|
|
474
|
+
* Get the content stream as a string. Deferred fragments (see `deferred`)
|
|
475
|
+
* are evaluated here, after font resolution has completed at build time.
|
|
444
476
|
*/
|
|
445
477
|
toString() {
|
|
446
|
-
|
|
478
|
+
const out = [];
|
|
479
|
+
for (const part of this.parts) {
|
|
480
|
+
out.push(typeof part === "function" ? part() : part);
|
|
481
|
+
}
|
|
482
|
+
return out.join("\n");
|
|
447
483
|
}
|
|
448
484
|
/**
|
|
449
485
|
* Get the content stream as a Uint8Array (UTF-8 encoded).
|
|
@@ -186,30 +186,47 @@ class FontManager {
|
|
|
186
186
|
getEmbeddedResourceName() {
|
|
187
187
|
return this.embeddedResourceName;
|
|
188
188
|
}
|
|
189
|
+
/**
|
|
190
|
+
* Resolve the resource name a draw-time-resolved Type1 resource should
|
|
191
|
+
* actually render (and be measured) with, given the font manager's
|
|
192
|
+
* *current* state. If an embedded font exists (possibly auto-discovered
|
|
193
|
+
* at build time, after the text was drawn against a Type1 resource), the
|
|
194
|
+
* embedded resource name is returned so both measurement and encoding go
|
|
195
|
+
* through the CIDFont. Otherwise the original Type1 resource name is kept;
|
|
196
|
+
* `measureText` handles Type3-fallback widths internally from that name.
|
|
197
|
+
*
|
|
198
|
+
* Centralises the routing rule shared by the deferred text renderer and
|
|
199
|
+
* any deferred measurement (anchor alignment, word wrapping) so the two
|
|
200
|
+
* never disagree.
|
|
201
|
+
*/
|
|
202
|
+
resolveRenderResourceName(type1ResourceName) {
|
|
203
|
+
return this.embeddedFont ? this.embeddedResourceName : type1ResourceName;
|
|
204
|
+
}
|
|
189
205
|
/**
|
|
190
206
|
* Record that a text string will be rendered, tracking its code points.
|
|
191
207
|
* Must be called for every text string before writing the PDF.
|
|
208
|
+
*
|
|
209
|
+
* Two sets are maintained because font selection may be decided *after*
|
|
210
|
+
* drawing (e.g. `PdfDocumentBuilder.build()` auto-discovers and embeds a
|
|
211
|
+
* system font once it sees the accumulated non-WinAnsi code points):
|
|
212
|
+
*
|
|
213
|
+
* - `usedCodePoints` — every code point seen, always. If an embedded
|
|
214
|
+
* font ends up being used (whether registered up front or
|
|
215
|
+
* auto-discovered at build time), the subset must cover all of these,
|
|
216
|
+
* including plain ASCII, so the CIDFont can encode the full run.
|
|
217
|
+
* - `type3CodePoints` — non-WinAnsi code points only. Drives the
|
|
218
|
+
* build-time decision to auto-embed a system font, and the Type3
|
|
219
|
+
* fallback when none is available.
|
|
192
220
|
*/
|
|
193
221
|
trackText(text) {
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
if (cp > 0xffff) {
|
|
199
|
-
i++; // skip low surrogate
|
|
200
|
-
}
|
|
222
|
+
for (let i = 0; i < text.length; i++) {
|
|
223
|
+
const cp = text.codePointAt(i);
|
|
224
|
+
if (cp > 0xffff) {
|
|
225
|
+
i++; // skip low surrogate
|
|
201
226
|
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
for (let i = 0; i < text.length; i++) {
|
|
206
|
-
const cp = text.codePointAt(i);
|
|
207
|
-
if (cp > 0xffff) {
|
|
208
|
-
i++;
|
|
209
|
-
}
|
|
210
|
-
if (!(0, pdf_stream_1.isWinAnsiCodePoint)(cp)) {
|
|
211
|
-
this.type3CodePoints.add(cp);
|
|
212
|
-
}
|
|
227
|
+
this.usedCodePoints.add(cp);
|
|
228
|
+
if (!(0, pdf_stream_1.isWinAnsiCodePoint)(cp)) {
|
|
229
|
+
this.type3CodePoints.add(cp);
|
|
213
230
|
}
|
|
214
231
|
}
|
|
215
232
|
}
|