reamkit 0.1.0-alpha.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +107 -30
- package/dist/esm/{bidi → core/bidi}/algorithm.js +1 -1
- package/dist/esm/{bidi → core/bidi}/char-types.js +1 -1
- package/dist/esm/{bidi → core/bidi}/index.d.ts +2 -0
- package/dist/esm/{bidi → core/bidi}/index.js +2 -1
- package/dist/esm/core/bidi/segments.d.ts +6 -0
- package/dist/esm/core/bidi/segments.js +41 -0
- package/dist/esm/core/bytes.d.ts +1 -0
- package/dist/esm/core/bytes.js +11 -0
- package/dist/esm/core/converter/facade.d.ts +45 -0
- package/dist/esm/core/converter/facade.js +89 -0
- package/dist/esm/core/converter/index.d.ts +4 -0
- package/dist/esm/core/converter/project.d.ts +4 -0
- package/dist/esm/core/converter/project.js +17 -0
- package/dist/esm/core/converter/ream.d.ts +35 -0
- package/dist/esm/core/converter/ream.js +101 -0
- package/dist/esm/{crypto → core/crypto}/asn1.js +1 -1
- package/dist/esm/{crypto → core/crypto}/cms.js +1 -1
- package/dist/esm/core/document-model/index.d.ts +1 -0
- package/dist/esm/{document-model → core/document-model}/types.d.ts +57 -41
- package/dist/esm/{ooxml → core}/drawingml/chart-parser.d.ts +1 -1
- package/dist/esm/{ooxml → core}/drawingml/chart-parser.js +6 -29
- package/dist/esm/{ooxml → core}/drawingml/colors.d.ts +3 -0
- package/dist/esm/{ooxml → core}/drawingml/colors.js +32 -2
- package/dist/esm/{ooxml → core}/drawingml/theme-parser.js +2 -2
- package/dist/esm/{font → core/font}/arabic-joining.js +1 -1
- package/dist/esm/{font → core/font}/binary-reader.js +1 -1
- package/dist/esm/{font → core/font}/font-registry.d.ts +1 -0
- package/dist/esm/{font → core/font}/font-registry.js +17 -16
- package/dist/esm/{font → core/font}/index.d.ts +3 -0
- package/dist/esm/core/font/measure.d.ts +7 -0
- package/dist/esm/core/font/measure.js +30 -0
- package/dist/esm/{font → core/font}/opentype-layout.js +1 -1
- package/dist/esm/{font → core/font}/ttf-parser.js +1 -1
- package/dist/esm/{font → core/font}/ttf-subset.js +1 -1
- package/dist/esm/core/fonts/provider.d.ts +60 -0
- package/dist/esm/core/fonts/provider.js +163 -0
- package/dist/esm/{fonts → core/fonts}/remote-fonts.js +1 -1
- package/dist/esm/{hyphenation → core/hyphenation}/index.js +1 -1
- package/dist/esm/{hyphenation → core/hyphenation}/liang.js +1 -1
- package/dist/esm/{hyphenation → core/hyphenation}/patterns-en-us.js +1 -1
- package/dist/esm/{hyphenation → core/hyphenation}/patterns-ru.js +1 -1
- package/dist/esm/core/images.d.ts +17 -0
- package/dist/esm/core/images.js +308 -0
- package/dist/esm/core/ir/adapters.d.ts +37 -0
- package/dist/esm/core/ir/features.d.ts +25 -0
- package/dist/esm/core/ir/features.js +24 -0
- package/dist/esm/core/ir/flow.d.ts +24 -0
- package/dist/esm/core/ir/index.d.ts +11 -0
- package/dist/esm/core/ir/loss.d.ts +22 -0
- package/dist/esm/core/ir/loss.js +15 -0
- package/dist/esm/core/ir/resources.d.ts +16 -0
- package/dist/esm/core/ir/resources.js +50 -0
- package/dist/esm/core/ir/units.d.ts +16 -0
- package/dist/esm/core/ir/units.js +41 -0
- package/dist/esm/core/line-breaker/index.d.ts +2 -0
- package/dist/esm/{line-breaker → core/line-breaker}/knuth-plass.d.ts +1 -0
- package/dist/esm/{line-breaker → core/line-breaker}/knuth-plass.js +3 -3
- package/dist/esm/core/numbering/apply.d.ts +3 -0
- package/dist/esm/core/numbering/apply.js +62 -0
- package/dist/esm/core/numbering/index.d.ts +2 -0
- package/dist/esm/{numbering → core/numbering}/state.js +1 -1
- package/dist/esm/{opc → core/opc}/core-properties.js +1 -1
- package/dist/esm/{opc → core/opc}/package.d.ts +2 -1
- package/dist/esm/{opc → core/opc}/package.js +7 -3
- package/dist/esm/{opc → core/opc}/relationship-types.js +1 -1
- package/dist/esm/{opc → core/opc}/relationships.js +1 -1
- package/dist/esm/{ooxml/wordproc → core}/po-helpers.js +1 -1
- package/dist/esm/core/style-cascade/index.d.ts +3 -0
- package/dist/esm/core/style-cascade/index.js +2 -0
- package/dist/esm/core/style-cascade/resolver.d.ts +7 -0
- package/dist/esm/{style-cascade → core/style-cascade}/resolver.js +82 -10
- package/dist/esm/{style-cascade → core/style-cascade}/types.d.ts +10 -8
- package/dist/esm/{style-cascade → core/style-cascade}/types.js +9 -8
- package/dist/esm/core/vector.d.ts +45 -0
- package/dist/esm/core/vector.js +48 -0
- package/dist/esm/{ooxml/spreadsheet → excel}/cell-reference.js +1 -1
- package/dist/esm/{ooxml/spreadsheet → excel}/defined-name-ref.js +1 -1
- package/dist/esm/{ooxml/spreadsheet → excel}/index.d.ts +1 -1
- package/dist/esm/{ooxml/spreadsheet → excel}/number-format.js +1 -1
- package/dist/esm/excel/print-model.d.ts +18 -0
- package/dist/esm/{converter/xlsx-to-pdf.js → excel/print-model.js} +39 -148
- package/dist/esm/{ooxml/spreadsheet → excel}/shared-strings-parser.js +1 -1
- package/dist/esm/{ooxml/spreadsheet → excel}/styles-parser.js +1 -1
- package/dist/esm/{ooxml/spreadsheet → excel}/workbook-parser.js +1 -1
- package/dist/esm/{ooxml/spreadsheet → excel}/worksheet-parser.js +1 -1
- package/dist/esm/excel/xlsx-reader.d.ts +4 -0
- package/dist/esm/excel/xlsx-reader.js +91 -0
- package/dist/esm/{converter → excel}/xlsx-to-pdf.d.ts +13 -2
- package/dist/esm/excel/xlsx-to-pdf.js +69 -0
- package/dist/esm/index.d.ts +23 -8
- package/dist/esm/index.js +18 -10
- package/dist/esm/{pdf → layout}/arc-to-bezier.d.ts +1 -1
- package/dist/esm/{pdf → layout}/arc-to-bezier.js +2 -2
- package/dist/esm/{pdf → layout}/chart-geometry.d.ts +1 -1
- package/dist/esm/{pdf → layout}/math-layout.d.ts +2 -2
- package/dist/esm/{pdf → layout}/math-layout.js +1 -1
- package/dist/esm/layout/page-doc.d.ts +133 -0
- package/dist/esm/layout/page-doc.js +38 -0
- package/dist/esm/{pdf → layout}/preset-geometry.d.ts +2 -2
- package/dist/esm/{pdf → layout}/preset-geometry.js +2 -2
- package/dist/esm/layout/styled-layout.d.ts +84 -0
- package/dist/esm/layout/styled-layout.js +1729 -0
- package/dist/esm/pdf/cid-font.d.ts +1 -1
- package/dist/esm/pdf/cid-font.js +6 -21
- package/dist/esm/pdf/image-xobject.d.ts +4 -5
- package/dist/esm/pdf/image-xobject.js +21 -324
- package/dist/esm/pdf/index.d.ts +2 -2
- package/dist/esm/pdf/index.js +1 -0
- package/dist/esm/pdf/signature.js +4 -4
- package/dist/esm/pdf/styled-page-emitter.d.ts +11 -0
- package/dist/esm/pdf/styled-page-emitter.js +557 -0
- package/dist/esm/pdf/styled-page-renderer.d.ts +4 -42
- package/dist/esm/pdf/styled-page-renderer.js +4 -2311
- package/dist/esm/pdf/text-page-renderer.d.ts +1 -1
- package/dist/esm/pdf/vector-graphics.d.ts +3 -45
- package/dist/esm/pdf/vector-graphics.js +2 -46
- package/dist/esm/svg/svg-writer.d.ts +8 -0
- package/dist/esm/svg/svg-writer.js +137 -0
- package/dist/esm/word/document-parser.d.ts +16 -0
- package/dist/esm/{ooxml/wordproc → word}/document-parser.js +55 -47
- package/dist/esm/word/docx-reader.d.ts +4 -0
- package/dist/esm/word/docx-reader.js +191 -0
- package/dist/esm/word/docx-to-pdf.d.ts +34 -0
- package/dist/esm/word/docx-to-pdf.js +112 -0
- package/dist/esm/{ooxml/wordproc → word}/drawing-parser.d.ts +10 -9
- package/dist/esm/{ooxml/wordproc → word}/drawing-parser.js +15 -42
- package/dist/esm/{ooxml/wordproc → word}/font-table.d.ts +2 -2
- package/dist/esm/{ooxml/wordproc → word}/font-table.js +2 -2
- package/dist/esm/{ooxml/wordproc → word}/index.d.ts +3 -2
- package/dist/esm/{ooxml/wordproc → word}/numbering-parser.d.ts +1 -1
- package/dist/esm/{ooxml/wordproc → word}/numbering-parser.js +1 -1
- package/dist/esm/{ooxml/math → word}/omml-parser.d.ts +2 -2
- package/dist/esm/{ooxml/math → word}/omml-parser.js +2 -2
- package/dist/esm/{ooxml/wordproc → word}/paragraph-properties.d.ts +1 -1
- package/dist/esm/{ooxml/wordproc → word}/paragraph-properties.js +9 -8
- package/dist/esm/{ooxml/wordproc → word}/po-to-flat.d.ts +1 -1
- package/dist/esm/{ooxml/wordproc → word}/po-to-flat.js +2 -2
- package/dist/esm/{ooxml/wordproc → word}/run-properties.d.ts +1 -1
- package/dist/esm/{ooxml/wordproc → word}/run-properties.js +3 -2
- package/dist/esm/{ooxml/wordproc → word}/settings-parser.js +2 -2
- package/dist/esm/word/styles-parser.d.ts +2 -0
- package/dist/esm/{ooxml/wordproc → word}/styles-parser.js +4 -7
- package/dist/esm/word/table-parser.d.ts +4 -0
- package/dist/esm/{ooxml/wordproc → word}/table-parser.js +80 -26
- package/dist/esm/{ooxml/wordproc → word}/xml-helpers.js +1 -1
- package/package.json +5 -6
- package/dist/esm/converter/docx-to-pdf.d.ts +0 -15
- package/dist/esm/converter/docx-to-pdf.js +0 -227
- package/dist/esm/converter/index.d.ts +0 -4
- package/dist/esm/converter/index.js +0 -2
- package/dist/esm/document-model/index.d.ts +0 -1
- package/dist/esm/line-breaker/index.d.ts +0 -2
- package/dist/esm/numbering/index.d.ts +0 -1
- package/dist/esm/ooxml/index.d.ts +0 -1
- package/dist/esm/ooxml/wordproc/document-parser.d.ts +0 -9
- package/dist/esm/ooxml/wordproc/styles-parser.d.ts +0 -3
- package/dist/esm/ooxml/wordproc/table-parser.d.ts +0 -3
- package/dist/esm/style-cascade/index.d.ts +0 -3
- package/dist/esm/style-cascade/resolver.d.ts +0 -4
- /package/dist/esm/{bidi → core/bidi}/algorithm.d.ts +0 -0
- /package/dist/esm/{bidi → core/bidi}/char-types.d.ts +0 -0
- /package/dist/esm/{crypto → core/crypto}/asn1.d.ts +0 -0
- /package/dist/esm/{crypto → core/crypto}/cms.d.ts +0 -0
- /package/dist/esm/{crypto → core/crypto}/index.d.ts +0 -0
- /package/dist/esm/{crypto → core/crypto}/index.js +0 -0
- /package/dist/esm/{document-model → core/document-model}/index.js +0 -0
- /package/dist/esm/{ooxml → core}/drawingml/theme-parser.d.ts +0 -0
- /package/dist/esm/{font → core/font}/arabic-joining.d.ts +0 -0
- /package/dist/esm/{font → core/font}/binary-reader.d.ts +0 -0
- /package/dist/esm/{font → core/font}/opentype-layout.d.ts +0 -0
- /package/dist/esm/{font → core/font}/ttf-parser.d.ts +0 -0
- /package/dist/esm/{font → core/font}/ttf-subset.d.ts +0 -0
- /package/dist/esm/{fonts → core/fonts}/index.d.ts +0 -0
- /package/dist/esm/{fonts → core/fonts}/remote-fonts.d.ts +0 -0
- /package/dist/esm/{hyphenation → core/hyphenation}/index.d.ts +0 -0
- /package/dist/esm/{hyphenation → core/hyphenation}/liang.d.ts +0 -0
- /package/dist/esm/{hyphenation → core/hyphenation}/patterns-en-us.d.ts +0 -0
- /package/dist/esm/{hyphenation → core/hyphenation}/patterns-ru.d.ts +0 -0
- /package/dist/esm/{numbering → core/numbering}/state.d.ts +0 -0
- /package/dist/esm/{opc → core/opc}/core-properties.d.ts +0 -0
- /package/dist/esm/{opc → core/opc}/index.d.ts +0 -0
- /package/dist/esm/{opc → core/opc}/index.js +0 -0
- /package/dist/esm/{opc → core/opc}/relationship-types.d.ts +0 -0
- /package/dist/esm/{opc → core/opc}/relationships.d.ts +0 -0
- /package/dist/esm/{ooxml/wordproc → core}/po-helpers.d.ts +0 -0
- /package/dist/esm/{ooxml/spreadsheet → excel}/cell-reference.d.ts +0 -0
- /package/dist/esm/{ooxml/spreadsheet → excel}/defined-name-ref.d.ts +0 -0
- /package/dist/esm/{ooxml/spreadsheet → excel}/index.js +0 -0
- /package/dist/esm/{ooxml/spreadsheet → excel}/number-format.d.ts +0 -0
- /package/dist/esm/{ooxml/spreadsheet → excel}/shared-strings-parser.d.ts +0 -0
- /package/dist/esm/{ooxml/spreadsheet → excel}/styles-parser.d.ts +0 -0
- /package/dist/esm/{ooxml/spreadsheet → excel}/workbook-parser.d.ts +0 -0
- /package/dist/esm/{ooxml/spreadsheet → excel}/worksheet-parser.d.ts +0 -0
- /package/dist/esm/{pdf → layout}/chart-geometry.js +0 -0
- /package/dist/esm/{ooxml/wordproc → word}/index.js +0 -0
- /package/dist/esm/{ooxml/wordproc → word}/settings-parser.d.ts +0 -0
- /package/dist/esm/{ooxml/wordproc → word}/text-extractor.d.ts +0 -0
- /package/dist/esm/{ooxml/wordproc → word}/text-extractor.js +0 -0
- /package/dist/esm/{ooxml/wordproc → word}/xml-helpers.d.ts +0 -0
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
import { unzlibSync, zlibSync } from "fflate";
|
|
2
|
+
//#region src/core/images.ts
|
|
3
|
+
function detectImageFormat(bytes) {
|
|
4
|
+
if (bytes.length >= 3 && bytes[0] === 255 && bytes[1] === 216 && bytes[2] === 255) return "jpeg";
|
|
5
|
+
if (bytes.length >= 8 && bytes[0] === 137 && bytes[1] === 80 && bytes[2] === 78 && bytes[3] === 71 && bytes[4] === 13 && bytes[5] === 10 && bytes[6] === 26 && bytes[7] === 10) return "png";
|
|
6
|
+
if (bytes.length >= 12 && bytes[0] === 0 && bytes[1] === 0 && bytes[2] === 0 && bytes[3] === 12 && bytes[4] === 106 && bytes[5] === 80 && bytes[6] === 32 && bytes[7] === 32 && bytes[8] === 13 && bytes[9] === 10 && bytes[10] === 135 && bytes[11] === 10) return "jpeg2000";
|
|
7
|
+
if (bytes.length >= 4 && bytes[0] === 255 && bytes[1] === 79 && bytes[2] === 255 && bytes[3] === 81) return "jpeg2000";
|
|
8
|
+
return null;
|
|
9
|
+
}
|
|
10
|
+
function prepareImage(bytes, options = {}) {
|
|
11
|
+
const format = detectImageFormat(bytes);
|
|
12
|
+
if (format === "jpeg") return prepareJpeg(bytes);
|
|
13
|
+
if (format === "png") return preparePng(bytes, options);
|
|
14
|
+
if (format === "jpeg2000") return prepareJpeg2000(bytes);
|
|
15
|
+
throw new Error("Unsupported image format");
|
|
16
|
+
}
|
|
17
|
+
function prepareJpeg2000(bytes) {
|
|
18
|
+
const { width, height } = readJpeg2000Info(bytes);
|
|
19
|
+
return {
|
|
20
|
+
format: "jpeg2000",
|
|
21
|
+
mimeType: "image/jp2",
|
|
22
|
+
widthPx: width,
|
|
23
|
+
heightPx: height,
|
|
24
|
+
filter: "JPXDecode",
|
|
25
|
+
data: bytes
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function readU32(b, o) {
|
|
29
|
+
return b[o] * 16777216 + (b[o + 1] << 16) + (b[o + 2] << 8) + b[o + 3];
|
|
30
|
+
}
|
|
31
|
+
var boxType = (b, o) => String.fromCharCode(b[o], b[o + 1], b[o + 2], b[o + 3]);
|
|
32
|
+
function readJpeg2000Info(bytes) {
|
|
33
|
+
if (bytes[0] === 255 && bytes[1] === 79) return readSiz(bytes, 2);
|
|
34
|
+
let p = 0;
|
|
35
|
+
while (p + 8 <= bytes.length) {
|
|
36
|
+
let len = readU32(bytes, p);
|
|
37
|
+
const type = boxType(bytes, p + 4);
|
|
38
|
+
let contentStart = p + 8;
|
|
39
|
+
if (len === 1) {
|
|
40
|
+
len = readU32(bytes, p + 12);
|
|
41
|
+
contentStart = p + 16;
|
|
42
|
+
}
|
|
43
|
+
const end = len === 0 ? bytes.length : p + len;
|
|
44
|
+
if (type === "jp2h") {
|
|
45
|
+
let q = contentStart;
|
|
46
|
+
while (q + 8 <= end) {
|
|
47
|
+
const clen = readU32(bytes, q);
|
|
48
|
+
if (boxType(bytes, q + 4) === "ihdr") return {
|
|
49
|
+
height: readU32(bytes, q + 8),
|
|
50
|
+
width: readU32(bytes, q + 12)
|
|
51
|
+
};
|
|
52
|
+
if (clen === 0) break;
|
|
53
|
+
q += clen;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (len === 0) break;
|
|
57
|
+
p = end;
|
|
58
|
+
}
|
|
59
|
+
for (let i = 0; i + 22 < bytes.length; i++) if (bytes[i] === 255 && bytes[i + 1] === 81) return readSiz(bytes, i);
|
|
60
|
+
throw new Error("JPEG 2000: no ihdr/SIZ found");
|
|
61
|
+
}
|
|
62
|
+
function readSiz(bytes, sizOffset) {
|
|
63
|
+
const xsiz = readU32(bytes, sizOffset + 6);
|
|
64
|
+
const ysiz = readU32(bytes, sizOffset + 10);
|
|
65
|
+
const xo = readU32(bytes, sizOffset + 14);
|
|
66
|
+
const yo = readU32(bytes, sizOffset + 18);
|
|
67
|
+
const width = xsiz - xo;
|
|
68
|
+
const height = ysiz - yo;
|
|
69
|
+
if (width <= 0 || height <= 0) throw new Error("JPEG 2000: invalid SIZ dimensions");
|
|
70
|
+
return {
|
|
71
|
+
width,
|
|
72
|
+
height
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
function prepareJpeg(bytes) {
|
|
76
|
+
const info = readJpegInfo(bytes);
|
|
77
|
+
return {
|
|
78
|
+
format: "jpeg",
|
|
79
|
+
mimeType: "image/jpeg",
|
|
80
|
+
widthPx: info.width,
|
|
81
|
+
heightPx: info.height,
|
|
82
|
+
colorSpace: info.numComponents === 1 ? "DeviceGray" : "DeviceRGB",
|
|
83
|
+
bitsPerComponent: info.precision,
|
|
84
|
+
filter: "DCTDecode",
|
|
85
|
+
data: bytes
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
function readJpegInfo(bytes) {
|
|
89
|
+
if (bytes.length < 4 || bytes[0] !== 255 || bytes[1] !== 216) throw new Error("Not a JPEG (missing SOI)");
|
|
90
|
+
let i = 2;
|
|
91
|
+
while (i + 9 < bytes.length) {
|
|
92
|
+
if (bytes[i] !== 255) {
|
|
93
|
+
i++;
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
let marker = bytes[i + 1];
|
|
97
|
+
while (marker === 255) {
|
|
98
|
+
i++;
|
|
99
|
+
marker = bytes[i + 1];
|
|
100
|
+
}
|
|
101
|
+
if (marker === 1 || marker >= 208 && marker <= 217) {
|
|
102
|
+
i += 2;
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
if (marker >= 192 && marker <= 207 && marker !== 196 && marker !== 200 && marker !== 204) return {
|
|
106
|
+
precision: bytes[i + 4],
|
|
107
|
+
height: bytes[i + 5] << 8 | bytes[i + 6],
|
|
108
|
+
width: bytes[i + 7] << 8 | bytes[i + 8],
|
|
109
|
+
numComponents: bytes[i + 9]
|
|
110
|
+
};
|
|
111
|
+
const length = bytes[i + 2] << 8 | bytes[i + 3];
|
|
112
|
+
i += 2 + length;
|
|
113
|
+
}
|
|
114
|
+
throw new Error("JPEG SOFn marker not found");
|
|
115
|
+
}
|
|
116
|
+
function preparePng(bytes, options = {}) {
|
|
117
|
+
let decoded = decodePng(bytes);
|
|
118
|
+
if (options.flattenAlpha && decoded.smaskRaw) decoded = flattenAlphaOnWhite(decoded);
|
|
119
|
+
return {
|
|
120
|
+
format: "png",
|
|
121
|
+
mimeType: "image/png",
|
|
122
|
+
widthPx: decoded.width,
|
|
123
|
+
heightPx: decoded.height,
|
|
124
|
+
colorSpace: decoded.colorSpace,
|
|
125
|
+
bitsPerComponent: decoded.bitsPerComponent,
|
|
126
|
+
filter: "FlateDecode",
|
|
127
|
+
data: zlibSync(decoded.raw),
|
|
128
|
+
...decoded.smaskRaw ? { smaskData: zlibSync(decoded.smaskRaw) } : {}
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
function decodePng(bytes) {
|
|
132
|
+
let width = 0;
|
|
133
|
+
let height = 0;
|
|
134
|
+
let bitDepth = 0;
|
|
135
|
+
let colorType = 0;
|
|
136
|
+
let interlaceMethod = 0;
|
|
137
|
+
const idatChunks = [];
|
|
138
|
+
let pos = 8;
|
|
139
|
+
while (pos + 12 <= bytes.length) {
|
|
140
|
+
const len = readU32BE(bytes, pos);
|
|
141
|
+
const type = chunkType(bytes, pos + 4);
|
|
142
|
+
const dataOff = pos + 8;
|
|
143
|
+
if (type === "IHDR") {
|
|
144
|
+
width = readU32BE(bytes, dataOff);
|
|
145
|
+
height = readU32BE(bytes, dataOff + 4);
|
|
146
|
+
bitDepth = bytes[dataOff + 8];
|
|
147
|
+
colorType = bytes[dataOff + 9];
|
|
148
|
+
interlaceMethod = bytes[dataOff + 12];
|
|
149
|
+
} else if (type === "IDAT") idatChunks.push(bytes.subarray(dataOff, dataOff + len));
|
|
150
|
+
else if (type === "IEND") break;
|
|
151
|
+
pos = dataOff + len + 4;
|
|
152
|
+
}
|
|
153
|
+
if (width === 0 || height === 0) throw new Error("PNG: missing IHDR");
|
|
154
|
+
if (idatChunks.length === 0) throw new Error("PNG: no IDAT");
|
|
155
|
+
if (interlaceMethod !== 0) throw new Error("PNG: interlaced not supported");
|
|
156
|
+
if (bitDepth !== 8) throw new Error(`PNG: bit depth ${bitDepth} not supported`);
|
|
157
|
+
const inflated = unzlibSync(concatBytes(idatChunks));
|
|
158
|
+
const channels = pngChannels(colorType);
|
|
159
|
+
if (channels === 0) throw new Error(`PNG color type ${colorType} not supported`);
|
|
160
|
+
const bpp = channels;
|
|
161
|
+
const scanlineBytes = width * bpp;
|
|
162
|
+
const expected = height * (1 + scanlineBytes);
|
|
163
|
+
if (inflated.length !== expected) throw new Error(`PNG: inflated size ${inflated.length} != expected ${expected} (interlaced or malformed)`);
|
|
164
|
+
const raw = new Uint8Array(height * scanlineBytes);
|
|
165
|
+
let prev = null;
|
|
166
|
+
for (let y = 0; y < height; y++) {
|
|
167
|
+
const inOff = y * (1 + scanlineBytes);
|
|
168
|
+
const filterType = inflated[inOff];
|
|
169
|
+
const decoded = new Uint8Array(scanlineBytes);
|
|
170
|
+
for (let x = 0; x < scanlineBytes; x++) {
|
|
171
|
+
const filt = inflated[inOff + 1 + x];
|
|
172
|
+
const a = x < bpp ? 0 : decoded[x - bpp];
|
|
173
|
+
const b = prev ? prev[x] : 0;
|
|
174
|
+
const c = !prev || x < bpp ? 0 : prev[x - bpp];
|
|
175
|
+
let v;
|
|
176
|
+
switch (filterType) {
|
|
177
|
+
case 0:
|
|
178
|
+
v = filt;
|
|
179
|
+
break;
|
|
180
|
+
case 1:
|
|
181
|
+
v = filt + a;
|
|
182
|
+
break;
|
|
183
|
+
case 2:
|
|
184
|
+
v = filt + b;
|
|
185
|
+
break;
|
|
186
|
+
case 3:
|
|
187
|
+
v = filt + Math.floor((a + b) / 2);
|
|
188
|
+
break;
|
|
189
|
+
case 4:
|
|
190
|
+
v = filt + paethPredictor(a, b, c);
|
|
191
|
+
break;
|
|
192
|
+
default: throw new Error(`PNG: unknown filter type ${filterType}`);
|
|
193
|
+
}
|
|
194
|
+
decoded[x] = v & 255;
|
|
195
|
+
}
|
|
196
|
+
raw.set(decoded, y * scanlineBytes);
|
|
197
|
+
prev = decoded;
|
|
198
|
+
}
|
|
199
|
+
return splitChannels(width, height, colorType, raw);
|
|
200
|
+
}
|
|
201
|
+
function flattenAlphaOnWhite(decoded) {
|
|
202
|
+
const alpha = decoded.smaskRaw;
|
|
203
|
+
if (!alpha) return decoded;
|
|
204
|
+
const channels = decoded.colorSpace === "DeviceRGB" ? 3 : 1;
|
|
205
|
+
const pixelCount = decoded.width * decoded.height;
|
|
206
|
+
const out = new Uint8Array(pixelCount * channels);
|
|
207
|
+
for (let i = 0; i < pixelCount; i++) {
|
|
208
|
+
const a = alpha[i] / 255;
|
|
209
|
+
for (let c = 0; c < channels; c++) {
|
|
210
|
+
const src = decoded.raw[i * channels + c];
|
|
211
|
+
out[i * channels + c] = Math.round(src * a + 255 * (1 - a));
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
return {
|
|
215
|
+
width: decoded.width,
|
|
216
|
+
height: decoded.height,
|
|
217
|
+
raw: out,
|
|
218
|
+
colorSpace: decoded.colorSpace,
|
|
219
|
+
bitsPerComponent: decoded.bitsPerComponent
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
function splitChannels(width, height, colorType, raw) {
|
|
223
|
+
const pixelCount = width * height;
|
|
224
|
+
if (colorType === 0) return {
|
|
225
|
+
width,
|
|
226
|
+
height,
|
|
227
|
+
raw,
|
|
228
|
+
colorSpace: "DeviceGray",
|
|
229
|
+
bitsPerComponent: 8
|
|
230
|
+
};
|
|
231
|
+
if (colorType === 2) return {
|
|
232
|
+
width,
|
|
233
|
+
height,
|
|
234
|
+
raw,
|
|
235
|
+
colorSpace: "DeviceRGB",
|
|
236
|
+
bitsPerComponent: 8
|
|
237
|
+
};
|
|
238
|
+
if (colorType === 4) {
|
|
239
|
+
const gray = new Uint8Array(pixelCount);
|
|
240
|
+
const alpha = new Uint8Array(pixelCount);
|
|
241
|
+
for (let i = 0; i < pixelCount; i++) {
|
|
242
|
+
gray[i] = raw[i * 2];
|
|
243
|
+
alpha[i] = raw[i * 2 + 1];
|
|
244
|
+
}
|
|
245
|
+
return {
|
|
246
|
+
width,
|
|
247
|
+
height,
|
|
248
|
+
raw: gray,
|
|
249
|
+
colorSpace: "DeviceGray",
|
|
250
|
+
bitsPerComponent: 8,
|
|
251
|
+
smaskRaw: alpha
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
if (colorType === 6) {
|
|
255
|
+
const rgb = new Uint8Array(pixelCount * 3);
|
|
256
|
+
const alpha = new Uint8Array(pixelCount);
|
|
257
|
+
for (let i = 0; i < pixelCount; i++) {
|
|
258
|
+
rgb[i * 3] = raw[i * 4];
|
|
259
|
+
rgb[i * 3 + 1] = raw[i * 4 + 1];
|
|
260
|
+
rgb[i * 3 + 2] = raw[i * 4 + 2];
|
|
261
|
+
alpha[i] = raw[i * 4 + 3];
|
|
262
|
+
}
|
|
263
|
+
return {
|
|
264
|
+
width,
|
|
265
|
+
height,
|
|
266
|
+
raw: rgb,
|
|
267
|
+
colorSpace: "DeviceRGB",
|
|
268
|
+
bitsPerComponent: 8,
|
|
269
|
+
smaskRaw: alpha
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
throw new Error(`PNG color type ${colorType} not supported (palette/indexed?)`);
|
|
273
|
+
}
|
|
274
|
+
function pngChannels(colorType) {
|
|
275
|
+
if (colorType === 0) return 1;
|
|
276
|
+
if (colorType === 2) return 3;
|
|
277
|
+
if (colorType === 4) return 2;
|
|
278
|
+
if (colorType === 6) return 4;
|
|
279
|
+
return 0;
|
|
280
|
+
}
|
|
281
|
+
function paethPredictor(a, b, c) {
|
|
282
|
+
const p = a + b - c;
|
|
283
|
+
const pa = Math.abs(p - a);
|
|
284
|
+
const pb = Math.abs(p - b);
|
|
285
|
+
const pc = Math.abs(p - c);
|
|
286
|
+
if (pa <= pb && pa <= pc) return a;
|
|
287
|
+
if (pb <= pc) return b;
|
|
288
|
+
return c;
|
|
289
|
+
}
|
|
290
|
+
function readU32BE(bytes, offset) {
|
|
291
|
+
return bytes[offset] * 16777216 + (bytes[offset + 1] << 16 | bytes[offset + 2] << 8 | bytes[offset + 3]);
|
|
292
|
+
}
|
|
293
|
+
function chunkType(bytes, offset) {
|
|
294
|
+
return String.fromCharCode(bytes[offset], bytes[offset + 1], bytes[offset + 2], bytes[offset + 3]);
|
|
295
|
+
}
|
|
296
|
+
function concatBytes(parts) {
|
|
297
|
+
let total = 0;
|
|
298
|
+
for (const p of parts) total += p.length;
|
|
299
|
+
const out = new Uint8Array(total);
|
|
300
|
+
let off = 0;
|
|
301
|
+
for (const p of parts) {
|
|
302
|
+
out.set(p, off);
|
|
303
|
+
off += p.length;
|
|
304
|
+
}
|
|
305
|
+
return out;
|
|
306
|
+
}
|
|
307
|
+
//#endregion
|
|
308
|
+
export { detectImageFormat, prepareImage };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Feature } from './features.js';
|
|
2
|
+
import { FlowDoc } from './flow.js';
|
|
3
|
+
import { LossReport } from './loss.js';
|
|
4
|
+
export interface ReadOptions {
|
|
5
|
+
/** Reserved for reader-specific knobs (limits live in the readers). */
|
|
6
|
+
readonly [key: string]: unknown;
|
|
7
|
+
}
|
|
8
|
+
export interface ReadResult<TDoc> {
|
|
9
|
+
readonly doc: TDoc;
|
|
10
|
+
readonly losses: LossReport;
|
|
11
|
+
}
|
|
12
|
+
export interface DocumentReader<TDoc = FlowDoc> {
|
|
13
|
+
/** Format id: 'docx', 'xlsx', 'pdf', … */
|
|
14
|
+
readonly id: string;
|
|
15
|
+
/** Which tree this reader produces. */
|
|
16
|
+
readonly produces: 'flow' | 'page';
|
|
17
|
+
/** Feature vocabulary this reader understands (capability matrix source). */
|
|
18
|
+
readonly supports: ReadonlySet<Feature>;
|
|
19
|
+
/** Cheap format detection (magic bytes / container markers). */
|
|
20
|
+
sniff: (bytes: Uint8Array) => boolean;
|
|
21
|
+
read: (bytes: Uint8Array, opts?: ReadOptions) => ReadResult<TDoc>;
|
|
22
|
+
}
|
|
23
|
+
export interface WriteOptions {
|
|
24
|
+
readonly [key: string]: unknown;
|
|
25
|
+
}
|
|
26
|
+
export interface WriteResult {
|
|
27
|
+
readonly bytes: Uint8Array;
|
|
28
|
+
readonly losses: LossReport;
|
|
29
|
+
}
|
|
30
|
+
export interface DocumentWriter<TDoc> {
|
|
31
|
+
/** Output format id: 'pdf', 'svg', 'html', 'docx', … */
|
|
32
|
+
readonly id: string;
|
|
33
|
+
/** Which tree this writer consumes. */
|
|
34
|
+
readonly consumes: 'flow' | 'page';
|
|
35
|
+
readonly supports: ReadonlySet<Feature>;
|
|
36
|
+
write: (doc: TDoc, opts?: WriteOptions) => WriteResult;
|
|
37
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export type Feature = string;
|
|
2
|
+
export declare const FEATURES: {
|
|
3
|
+
readonly text: "text";
|
|
4
|
+
readonly tables: "tables";
|
|
5
|
+
readonly tablesNested: "tables.nested";
|
|
6
|
+
readonly lists: "lists";
|
|
7
|
+
readonly sections: "sections";
|
|
8
|
+
readonly headersFooters: "headersFooters";
|
|
9
|
+
readonly images: "images";
|
|
10
|
+
readonly imagesJp2: "images.jp2";
|
|
11
|
+
readonly shapes: "shapes";
|
|
12
|
+
readonly charts: "charts";
|
|
13
|
+
readonly math: "math";
|
|
14
|
+
readonly rtl: "rtl";
|
|
15
|
+
readonly trackedChanges: "trackedChanges";
|
|
16
|
+
readonly hyphenation: "hyphenation";
|
|
17
|
+
readonly fontsEmbedding: "fonts.embedding";
|
|
18
|
+
readonly fontsSubstitution: "fonts.substitution";
|
|
19
|
+
readonly pdfA: "pdf.archival";
|
|
20
|
+
readonly pdfTagged: "pdf.tagged";
|
|
21
|
+
readonly pdfSignatures: "pdf.signatures";
|
|
22
|
+
};
|
|
23
|
+
export type KnownFeature = (typeof FEATURES)[keyof typeof FEATURES];
|
|
24
|
+
/** True when `feature` equals `prefix` or sits under it ('tables.nested' ⊂ 'tables'). */
|
|
25
|
+
export declare function featureWithin(feature: Feature, prefix: Feature): boolean;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
//#region src/core/ir/features.ts
|
|
2
|
+
var FEATURES = {
|
|
3
|
+
text: "text",
|
|
4
|
+
tables: "tables",
|
|
5
|
+
tablesNested: "tables.nested",
|
|
6
|
+
lists: "lists",
|
|
7
|
+
sections: "sections",
|
|
8
|
+
headersFooters: "headersFooters",
|
|
9
|
+
images: "images",
|
|
10
|
+
imagesJp2: "images.jp2",
|
|
11
|
+
shapes: "shapes",
|
|
12
|
+
charts: "charts",
|
|
13
|
+
math: "math",
|
|
14
|
+
rtl: "rtl",
|
|
15
|
+
trackedChanges: "trackedChanges",
|
|
16
|
+
hyphenation: "hyphenation",
|
|
17
|
+
fontsEmbedding: "fonts.embedding",
|
|
18
|
+
fontsSubstitution: "fonts.substitution",
|
|
19
|
+
pdfA: "pdf.archival",
|
|
20
|
+
pdfTagged: "pdf.tagged",
|
|
21
|
+
pdfSignatures: "pdf.signatures"
|
|
22
|
+
};
|
|
23
|
+
//#endregion
|
|
24
|
+
export { FEATURES };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { BodyElement, Chart, DocumentInfo, Numbering, Section, SectionProperties, StyleSheet } from '../document-model/index.js';
|
|
2
|
+
import { FontRegistry } from '../font/index.js';
|
|
3
|
+
import { ResourceStore } from './resources.js';
|
|
4
|
+
export interface FlowDoc {
|
|
5
|
+
readonly kind: 'flow';
|
|
6
|
+
readonly body: ReadonlyArray<BodyElement>;
|
|
7
|
+
/** Multi-section page geometry (docx). Empty for single-geometry sources. */
|
|
8
|
+
readonly sections: ReadonlyArray<Section>;
|
|
9
|
+
/** Single-section page geometry (xlsx print setup). */
|
|
10
|
+
readonly section?: SectionProperties;
|
|
11
|
+
readonly styles: StyleSheet;
|
|
12
|
+
readonly numbering?: Numbering;
|
|
13
|
+
readonly headersFooters?: ReadonlyMap<string, ReadonlyArray<BodyElement>>;
|
|
14
|
+
/** Parsed charts keyed by relationship id (ChartBlock.chartRelId). */
|
|
15
|
+
readonly charts?: ReadonlyMap<string, Chart>;
|
|
16
|
+
/** Content-addressed binary resources (images). */
|
|
17
|
+
readonly resources: ResourceStore;
|
|
18
|
+
/** Fonts embedded in the source document itself (docx fontTable), by name. */
|
|
19
|
+
readonly embeddedFonts?: ReadonlyMap<string, FontRegistry>;
|
|
20
|
+
/** Document metadata from docProps/core.xml. */
|
|
21
|
+
readonly info?: DocumentInfo;
|
|
22
|
+
/** Document natural language hint (BCP-47), e.g. for tagged-PDF /Lang. */
|
|
23
|
+
readonly language?: string;
|
|
24
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type { Pt } from './units.js';
|
|
2
|
+
export { pt, twipsToPt, halfPtToPt, eighthPtToPt, emuToPt, pxToPt, inchToPt, mmToPt, } from './units.js';
|
|
3
|
+
export type { ResourceId } from './resources.js';
|
|
4
|
+
export { ResourceStore } from './resources.js';
|
|
5
|
+
export type { Feature, KnownFeature } from './features.js';
|
|
6
|
+
export { FEATURES, featureWithin } from './features.js';
|
|
7
|
+
export type { Loss, LossReport, LossSeverity } from './loss.js';
|
|
8
|
+
export { ConversionLossError, formatLoss } from './loss.js';
|
|
9
|
+
export interface NativeBag {
|
|
10
|
+
readonly [formatId: string]: unknown;
|
|
11
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Feature } from './features.js';
|
|
2
|
+
/**
|
|
3
|
+
* - `dropped` — content is absent from the output (e.g. math → markdown).
|
|
4
|
+
* - `degraded` — content survives with reduced fidelity (e.g. gradient → flat fill).
|
|
5
|
+
* - `substituted` — content was replaced by an equivalent (e.g. font substitution).
|
|
6
|
+
*/
|
|
7
|
+
export type LossSeverity = 'dropped' | 'degraded' | 'substituted';
|
|
8
|
+
export interface Loss {
|
|
9
|
+
readonly severity: LossSeverity;
|
|
10
|
+
readonly feature: Feature;
|
|
11
|
+
/** Human-readable specifics: what exactly happened to what. */
|
|
12
|
+
readonly detail: string;
|
|
13
|
+
/** Optional location hint (page/paragraph/sheet reference). */
|
|
14
|
+
readonly where?: string;
|
|
15
|
+
}
|
|
16
|
+
export type LossReport = ReadonlyArray<Loss>;
|
|
17
|
+
export declare function formatLoss(loss: Loss): string;
|
|
18
|
+
/** Thrown by strict-mode conversions on the first recorded loss. */
|
|
19
|
+
export declare class ConversionLossError extends Error {
|
|
20
|
+
readonly loss: Loss;
|
|
21
|
+
constructor(loss: Loss);
|
|
22
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
//#region src/core/ir/loss.ts
|
|
2
|
+
function formatLoss(loss) {
|
|
3
|
+
const where = loss.where ? ` at ${loss.where}` : "";
|
|
4
|
+
return `[${loss.severity}] ${loss.feature}${where}: ${loss.detail}`;
|
|
5
|
+
}
|
|
6
|
+
/** Thrown by strict-mode conversions on the first recorded loss. */
|
|
7
|
+
var ConversionLossError = class extends Error {
|
|
8
|
+
constructor(loss) {
|
|
9
|
+
super(`strict conversion failed — ${formatLoss(loss)}`);
|
|
10
|
+
this.loss = loss;
|
|
11
|
+
this.name = "ConversionLossError";
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
//#endregion
|
|
15
|
+
export { ConversionLossError, formatLoss };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export type ResourceId = string & {
|
|
2
|
+
readonly __brand: 'resource-id';
|
|
3
|
+
};
|
|
4
|
+
export declare class ResourceStore {
|
|
5
|
+
private readonly byId;
|
|
6
|
+
/**
|
|
7
|
+
* Store bytes and return their content-addressed id. Re-putting identical
|
|
8
|
+
* bytes returns the existing id (deduplication); a hash collision with
|
|
9
|
+
* different bytes probes deterministic `~n` suffixes.
|
|
10
|
+
*/
|
|
11
|
+
put(bytes: Uint8Array): ResourceId;
|
|
12
|
+
get(id: ResourceId): Uint8Array | undefined;
|
|
13
|
+
has(id: ResourceId): boolean;
|
|
14
|
+
ids(): ReadonlyArray<ResourceId>;
|
|
15
|
+
get size(): number;
|
|
16
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
//#region src/core/ir/resources.ts
|
|
2
|
+
var FNV_PRIME = 16777619;
|
|
3
|
+
function hashBytes(bytes) {
|
|
4
|
+
let a = 2166136261;
|
|
5
|
+
let b = 3421674724;
|
|
6
|
+
for (const byte of bytes) {
|
|
7
|
+
a = Math.imul(a ^ byte, FNV_PRIME);
|
|
8
|
+
b = Math.imul(b ^ byte, FNV_PRIME);
|
|
9
|
+
}
|
|
10
|
+
return `${(a >>> 0).toString(16).padStart(8, "0")}${(b >>> 0).toString(16).padStart(8, "0")}`;
|
|
11
|
+
}
|
|
12
|
+
function equalBytes(x, y) {
|
|
13
|
+
if (x.length !== y.length) return false;
|
|
14
|
+
for (let i = 0; i < x.length; i++) if (x[i] !== y[i]) return false;
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
var ResourceStore = class {
|
|
18
|
+
byId = /* @__PURE__ */ new Map();
|
|
19
|
+
/**
|
|
20
|
+
* Store bytes and return their content-addressed id. Re-putting identical
|
|
21
|
+
* bytes returns the existing id (deduplication); a hash collision with
|
|
22
|
+
* different bytes probes deterministic `~n` suffixes.
|
|
23
|
+
*/
|
|
24
|
+
put(bytes) {
|
|
25
|
+
const base = `r-${hashBytes(bytes)}-${bytes.length}`;
|
|
26
|
+
for (let n = 0;; n++) {
|
|
27
|
+
const id = n === 0 ? base : `${base}~${n}`;
|
|
28
|
+
const existing = this.byId.get(id);
|
|
29
|
+
if (existing === void 0) {
|
|
30
|
+
this.byId.set(id, bytes);
|
|
31
|
+
return id;
|
|
32
|
+
}
|
|
33
|
+
if (equalBytes(existing, bytes)) return id;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
get(id) {
|
|
37
|
+
return this.byId.get(id);
|
|
38
|
+
}
|
|
39
|
+
has(id) {
|
|
40
|
+
return this.byId.has(id);
|
|
41
|
+
}
|
|
42
|
+
ids() {
|
|
43
|
+
return [...this.byId.keys()];
|
|
44
|
+
}
|
|
45
|
+
get size() {
|
|
46
|
+
return this.byId.size;
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
//#endregion
|
|
50
|
+
export { ResourceStore };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export type Pt = number & {
|
|
2
|
+
readonly __brand: 'pt';
|
|
3
|
+
};
|
|
4
|
+
/** Brand a raw number as points. The number must already BE points. */
|
|
5
|
+
export declare function pt(value: number): Pt;
|
|
6
|
+
export declare function twipsToPt(twips: number): Pt;
|
|
7
|
+
/** Half-points (OOXML font sizes, `w:sz`): 2 half-points = 1 pt. */
|
|
8
|
+
export declare function halfPtToPt(halfPt: number): Pt;
|
|
9
|
+
/** Eighths of a point (OOXML border widths, `w:sz` on borders): 8 = 1 pt. */
|
|
10
|
+
export declare function eighthPtToPt(eighthPt: number): Pt;
|
|
11
|
+
/** English Metric Units (DrawingML): 914400 EMU = 1 inch = 72 pt → 12700 EMU = 1 pt. */
|
|
12
|
+
export declare function emuToPt(emu: number): Pt;
|
|
13
|
+
/** CSS reference pixels: 96 px = 1 inch = 72 pt. */
|
|
14
|
+
export declare function pxToPt(px: number): Pt;
|
|
15
|
+
export declare function inchToPt(inches: number): Pt;
|
|
16
|
+
export declare function mmToPt(mm: number): Pt;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
//#region src/core/ir/units.ts
|
|
2
|
+
/** Brand a raw number as points. The number must already BE points. */
|
|
3
|
+
function pt(value) {
|
|
4
|
+
return value;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Twentieths of a point (OOXML `dxa` / twips): 20 twips = 1 pt.
|
|
8
|
+
*
|
|
9
|
+
* Deliberately `* (1/20)`, not `/ 20`: the two differ in the last ulp for ~35%
|
|
10
|
+
* of integer inputs, and the layout engine historically multiplied by a
|
|
11
|
+
* `TWIP_TO_PT = 1/20` constant — keeping the exact operator keeps the
|
|
12
|
+
* byte-identical corpus gate meaningful across the IR migration.
|
|
13
|
+
*/
|
|
14
|
+
var TWIP_TO_PT = 1 / 20;
|
|
15
|
+
function twipsToPt(twips) {
|
|
16
|
+
return twips * TWIP_TO_PT;
|
|
17
|
+
}
|
|
18
|
+
/** Half-points (OOXML font sizes, `w:sz`): 2 half-points = 1 pt. */
|
|
19
|
+
function halfPtToPt(halfPt) {
|
|
20
|
+
return halfPt / 2;
|
|
21
|
+
}
|
|
22
|
+
/** Eighths of a point (OOXML border widths, `w:sz` on borders): 8 = 1 pt. */
|
|
23
|
+
function eighthPtToPt(eighthPt) {
|
|
24
|
+
return eighthPt / 8;
|
|
25
|
+
}
|
|
26
|
+
/** English Metric Units (DrawingML): 914400 EMU = 1 inch = 72 pt → 12700 EMU = 1 pt. */
|
|
27
|
+
function emuToPt(emu) {
|
|
28
|
+
return emu / 12700;
|
|
29
|
+
}
|
|
30
|
+
/** CSS reference pixels: 96 px = 1 inch = 72 pt. */
|
|
31
|
+
function pxToPt(px) {
|
|
32
|
+
return px * .75;
|
|
33
|
+
}
|
|
34
|
+
function inchToPt(inches) {
|
|
35
|
+
return inches * 72;
|
|
36
|
+
}
|
|
37
|
+
function mmToPt(mm) {
|
|
38
|
+
return mm / 25.4 * 72;
|
|
39
|
+
}
|
|
40
|
+
//#endregion
|
|
41
|
+
export { eighthPtToPt, emuToPt, halfPtToPt, inchToPt, mmToPt, pt, pxToPt, twipsToPt };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//#region src/line-breaker/knuth-plass.ts
|
|
1
|
+
//#region src/core/line-breaker/knuth-plass.ts
|
|
2
2
|
var FORCED_BREAK = -1e4;
|
|
3
3
|
var FORBIDDEN_BREAK = 1e4;
|
|
4
4
|
var LINE_PENALTY = 10;
|
|
@@ -91,7 +91,7 @@ function breakLines(items, lineWidths) {
|
|
|
91
91
|
const badness = 100 * Math.pow(Math.abs(r), 3);
|
|
92
92
|
let d;
|
|
93
93
|
if (penaltyAtBreak >= 0 && penaltyAtBreak < FORBIDDEN_BREAK) d = Math.pow(LINE_PENALTY + badness + penaltyAtBreak, 2);
|
|
94
|
-
else if (penaltyAtBreak >
|
|
94
|
+
else if (penaltyAtBreak > -1e4 && penaltyAtBreak < 0) d = Math.pow(LINE_PENALTY + badness, 2) - penaltyAtBreak * penaltyAtBreak;
|
|
95
95
|
else d = Math.pow(LINE_PENALTY + badness, 2);
|
|
96
96
|
return d;
|
|
97
97
|
};
|
|
@@ -169,4 +169,4 @@ function breakLines(items, lineWidths) {
|
|
|
169
169
|
};
|
|
170
170
|
}
|
|
171
171
|
//#endregion
|
|
172
|
-
export { breakLines };
|
|
172
|
+
export { FORCED_BREAK, breakLines };
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { BodyElement, Numbering } from '../document-model/index.js';
|
|
2
|
+
export declare function applyNumbering(body: ReadonlyArray<BodyElement>, numbering: Numbering | undefined): Array<BodyElement>;
|
|
3
|
+
export declare function applyNumberingToHeadersFooters(hf: ReadonlyMap<string, ReadonlyArray<BodyElement>> | undefined, numbering: Numbering | undefined): ReadonlyMap<string, ReadonlyArray<BodyElement>>;
|