reamkit 1.30.0 → 1.32.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 +70 -24
- package/dist/esm/core/bidi/index.d.ts +10 -0
- package/dist/esm/core/bidi/index.js +18 -2
- package/dist/esm/core/converter/facade.js +10 -5
- package/dist/esm/core/converter/project.js +4 -1
- package/dist/esm/core/converter/ream.js +17 -6
- package/dist/esm/core/converter/sheet-images.d.ts +17 -0
- package/dist/esm/core/converter/sheet-images.js +33 -0
- package/dist/esm/core/crypto/offcrypto.js +1 -1
- package/dist/esm/core/document-model/index.d.ts +1 -1
- package/dist/esm/core/document-model/types.d.ts +175 -0
- package/dist/esm/core/drawingml/chart-geometry.d.ts +21 -8
- package/dist/esm/core/drawingml/chart-geometry.js +198 -108
- package/dist/esm/core/drawingml/chart-parser.js +73 -2
- package/dist/esm/core/drawingml/colors.d.ts +6 -0
- package/dist/esm/core/drawingml/colors.js +23 -3
- package/dist/esm/core/drawingml/shape-render.d.ts +3 -1
- package/dist/esm/core/drawingml/shape-render.js +4 -2
- package/dist/esm/core/font/index.d.ts +2 -0
- package/dist/esm/core/font/measure.d.ts +9 -0
- package/dist/esm/core/font/measure.js +9 -1
- package/dist/esm/core/font/ttf-build.d.ts +113 -0
- package/dist/esm/core/font/ttf-build.js +1224 -0
- package/dist/esm/core/font/ttf-subset.d.ts +19 -0
- package/dist/esm/core/font/ttf-subset.js +14 -1
- package/dist/esm/core/fonts/families.js +4 -2
- package/dist/esm/core/fonts/provider.d.ts +17 -0
- package/dist/esm/core/fonts/provider.js +27 -2
- package/dist/esm/core/fonts/remote-fonts.js +8 -1
- package/dist/esm/core/fonts/scripts.js +4 -2
- package/dist/esm/core/ir/flow.d.ts +77 -1
- package/dist/esm/core/ir/sheet.d.ts +43 -0
- package/dist/esm/core/number-format.js +16 -11
- package/dist/esm/core/numbering/index.d.ts +1 -1
- package/dist/esm/core/numbering/state.d.ts +11 -1
- package/dist/esm/core/numbering/state.js +10 -1
- package/dist/esm/core/spreadsheet-model/index.d.ts +1 -1
- package/dist/esm/core/spreadsheet-model/types.d.ts +96 -0
- package/dist/esm/core/style-cascade/resolver.js +39 -6
- package/dist/esm/core/style-cascade/types.d.ts +19 -1
- package/dist/esm/core/style-cascade/types.js +3 -0
- package/dist/esm/excel/column-bands.d.ts +39 -6
- package/dist/esm/excel/column-bands.js +41 -17
- package/dist/esm/excel/comments-parser.js +19 -0
- package/dist/esm/excel/conditional-format.d.ts +7 -3
- package/dist/esm/excel/conditional-format.js +77 -39
- package/dist/esm/excel/formula/context.d.ts +18 -0
- package/dist/esm/excel/formula/eval.js +51 -0
- package/dist/esm/excel/formula/index.d.ts +2 -2
- package/dist/esm/excel/formula/lexer.d.ts +1 -1
- package/dist/esm/excel/formula/lexer.js +41 -0
- package/dist/esm/excel/formula/parser.d.ts +25 -0
- package/dist/esm/excel/formula/parser.js +95 -0
- package/dist/esm/excel/print-model.d.ts +38 -1
- package/dist/esm/excel/print-model.js +522 -80
- package/dist/esm/excel/shared-strings-parser.d.ts +9 -0
- package/dist/esm/excel/shared-strings-parser.js +11 -1
- package/dist/esm/excel/sheet-drawing.d.ts +38 -2
- package/dist/esm/excel/sheet-drawing.js +47 -13
- package/dist/esm/excel/sheet-shape-parser.d.ts +6 -2
- package/dist/esm/excel/sheet-shape-parser.js +18 -6
- package/dist/esm/excel/sheet-to-flow.d.ts +17 -0
- package/dist/esm/excel/sheet-to-flow.js +434 -47
- package/dist/esm/excel/styles-parser.d.ts +9 -0
- package/dist/esm/excel/styles-parser.js +80 -26
- package/dist/esm/excel/table-parser.js +5 -0
- package/dist/esm/excel/table-style-presets.d.ts +26 -0
- package/dist/esm/excel/table-style-presets.js +1555 -0
- package/dist/esm/excel/table-style.d.ts +13 -0
- package/dist/esm/excel/table-style.js +75 -0
- package/dist/esm/excel/tint.d.ts +10 -0
- package/dist/esm/excel/tint.js +75 -0
- package/dist/esm/excel/vml-drawing.d.ts +41 -3
- package/dist/esm/excel/vml-drawing.js +143 -10
- package/dist/esm/excel/worksheet-parser.js +89 -15
- package/dist/esm/excel/xls/biff-reader.js +10 -2
- package/dist/esm/excel/xlsx-reader.js +195 -14
- package/dist/esm/excel/xlsx-writer.js +8 -7
- package/dist/esm/html/html-writer.js +202 -20
- package/dist/esm/index.d.ts +2 -2
- package/dist/esm/layout/fit-pages.d.ts +11 -0
- package/dist/esm/layout/fit-pages.js +86 -0
- package/dist/esm/layout/line-paint.d.ts +58 -0
- package/dist/esm/layout/line-paint.js +107 -0
- package/dist/esm/layout/page-doc.d.ts +61 -3
- package/dist/esm/layout/page-doc.js +141 -1
- package/dist/esm/layout/styled-layout.d.ts +55 -7
- package/dist/esm/layout/styled-layout.js +1154 -169
- package/dist/esm/layout/turned-section.d.ts +38 -0
- package/dist/esm/layout/turned-section.js +205 -0
- package/dist/esm/markdown/markdown-writer.js +17 -6
- package/dist/esm/pdf/styled-page-emitter.js +114 -60
- package/dist/esm/pdf/styled-page-renderer.js +1 -1
- package/dist/esm/pdf-reader/cff-outline.d.ts +27 -0
- package/dist/esm/pdf-reader/cff-outline.js +169 -21
- package/dist/esm/pdf-reader/content.d.ts +53 -0
- package/dist/esm/pdf-reader/content.js +9 -1
- package/dist/esm/pdf-reader/display.d.ts +36 -0
- package/dist/esm/pdf-reader/display.js +66 -1
- package/dist/esm/pdf-reader/document.js +5 -1
- package/dist/esm/pdf-reader/embedded-fonts.d.ts +2 -1
- package/dist/esm/pdf-reader/embedded-fonts.js +32 -2
- package/dist/esm/pdf-reader/encodings.d.ts +8 -0
- package/dist/esm/pdf-reader/encodings.js +25 -3
- package/dist/esm/pdf-reader/face-outlines.d.ts +78 -0
- package/dist/esm/pdf-reader/face-outlines.js +362 -0
- package/dist/esm/pdf-reader/figures.d.ts +52 -0
- package/dist/esm/pdf-reader/figures.js +433 -0
- package/dist/esm/pdf-reader/flow-build.d.ts +131 -5
- package/dist/esm/pdf-reader/flow-build.js +345 -26
- package/dist/esm/pdf-reader/font.js +321 -36
- package/dist/esm/pdf-reader/glyf-outline.d.ts +33 -0
- package/dist/esm/pdf-reader/glyf-outline.js +135 -1
- package/dist/esm/pdf-reader/glyph-names.js +154 -1
- package/dist/esm/pdf-reader/layout.d.ts +93 -0
- package/dist/esm/pdf-reader/layout.js +1703 -214
- package/dist/esm/pdf-reader/page-numbers.d.ts +53 -0
- package/dist/esm/pdf-reader/page-numbers.js +167 -0
- package/dist/esm/pdf-reader/tagged.js +182 -23
- package/dist/esm/pdf-reader/text.d.ts +6 -3
- package/dist/esm/pdf-reader/text.js +98 -9
- package/dist/esm/pdf-reader/type1-outline.d.ts +11 -0
- package/dist/esm/pdf-reader/type1-outline.js +63 -8
- package/dist/esm/pdf-reader/vector.js +71 -1
- package/dist/esm/svg/svg-text.d.ts +58 -0
- package/dist/esm/svg/svg-text.js +322 -0
- package/dist/esm/svg/svg-writer.js +135 -71
- package/dist/esm/word/doc/doc-reader.js +6 -2
- package/dist/esm/word/doc/doc-text.d.ts +6 -0
- package/dist/esm/word/doc/doc-text.js +19 -1
- package/dist/esm/word/document-parser.d.ts +2 -2
- package/dist/esm/word/document-parser.js +11 -1
- package/dist/esm/word/docx-reader.js +5 -3
- package/dist/esm/word/docx-writer.js +218 -23
- package/dist/esm/word/drawing-parser.d.ts +5 -3
- package/dist/esm/word/drawing-parser.js +49 -8
- package/dist/esm/word/font-embed.d.ts +30 -0
- package/dist/esm/word/font-embed.js +173 -0
- package/dist/esm/word/font-table.d.ts +10 -0
- package/dist/esm/word/font-table.js +13 -1
- package/dist/esm/word/index.js +1 -1
- package/dist/esm/word/numbering-parser.d.ts +3 -1
- package/dist/esm/word/numbering-parser.js +2 -1
- package/dist/esm/word/paragraph-properties.d.ts +7 -6
- package/dist/esm/word/paragraph-properties.js +14 -2
- package/dist/esm/word/run-properties.js +26 -0
- package/package.json +12 -3
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { BodyElement } from '../core/document-model/index.js';
|
|
2
|
+
import { PageItem } from './page-doc.js';
|
|
3
|
+
/** The sheet a turned section prints on, and the margins it states for it. */
|
|
4
|
+
export interface Sheet {
|
|
5
|
+
readonly width: number;
|
|
6
|
+
readonly height: number;
|
|
7
|
+
readonly marginLeft: number;
|
|
8
|
+
readonly marginRight: number;
|
|
9
|
+
readonly marginTop: number;
|
|
10
|
+
readonly marginBottom: number;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* One item of a turned section's body, carried from the frame the text reads
|
|
14
|
+
* in onto the sheet: a point `(x, y)` of the frame (top-left origin, y down)
|
|
15
|
+
* lands at `(sheetWidth − y, x)` — the frame's top edge is the sheet's right
|
|
16
|
+
* edge, and its left edge the sheet's top.
|
|
17
|
+
*
|
|
18
|
+
* @param item The item as the frame's layout placed it.
|
|
19
|
+
* @param sheetWidth The sheet's width, which is the frame's height.
|
|
20
|
+
* @returns The same item on the sheet, turned a quarter clockwise.
|
|
21
|
+
*/
|
|
22
|
+
export declare function turnOntoSheet(item: PageItem, sheetWidth: number): PageItem;
|
|
23
|
+
/**
|
|
24
|
+
* A drawing anchored in a turned section, given the place in the text's frame
|
|
25
|
+
* from which turning the body carries it to where Word stands it: on the sheet,
|
|
26
|
+
* at the offsets its anchor states, upright.
|
|
27
|
+
*
|
|
28
|
+
* The anchor is resolved against the SHEET — its page, its margins and the
|
|
29
|
+
* bands beside them. What is measured from the text itself (a paragraph, a
|
|
30
|
+
* line, a column) has no place on the sheet before the text is laid out, and is
|
|
31
|
+
* measured from the margin instead. Only pictures and shapes are carried; a
|
|
32
|
+
* chart or a floating table turns with the text.
|
|
33
|
+
*
|
|
34
|
+
* @param el The body element, anchored or not.
|
|
35
|
+
* @param sheet The sheet the section prints on.
|
|
36
|
+
* @returns The element, its anchor restated in the frame and its turn backed off.
|
|
37
|
+
*/
|
|
38
|
+
export declare function floatIntoFrame(el: BodyElement, sheet: Sheet): BodyElement;
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { pt } from "../core/ir/units.js";
|
|
2
|
+
//#region src/layout/turned-section.ts
|
|
3
|
+
/** A quarter turn in the 1/60000° a DrawingML rotation is stated in (§20.1.7.6). */
|
|
4
|
+
var QUARTER_60K = 90 * 6e4;
|
|
5
|
+
/**
|
|
6
|
+
* One item of a turned section's body, carried from the frame the text reads
|
|
7
|
+
* in onto the sheet: a point `(x, y)` of the frame (top-left origin, y down)
|
|
8
|
+
* lands at `(sheetWidth − y, x)` — the frame's top edge is the sheet's right
|
|
9
|
+
* edge, and its left edge the sheet's top.
|
|
10
|
+
*
|
|
11
|
+
* @param item The item as the frame's layout placed it.
|
|
12
|
+
* @param sheetWidth The sheet's width, which is the frame's height.
|
|
13
|
+
* @returns The same item on the sheet, turned a quarter clockwise.
|
|
14
|
+
*/
|
|
15
|
+
function turnOntoSheet(item, sheetWidth) {
|
|
16
|
+
const turned = turnItem(item, sheetWidth);
|
|
17
|
+
const w = item.window;
|
|
18
|
+
return w ? {
|
|
19
|
+
...turned,
|
|
20
|
+
window: turnBox(w.x, w.y, w.width, w.height, sheetWidth)
|
|
21
|
+
} : turned;
|
|
22
|
+
}
|
|
23
|
+
/** A top-left-frame box of the frame, as it stands on the sheet once turned a quarter clockwise. */
|
|
24
|
+
function turnBox(x, y, w, h, sheetWidth) {
|
|
25
|
+
return {
|
|
26
|
+
x: pt(sheetWidth - y - h),
|
|
27
|
+
y: pt(x),
|
|
28
|
+
width: pt(h),
|
|
29
|
+
height: pt(w)
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
function turnItem(item, sheetWidth) {
|
|
33
|
+
const box = (x, y, w, h) => turnBox(x, y, w, h, sheetWidth);
|
|
34
|
+
switch (item.type) {
|
|
35
|
+
case "line": {
|
|
36
|
+
const quarter = withinTurn((item.rotationDeg ?? 0) - 90);
|
|
37
|
+
const turned = quarter > 180 ? quarter - 360 : quarter;
|
|
38
|
+
const { rotationDeg: _flat, clip, ...rest } = item;
|
|
39
|
+
return {
|
|
40
|
+
...rest,
|
|
41
|
+
originX: pt(sheetWidth - item.baselineY),
|
|
42
|
+
baselineY: pt(item.originX),
|
|
43
|
+
...turned !== 0 ? { rotationDeg: turned } : {},
|
|
44
|
+
...clip ? { clip: box(clip.x, clip.y, clip.width, clip.height) } : {}
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
case "image": {
|
|
48
|
+
const cx = item.x + item.width / 2;
|
|
49
|
+
const cy = item.y + item.height / 2;
|
|
50
|
+
const turned = withinTurn((item.rotationDeg ?? 0) + 90);
|
|
51
|
+
const { rotationDeg: _flat, clip, ...rest } = item;
|
|
52
|
+
return {
|
|
53
|
+
...rest,
|
|
54
|
+
x: pt(sheetWidth - cy - item.width / 2),
|
|
55
|
+
y: pt(cx - item.height / 2),
|
|
56
|
+
...turned !== 0 ? { rotationDeg: turned } : {},
|
|
57
|
+
...clip ? { clip: {
|
|
58
|
+
paths: clip.paths,
|
|
59
|
+
transform: turnMatrix(clip.transform, sheetWidth)
|
|
60
|
+
} } : {}
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
case "shape": {
|
|
64
|
+
const shadow = item.shape.shadow;
|
|
65
|
+
return {
|
|
66
|
+
...item,
|
|
67
|
+
shape: {
|
|
68
|
+
...item.shape,
|
|
69
|
+
transform: turnMatrix(item.shape.transform, sheetWidth),
|
|
70
|
+
...shadow ? { shadow: {
|
|
71
|
+
...shadow,
|
|
72
|
+
dxPt: -shadow.dyPt,
|
|
73
|
+
dyPt: shadow.dxPt
|
|
74
|
+
} } : {}
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
case "border": return {
|
|
79
|
+
...item,
|
|
80
|
+
...box(item.x, item.y, item.width, item.height),
|
|
81
|
+
side: TURNED_SIDE[item.side]
|
|
82
|
+
};
|
|
83
|
+
case "fill": return {
|
|
84
|
+
...item,
|
|
85
|
+
...box(item.x, item.y, item.width, item.height)
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/** An angle in degrees brought into one full turn, `[0, 360)`, with the float noise off. */
|
|
90
|
+
function withinTurn(deg) {
|
|
91
|
+
const t = (deg % 360 + 360) % 360;
|
|
92
|
+
return Math.abs(t) < 1e-9 || Math.abs(t - 360) < 1e-9 ? 0 : t;
|
|
93
|
+
}
|
|
94
|
+
/** Which edge of a box each edge becomes when the box turns a quarter clockwise. */
|
|
95
|
+
var TURNED_SIDE = {
|
|
96
|
+
top: "right",
|
|
97
|
+
right: "bottom",
|
|
98
|
+
bottom: "left",
|
|
99
|
+
left: "top"
|
|
100
|
+
};
|
|
101
|
+
/**
|
|
102
|
+
* A local→page matrix `[a b c d e f]` (x' = a·u + c·v + e, y' = b·u + d·v + f,
|
|
103
|
+
* page top-left, y down) followed by the turn onto the sheet.
|
|
104
|
+
*/
|
|
105
|
+
function turnMatrix(m, sheetWidth) {
|
|
106
|
+
return [
|
|
107
|
+
-m[1],
|
|
108
|
+
m[0],
|
|
109
|
+
-m[3],
|
|
110
|
+
m[2],
|
|
111
|
+
sheetWidth - m[5],
|
|
112
|
+
m[4]
|
|
113
|
+
];
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* A drawing anchored in a turned section, given the place in the text's frame
|
|
117
|
+
* from which turning the body carries it to where Word stands it: on the sheet,
|
|
118
|
+
* at the offsets its anchor states, upright.
|
|
119
|
+
*
|
|
120
|
+
* The anchor is resolved against the SHEET — its page, its margins and the
|
|
121
|
+
* bands beside them. What is measured from the text itself (a paragraph, a
|
|
122
|
+
* line, a column) has no place on the sheet before the text is laid out, and is
|
|
123
|
+
* measured from the margin instead. Only pictures and shapes are carried; a
|
|
124
|
+
* chart or a floating table turns with the text.
|
|
125
|
+
*
|
|
126
|
+
* @param el The body element, anchored or not.
|
|
127
|
+
* @param sheet The sheet the section prints on.
|
|
128
|
+
* @returns The element, its anchor restated in the frame and its turn backed off.
|
|
129
|
+
*/
|
|
130
|
+
function floatIntoFrame(el, sheet) {
|
|
131
|
+
if (el.kind === "image" && el.image.float !== void 0) {
|
|
132
|
+
const { image } = el;
|
|
133
|
+
const float = image.float;
|
|
134
|
+
const placed = frameAnchor(float, image.width, image.height, sheet);
|
|
135
|
+
return {
|
|
136
|
+
...el,
|
|
137
|
+
image: {
|
|
138
|
+
...image,
|
|
139
|
+
float: placed,
|
|
140
|
+
rotation60k: backedOff(image.rotation60k)
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
if (el.kind === "shape" && el.shape.float !== void 0) {
|
|
145
|
+
const { shape } = el;
|
|
146
|
+
const float = shape.float;
|
|
147
|
+
const placed = frameAnchor(float, shape.width, shape.height, sheet);
|
|
148
|
+
return {
|
|
149
|
+
...el,
|
|
150
|
+
shape: {
|
|
151
|
+
...shape,
|
|
152
|
+
float: placed,
|
|
153
|
+
transform: {
|
|
154
|
+
...shape.transform,
|
|
155
|
+
rotation60k: backedOff(shape.transform?.rotation60k)
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
return el;
|
|
161
|
+
}
|
|
162
|
+
/** A clockwise turn with a quarter taken off, kept in the one full turn. */
|
|
163
|
+
function backedOff(rotation60k) {
|
|
164
|
+
const full = 360 * 6e4;
|
|
165
|
+
return (((rotation60k ?? 0) - QUARTER_60K) % full + full) % full;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* The anchor a drawing of `w × h` needs in the frame for the body's turn to put
|
|
169
|
+
* it where `float` stands it on the sheet.
|
|
170
|
+
*/
|
|
171
|
+
function frameAnchor(float, w, h, sheet) {
|
|
172
|
+
const x = sheetX(float.posH, w, sheet);
|
|
173
|
+
const cx = sheetY(float.posV, h, sheet) + h / 2;
|
|
174
|
+
const cy = sheet.width - (x + w / 2);
|
|
175
|
+
const { posH: _h, posV: _v, ...rest } = float;
|
|
176
|
+
return {
|
|
177
|
+
...rest,
|
|
178
|
+
posH: {
|
|
179
|
+
relativeFrom: "page",
|
|
180
|
+
offsetPt: pt(cx - w / 2)
|
|
181
|
+
},
|
|
182
|
+
posV: {
|
|
183
|
+
relativeFrom: "page",
|
|
184
|
+
offsetPt: pt(cy - h / 2)
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
/** §20.4.3.3 — the box's left edge on the sheet. */
|
|
189
|
+
function sheetX(h, w, sheet) {
|
|
190
|
+
const textRight = sheet.width - sheet.marginRight;
|
|
191
|
+
const [base, span] = h?.relativeFrom === "page" ? [0, sheet.width] : h?.relativeFrom === "leftMargin" ? [0, sheet.marginLeft] : h?.relativeFrom === "rightMargin" ? [textRight, sheet.marginRight] : [sheet.marginLeft, textRight - sheet.marginLeft];
|
|
192
|
+
if (h?.align === "center") return base + (span - w) / 2;
|
|
193
|
+
if (h?.align === "right") return base + span - w;
|
|
194
|
+
return base + (h?.offsetPt ?? 0);
|
|
195
|
+
}
|
|
196
|
+
/** §20.4.3.4 — the box's top edge on the sheet. */
|
|
197
|
+
function sheetY(v, h, sheet) {
|
|
198
|
+
const textBottom = sheet.height - sheet.marginBottom;
|
|
199
|
+
const [base, span] = v?.relativeFrom === "page" ? [0, sheet.height] : v?.relativeFrom === "topMargin" ? [0, sheet.marginTop] : v?.relativeFrom === "bottomMargin" ? [textBottom, sheet.marginBottom] : [sheet.marginTop, textBottom - sheet.marginTop];
|
|
200
|
+
if (v?.align === "center") return base + (span - h) / 2;
|
|
201
|
+
if (v?.align === "bottom") return base + span - h;
|
|
202
|
+
return base + (v?.offsetPt ?? 0);
|
|
203
|
+
}
|
|
204
|
+
//#endregion
|
|
205
|
+
export { floatIntoFrame, turnOntoSheet };
|
|
@@ -32,6 +32,7 @@ function writeMarkdown(flow, options = {}) {
|
|
|
32
32
|
anchors: referencedAnchors(flow.body),
|
|
33
33
|
notes: noteNumbers(flow),
|
|
34
34
|
mediaNames: /* @__PURE__ */ new Map(),
|
|
35
|
+
drawn: /* @__PURE__ */ new Set(),
|
|
35
36
|
...flow.numbering ? { numbering: flow.numbering } : {}
|
|
36
37
|
};
|
|
37
38
|
if (flow.headersFooters && flow.headersFooters.size > 0) lose(ctx, "dropped", FEATURES.headersFooters, "markdown has no pages to band headers onto");
|
|
@@ -98,8 +99,14 @@ function emitBlock(out, el, ctx) {
|
|
|
98
99
|
return;
|
|
99
100
|
}
|
|
100
101
|
ctx.list.length = 0;
|
|
101
|
-
if (el.kind === "table")
|
|
102
|
-
|
|
102
|
+
if (el.kind === "table") {
|
|
103
|
+
emitTable(out, el.table, ctx);
|
|
104
|
+
for (const drawing of el.table.overlay?.drawings ?? []) {
|
|
105
|
+
if (ctx.drawn.has(drawing)) continue;
|
|
106
|
+
ctx.drawn.add(drawing);
|
|
107
|
+
emitBlock(out, drawing, ctx);
|
|
108
|
+
}
|
|
109
|
+
} else if (el.kind === "image") {
|
|
103
110
|
const img = pictureMarkdown(el.image.resource, el.image.altText, ctx);
|
|
104
111
|
if (img.length > 0) out.push(img);
|
|
105
112
|
} else if (el.kind === "chart") lose(ctx, "dropped", FEATURES.charts, "markdown cannot draw a chart");
|
|
@@ -275,8 +282,10 @@ function noteNumbers(flow) {
|
|
|
275
282
|
add(r.endnoteRef, endnotes, flow.endnotes);
|
|
276
283
|
add(r.commentRef, comments, flow.comments);
|
|
277
284
|
}
|
|
278
|
-
else if (el.kind === "table")
|
|
279
|
-
|
|
285
|
+
else if (el.kind === "table") {
|
|
286
|
+
for (const row of el.table.rows) for (const cell of row.cells) visit(cell.content);
|
|
287
|
+
visit(el.table.overlay?.drawings ?? []);
|
|
288
|
+
} else if (el.kind === "shape") visitShape(el.shape);
|
|
280
289
|
};
|
|
281
290
|
visit(flow.body);
|
|
282
291
|
return {
|
|
@@ -370,8 +379,10 @@ function referencedAnchors(body) {
|
|
|
370
379
|
const visit = (els) => {
|
|
371
380
|
for (const el of els) if (el.kind === "paragraph") {
|
|
372
381
|
for (const r of el.paragraph.runs) if (r.anchor !== void 0) out.add(r.anchor);
|
|
373
|
-
} else if (el.kind === "table")
|
|
374
|
-
|
|
382
|
+
} else if (el.kind === "table") {
|
|
383
|
+
for (const row of el.table.rows) for (const cell of row.cells) visit(cell.content);
|
|
384
|
+
visit(el.table.overlay?.drawings ?? []);
|
|
385
|
+
} else if (el.kind === "shape") visitShape(el.shape);
|
|
375
386
|
};
|
|
376
387
|
visit(body);
|
|
377
388
|
return out;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { dict, name, ref, stream, unicodeString } from "./objects.js";
|
|
2
2
|
import { embedTtfFont } from "./cid-font.js";
|
|
3
3
|
import { preparePdfEncryption } from "./encryption.js";
|
|
4
|
-
import {
|
|
4
|
+
import { pageLayers, paintPlan } from "../layout/page-doc.js";
|
|
5
5
|
import { reverseByCodePoint } from "../core/bidi/index.js";
|
|
6
|
-
import
|
|
7
|
-
import {
|
|
6
|
+
import "../layout/styled-layout.js";
|
|
7
|
+
import { BORDER_DASHES, FAUX_ITALIC_SHEAR, computeJustifyExtra, lineVisualOrder, settableInOneMatrix, washVeil } from "../layout/line-paint.js";
|
|
8
8
|
import { emitClipPath, emitVectorShape, shadowBlurLayers } from "./vector-graphics.js";
|
|
9
9
|
import { buildGradientAlphaMask, buildGradientPattern, shapeBbox } from "./shading.js";
|
|
10
10
|
import { warpGlyphMatrix } from "../core/drawingml/text-warp.js";
|
|
@@ -16,16 +16,6 @@ import { addSignaturePlaceholder } from "./signature.js";
|
|
|
16
16
|
import { buildXmpPacket } from "./xmp.js";
|
|
17
17
|
//#region src/pdf/styled-page-emitter.ts
|
|
18
18
|
var encoder = new TextEncoder();
|
|
19
|
-
function washVeil(wash) {
|
|
20
|
-
if (!wash) return void 0;
|
|
21
|
-
const alpha = 1 - wash.gain;
|
|
22
|
-
if (!(alpha > .004)) return void 0;
|
|
23
|
-
const offset = .5 * (1 - wash.gain) + wash.black;
|
|
24
|
-
return {
|
|
25
|
-
alpha: Math.min(1, alpha),
|
|
26
|
-
grey: Math.max(0, Math.min(1, offset / alpha))
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
19
|
/**
|
|
30
20
|
* The veil operators for a washed picture, to follow its own `/Im Do`: the
|
|
31
21
|
* placement matrix maps the unit square onto the picture as drawn, so the wash
|
|
@@ -268,7 +258,7 @@ function assembleStyledPdf(laid, options, doc) {
|
|
|
268
258
|
tagFor: (structId) => builder.node(structId).type
|
|
269
259
|
};
|
|
270
260
|
}
|
|
271
|
-
const { content: contentBytes, links } =
|
|
261
|
+
const { content: contentBytes, links } = emitPageLayers(page, pageTagging, gradientNames, alphaStateNames, wantDuotone, gradientMaskNames);
|
|
272
262
|
const contentsRef = doc.add(stream({}, contentBytes));
|
|
273
263
|
const pageEntries = {
|
|
274
264
|
Type: name("Page"),
|
|
@@ -611,31 +601,56 @@ function emitTaggedRuns(out, cmds, tagging, body) {
|
|
|
611
601
|
* 24. Scaling them by the width instead drew page-borders-export-case-2.docx's
|
|
612
602
|
* half-point frame as a row of specks a quarter the length it should be.
|
|
613
603
|
*/
|
|
614
|
-
var BORDER_DASHES = new Map([
|
|
615
|
-
["dashed", [8, 2.5]],
|
|
616
|
-
["dashSmallGap", [3, 1]],
|
|
617
|
-
["dotted", [.5, 1]],
|
|
618
|
-
["dashDot", [
|
|
619
|
-
8,
|
|
620
|
-
2.5,
|
|
621
|
-
2.5,
|
|
622
|
-
2.5
|
|
623
|
-
]],
|
|
624
|
-
["dashDotDot", [
|
|
625
|
-
8,
|
|
626
|
-
2.5,
|
|
627
|
-
2.5,
|
|
628
|
-
2.5,
|
|
629
|
-
2.5,
|
|
630
|
-
2.5
|
|
631
|
-
]]
|
|
632
|
-
]);
|
|
633
|
-
var FAUX_ITALIC_SHEAR = .2126;
|
|
634
604
|
/** The PDF dash array for a border style; an empty string means a solid rule. */
|
|
635
605
|
function dashPatternFor(style) {
|
|
636
606
|
const pattern = style !== void 0 ? BORDER_DASHES.get(style) : void 0;
|
|
637
607
|
return pattern ? `[${pattern.map(formatNumber).join(" ")}]` : "";
|
|
638
608
|
}
|
|
609
|
+
/**
|
|
610
|
+
* A page's content stream in its layers (pageLayers): its own items, then —
|
|
611
|
+
* when some of them stand IN FRONT of its text (PageItemBase.over) — those,
|
|
612
|
+
* painted again pass by pass over what the first layer left, their own text
|
|
613
|
+
* last; and each group seen through a window of its own (PageItemBase.window)
|
|
614
|
+
* inside a clip to it. Each layer is a balanced stream of its own, so they
|
|
615
|
+
* simply follow one another.
|
|
616
|
+
*/
|
|
617
|
+
function emitPageLayers(page, ...rest) {
|
|
618
|
+
const layers = pageLayers(page.commands);
|
|
619
|
+
if (layers.length === 1 && !layers[0].window) return emitPageContent(page, ...rest);
|
|
620
|
+
const parts = [];
|
|
621
|
+
const links = [];
|
|
622
|
+
for (const layer of layers) {
|
|
623
|
+
const emitted = emitPageContent({
|
|
624
|
+
...page,
|
|
625
|
+
commands: layer.items
|
|
626
|
+
}, ...rest);
|
|
627
|
+
links.push(...emitted.links);
|
|
628
|
+
const w = layer.window;
|
|
629
|
+
if (!w) {
|
|
630
|
+
parts.push(emitted.content);
|
|
631
|
+
continue;
|
|
632
|
+
}
|
|
633
|
+
if (emitted.content.length === 0) continue;
|
|
634
|
+
const rect = [
|
|
635
|
+
w.x,
|
|
636
|
+
page.height - w.y - w.height,
|
|
637
|
+
w.width,
|
|
638
|
+
w.height
|
|
639
|
+
].map(formatNumber);
|
|
640
|
+
parts.push(encoder.encode(`q ${rect.join(" ")} re W n`), emitted.content, encoder.encode("Q"));
|
|
641
|
+
}
|
|
642
|
+
const content = new Uint8Array(parts.reduce((sum, p) => sum + p.length, 0) + Math.max(0, parts.length - 1));
|
|
643
|
+
let at = 0;
|
|
644
|
+
parts.forEach((p, i) => {
|
|
645
|
+
if (i > 0) content[at++] = 10;
|
|
646
|
+
content.set(p, at);
|
|
647
|
+
at += p.length;
|
|
648
|
+
});
|
|
649
|
+
return {
|
|
650
|
+
content,
|
|
651
|
+
links
|
|
652
|
+
};
|
|
653
|
+
}
|
|
639
654
|
function emitPageContent(page, tagging, gradientNames, alphaStateNames, duotoneStateFor, gradientMaskNames) {
|
|
640
655
|
const commands = page.commands;
|
|
641
656
|
const links = [];
|
|
@@ -676,12 +691,13 @@ function emitPageContent(page, tagging, gradientNames, alphaStateNames, duotoneS
|
|
|
676
691
|
}
|
|
677
692
|
lastStroke = strokeHex;
|
|
678
693
|
}
|
|
679
|
-
const
|
|
694
|
+
const scale = (tok.synthetic?.widthScale ?? 1) * (tok.resolvedRun.widthScale ?? 1);
|
|
695
|
+
const tz = Math.round(scale * 100);
|
|
680
696
|
if (tz !== lastTz) {
|
|
681
697
|
out.push(`${formatNumber(tz)} Tz`);
|
|
682
698
|
lastTz = tz;
|
|
683
699
|
}
|
|
684
|
-
const tc = tok.resolvedRun.letterSpacingPt ?? 0;
|
|
700
|
+
const tc = (tok.resolvedRun.letterSpacingPt ?? 0) / (tz > 0 ? tz / 100 : 1);
|
|
685
701
|
if (tc !== lastTc) {
|
|
686
702
|
out.push(`${formatNumber(tc)} Tc`);
|
|
687
703
|
lastTc = tc;
|
|
@@ -888,7 +904,69 @@ function emitPageContent(page, tagging, gradientNames, alphaStateNames, duotoneS
|
|
|
888
904
|
lastColor = "";
|
|
889
905
|
lastTc = 0;
|
|
890
906
|
};
|
|
907
|
+
const emitTurned = (cmd) => {
|
|
908
|
+
if (inBT) {
|
|
909
|
+
out.push("ET");
|
|
910
|
+
inBT = false;
|
|
911
|
+
}
|
|
912
|
+
const rad = (cmd.rotationDeg ?? 0) * Math.PI / 180;
|
|
913
|
+
const cos = Math.cos(rad);
|
|
914
|
+
const sin = Math.sin(rad);
|
|
915
|
+
const ox = cmd.originX;
|
|
916
|
+
const oy = H - cmd.baselineY;
|
|
917
|
+
out.push("q");
|
|
918
|
+
out.push(`${formatNumber(cos)} ${formatNumber(sin)} ${formatNumber(-sin)} ${formatNumber(cos)} ${formatNumber(ox - ox * cos + oy * sin)} ${formatNumber(oy - ox * sin - oy * cos)} cm`);
|
|
919
|
+
lastFont = "";
|
|
920
|
+
lastFauxWidth = 0;
|
|
921
|
+
lastStroke = void 0;
|
|
922
|
+
lastTz = 100;
|
|
923
|
+
lastSize = -1;
|
|
924
|
+
lastColor = "";
|
|
925
|
+
lastTc = 0;
|
|
926
|
+
const from = links.length;
|
|
927
|
+
const { rotationDeg: _turned, ...flat } = cmd;
|
|
928
|
+
out.push("BT");
|
|
929
|
+
inBT = true;
|
|
930
|
+
emitOneLine(flat);
|
|
931
|
+
if (inBT) {
|
|
932
|
+
out.push("ET");
|
|
933
|
+
inBT = false;
|
|
934
|
+
}
|
|
935
|
+
out.push("Q");
|
|
936
|
+
lastFont = "";
|
|
937
|
+
lastFauxWidth = 0;
|
|
938
|
+
lastStroke = void 0;
|
|
939
|
+
lastTz = 100;
|
|
940
|
+
lastSize = -1;
|
|
941
|
+
lastColor = "";
|
|
942
|
+
lastTc = 0;
|
|
943
|
+
for (let k = from; k < links.length; k++) {
|
|
944
|
+
const link = links[k];
|
|
945
|
+
const [x0, y0, x1, y1] = link.rect;
|
|
946
|
+
const corners = [
|
|
947
|
+
[x0, y0],
|
|
948
|
+
[x1, y0],
|
|
949
|
+
[x1, y1],
|
|
950
|
+
[x0, y1]
|
|
951
|
+
].map(([x, y]) => [ox + (x - ox) * cos - (y - oy) * sin, oy + (x - ox) * sin + (y - oy) * cos]);
|
|
952
|
+
const xs = corners.map((c) => c[0]);
|
|
953
|
+
const ys = corners.map((c) => c[1]);
|
|
954
|
+
links[k] = {
|
|
955
|
+
...link,
|
|
956
|
+
rect: [
|
|
957
|
+
Math.min(...xs),
|
|
958
|
+
Math.min(...ys),
|
|
959
|
+
Math.max(...xs),
|
|
960
|
+
Math.max(...ys)
|
|
961
|
+
]
|
|
962
|
+
};
|
|
963
|
+
}
|
|
964
|
+
};
|
|
891
965
|
const emitOneLine = (cmd) => {
|
|
966
|
+
if (cmd.rotationDeg && cmd.warp === void 0 && !settableInOneMatrix(cmd.line)) {
|
|
967
|
+
emitTurned(cmd);
|
|
968
|
+
return;
|
|
969
|
+
}
|
|
892
970
|
const line = cmd.line;
|
|
893
971
|
const originX = cmd.originX;
|
|
894
972
|
const baselineY = H - cmd.baselineY;
|
|
@@ -1351,9 +1429,6 @@ function emitPageContent(page, tagging, gradientNames, alphaStateNames, duotoneS
|
|
|
1351
1429
|
links
|
|
1352
1430
|
};
|
|
1353
1431
|
}
|
|
1354
|
-
function lineVisualOrder(line) {
|
|
1355
|
-
return reorderVisual(line.tokens.map((t) => t.bidiLevel));
|
|
1356
|
-
}
|
|
1357
1432
|
/**
|
|
1358
1433
|
* The operators that put an image XObject in a box — ISO 32000-1 §8.9.5.1: the
|
|
1359
1434
|
* unit square scaled to the box and moved to `(x, y)`, its bottom-left corner.
|
|
@@ -1397,27 +1472,6 @@ function rotateAboutCm(cx, cy, deg) {
|
|
|
1397
1472
|
const s = Math.sin(rad);
|
|
1398
1473
|
return `${formatNumber(c)} ${formatNumber(s)} ${formatNumber(-s)} ${formatNumber(c)} ${formatNumber(cx - cx * c + cy * s)} ${formatNumber(cy - cx * s - cy * c)} cm`;
|
|
1399
1474
|
}
|
|
1400
|
-
function computeJustifyExtra(line) {
|
|
1401
|
-
const alignment = line.resolved.alignment;
|
|
1402
|
-
if (alignment !== "both" && alignment !== "distribute") return 0;
|
|
1403
|
-
if (line.noJustify === true) return 0;
|
|
1404
|
-
if (line.isLastInParagraph && alignment !== "distribute") return 0;
|
|
1405
|
-
let last = line.tokens.length - 1;
|
|
1406
|
-
while (last >= 0 && line.tokens[last].kind === "text" && line.tokens[last].isSpace) last--;
|
|
1407
|
-
let spaces = 0;
|
|
1408
|
-
let narrowest = Infinity;
|
|
1409
|
-
let contentWidthPt = 0;
|
|
1410
|
-
for (let i = 0; i <= last; i++) {
|
|
1411
|
-
const tok = line.tokens[i];
|
|
1412
|
-
contentWidthPt += tok.widthPt;
|
|
1413
|
-
if (!tok.isSpace) continue;
|
|
1414
|
-
spaces++;
|
|
1415
|
-
if (tok.widthPt < narrowest) narrowest = tok.widthPt;
|
|
1416
|
-
}
|
|
1417
|
-
if (spaces === 0) return 0;
|
|
1418
|
-
const extra = (line.availableWidthPt - contentWidthPt) / spaces;
|
|
1419
|
-
return extra < 0 ? Math.max(extra, -narrowest * GLUE_SHRINK_RATIO) : extra;
|
|
1420
|
-
}
|
|
1421
1475
|
function hexToRgb01(hex) {
|
|
1422
1476
|
return [
|
|
1423
1477
|
parseInt(hex.slice(0, 2), 16) / 255,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { PdfDocument } from "./writer.js";
|
|
2
|
-
import { layoutStyledDocument } from "../layout/styled-layout.js";
|
|
3
2
|
import "../layout/page-doc.js";
|
|
3
|
+
import { layoutStyledDocument } from "../layout/styled-layout.js";
|
|
4
4
|
import { emitStyledPdf, emitStyledPdfEncrypted } from "./styled-page-emitter.js";
|
|
5
5
|
//#region src/pdf/styled-page-renderer.ts
|
|
6
6
|
/**
|
|
@@ -32,5 +32,32 @@ export declare function cffNameToGid(program: Uint8Array): Map<string, number> |
|
|
|
32
32
|
* CID-keyed or cannot be read.
|
|
33
33
|
*/
|
|
34
34
|
export declare function cffCidToGid(program: Uint8Array): Map<number, number> | undefined;
|
|
35
|
+
/**
|
|
36
|
+
* How far the pen moves after a name-keyed CFF program's `space`, in
|
|
37
|
+
* thousandths of an em — the width a writer gives the space a page never
|
|
38
|
+
* showed, which is the one it was typeset with.
|
|
39
|
+
*
|
|
40
|
+
* @param program The raw CFF bytes.
|
|
41
|
+
* @returns The advance, or `undefined` where the program has no `space` or its
|
|
42
|
+
* width cannot be read off the charstring.
|
|
43
|
+
*/
|
|
44
|
+
export declare function cffSpaceAdvance(program: Uint8Array): number | undefined;
|
|
45
|
+
/**
|
|
46
|
+
* The embedding a CFF program's licence allows: CFF has no OS/2 table, and
|
|
47
|
+
* Adobe writes the OS/2 `fsType` into the Top DICT's `PostScript` string
|
|
48
|
+
* instead (TN 5176 §9, key 12 21) as `/FSType 8 def`.
|
|
49
|
+
*
|
|
50
|
+
* @param program The raw CFF bytes.
|
|
51
|
+
* @returns The value, or `undefined` where the program states none.
|
|
52
|
+
*/
|
|
53
|
+
export declare function cffFsType(program: Uint8Array): number | undefined;
|
|
54
|
+
/**
|
|
55
|
+
* The `/FSType n def` a PostScript font program writes where an OpenType one
|
|
56
|
+
* has its OS/2 field (Adobe TN 5176 §9; a Type 1 font's `FontInfo` alike).
|
|
57
|
+
*
|
|
58
|
+
* @param text The PostScript to search.
|
|
59
|
+
* @returns The value, or `undefined` where the text states none.
|
|
60
|
+
*/
|
|
61
|
+
export declare function postScriptFsType(text: string): number | undefined;
|
|
35
62
|
/** The `CFF ` table of an OpenType wrapper, where the program is one. */
|
|
36
63
|
export declare function openTypeCff(program: Uint8Array): Uint8Array | undefined;
|