reamkit 1.25.1 → 1.26.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 +5 -3
- package/dist/esm/pdf-reader/content.d.ts +2 -16
- package/dist/esm/pdf-reader/content.js +69 -3
- package/dist/esm/pdf-reader/font.js +21 -1
- package/dist/esm/pdf-reader/glyph-names.d.ts +6 -0
- package/dist/esm/pdf-reader/glyph-names.js +408 -0
- package/dist/esm/pdf-reader/image-decode.js +32 -1
- package/dist/esm/pdf-reader/jbig2.d.ts +86 -0
- package/dist/esm/pdf-reader/jbig2.js +2597 -0
- package/dist/esm/pdf-reader/shading.d.ts +13 -0
- package/dist/esm/pdf-reader/shading.js +68 -2
- package/dist/esm/pdf-reader/vector.js +5 -4
- package/dist/esm/word/docx-writer.js +140 -12
- package/package.json +1 -1
|
@@ -25,3 +25,16 @@ export declare function buildShadingMap(file: PdfFile, page: PdfPage): Map<strin
|
|
|
25
25
|
* @returns Name → fill alpha, for the states that state one below 1.
|
|
26
26
|
*/
|
|
27
27
|
export declare function buildAlphaMap(file: PdfFile, page: PdfPage): Map<string, number>;
|
|
28
|
+
/**
|
|
29
|
+
* §8.6 — how many components a colour space takes, and what they mean.
|
|
30
|
+
*
|
|
31
|
+
* `sc` / `scn` give bare numbers; only the space in force says whether `1 1 1`
|
|
32
|
+
* is white or something else, and whether a lone `1` is white (DeviceGray) or
|
|
33
|
+
* the colorant at full strength (Separation), which is usually black.
|
|
34
|
+
*/
|
|
35
|
+
export interface ColorSpaceInfo {
|
|
36
|
+
readonly kind: 'gray' | 'rgb' | 'cmyk' | 'tint';
|
|
37
|
+
readonly components: number;
|
|
38
|
+
}
|
|
39
|
+
/** The spaces a page's `/ColorSpace` resources name, by name. */
|
|
40
|
+
export declare function buildColorSpaceMap(file: PdfFile, page: PdfPage): Map<string, ColorSpaceInfo>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { PDF_NULL, PdfStream } from "../pdf/objects.js";
|
|
1
|
+
import { PDF_NULL, PdfName, PdfStream } from "../pdf/objects.js";
|
|
2
2
|
//#region src/pdf-reader/shading.ts
|
|
3
3
|
/**
|
|
4
4
|
* Resolve a page's `/Pattern` resources into gradient fills (E-PDF EP16c, ISO
|
|
@@ -179,5 +179,71 @@ function buildAlphaMap(file, page) {
|
|
|
179
179
|
}
|
|
180
180
|
return out;
|
|
181
181
|
}
|
|
182
|
+
/** The spaces a page's `/ColorSpace` resources name, by name. */
|
|
183
|
+
function buildColorSpaceMap(file, page) {
|
|
184
|
+
const out = /* @__PURE__ */ new Map();
|
|
185
|
+
if (!page.resources) return out;
|
|
186
|
+
const spaces = file.get(page.resources, "ColorSpace");
|
|
187
|
+
if (!(spaces instanceof Map)) return out;
|
|
188
|
+
for (const [name, value] of spaces) {
|
|
189
|
+
const info = colorSpaceInfo(file, file.resolve(value));
|
|
190
|
+
if (info) out.set(name, info);
|
|
191
|
+
}
|
|
192
|
+
return out;
|
|
193
|
+
}
|
|
194
|
+
/** What a colour space object comes to, or `undefined` for one not read. */
|
|
195
|
+
function colorSpaceInfo(file, cs) {
|
|
196
|
+
if (cs instanceof PdfName) return byFamily(cs.value, 0);
|
|
197
|
+
if (!Array.isArray(cs) || cs.length === 0) return void 0;
|
|
198
|
+
const head = file.resolve(cs[0]);
|
|
199
|
+
if (!(head instanceof PdfName)) return void 0;
|
|
200
|
+
if (head.value === "ICCBased") {
|
|
201
|
+
const stream = file.resolve(cs[1] ?? PDF_NULL);
|
|
202
|
+
const n = stream instanceof PdfStream ? file.get(stream.dict, "N") : void 0;
|
|
203
|
+
return byFamily("ICCBased", typeof n === "number" ? n : 3);
|
|
204
|
+
}
|
|
205
|
+
if (head.value === "Indexed") return;
|
|
206
|
+
if (head.value === "Separation" || head.value === "DeviceN") {
|
|
207
|
+
const names = file.resolve(cs[1] ?? PDF_NULL);
|
|
208
|
+
return {
|
|
209
|
+
kind: "tint",
|
|
210
|
+
components: head.value === "Separation" ? 1 : Array.isArray(names) ? names.length : 1
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
return byFamily(head.value, 0);
|
|
214
|
+
}
|
|
215
|
+
function byFamily(family, n) {
|
|
216
|
+
switch (family) {
|
|
217
|
+
case "DeviceGray":
|
|
218
|
+
case "CalGray":
|
|
219
|
+
case "G": return {
|
|
220
|
+
kind: "gray",
|
|
221
|
+
components: 1
|
|
222
|
+
};
|
|
223
|
+
case "DeviceRGB":
|
|
224
|
+
case "CalRGB":
|
|
225
|
+
case "Lab":
|
|
226
|
+
case "RGB": return {
|
|
227
|
+
kind: "rgb",
|
|
228
|
+
components: 3
|
|
229
|
+
};
|
|
230
|
+
case "DeviceCMYK":
|
|
231
|
+
case "CMYK": return {
|
|
232
|
+
kind: "cmyk",
|
|
233
|
+
components: 4
|
|
234
|
+
};
|
|
235
|
+
case "ICCBased": return n === 1 ? {
|
|
236
|
+
kind: "gray",
|
|
237
|
+
components: 1
|
|
238
|
+
} : n === 4 ? {
|
|
239
|
+
kind: "cmyk",
|
|
240
|
+
components: 4
|
|
241
|
+
} : {
|
|
242
|
+
kind: "rgb",
|
|
243
|
+
components: 3
|
|
244
|
+
};
|
|
245
|
+
default: return;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
182
248
|
//#endregion
|
|
183
|
-
export { buildAlphaMap, buildShadingMap };
|
|
249
|
+
export { buildAlphaMap, buildColorSpaceMap, buildShadingMap };
|
|
@@ -3,7 +3,7 @@ import { FEATURES } from "../core/ir/features.js";
|
|
|
3
3
|
import { IDENTITY, interpretContent, multiply } from "./content.js";
|
|
4
4
|
import { collectPageAppearances } from "./annots.js";
|
|
5
5
|
import { buildFonts } from "./text.js";
|
|
6
|
-
import { buildAlphaMap, buildShadingMap } from "./shading.js";
|
|
6
|
+
import { buildAlphaMap, buildColorSpaceMap, buildShadingMap } from "./shading.js";
|
|
7
7
|
//#region src/pdf-reader/vector.ts
|
|
8
8
|
/**
|
|
9
9
|
* Every vector the page paints, its FORM XOBJECTS included (§8.8).
|
|
@@ -17,14 +17,14 @@ import { buildAlphaMap, buildShadingMap } from "./shading.js";
|
|
|
17
17
|
* The same walk `collectPageImages` already makes, with the same depth and
|
|
18
18
|
* cycle guards, collecting paths instead of pictures.
|
|
19
19
|
*/
|
|
20
|
-
function paintedVectors(file, page, shadings, alphas) {
|
|
20
|
+
function paintedVectors(file, page, shadings, alphas, spaces) {
|
|
21
21
|
const out = [];
|
|
22
22
|
const visiting = /* @__PURE__ */ new Set();
|
|
23
23
|
const walk = (resources, content, baseCtm, depth, prefix) => {
|
|
24
24
|
if (out.length >= MAX_VECTORS) return;
|
|
25
25
|
const xobjects = resources ? file.get(resources, "XObject") : PDF_NULL;
|
|
26
26
|
const xobjDict = xobjects instanceof Map ? xobjects : void 0;
|
|
27
|
-
const result = interpretContent(content, buildFonts(file, resources), baseCtm, shadings, alphas);
|
|
27
|
+
const result = interpretContent(content, buildFonts(file, resources), baseCtm, shadings, alphas, spaces);
|
|
28
28
|
const events = [
|
|
29
29
|
...result.vectors.map((vector) => ({
|
|
30
30
|
order: vector.order,
|
|
@@ -120,9 +120,10 @@ function collectPageVectors(file, page, occupied = []) {
|
|
|
120
120
|
const pageArea = Math.max(1, Math.abs((px1 - px0) * (py1 - py0)));
|
|
121
121
|
const shadings = buildShadingMap(file, page);
|
|
122
122
|
const alphas = buildAlphaMap(file, page);
|
|
123
|
+
const spaces = buildColorSpaceMap(file, page);
|
|
123
124
|
const out = [];
|
|
124
125
|
const painted = [...occupied];
|
|
125
|
-
const raws = paintedVectors(file, page, shadings, alphas);
|
|
126
|
+
const raws = paintedVectors(file, page, shadings, alphas, spaces);
|
|
126
127
|
for (const raw of raws) {
|
|
127
128
|
if (out.length >= MAX_VECTORS) break;
|
|
128
129
|
const v = clipped(raw);
|
|
@@ -43,10 +43,6 @@ var RASTER_MEDIA = {
|
|
|
43
43
|
ext: "jpeg",
|
|
44
44
|
contentType: "image/jpeg"
|
|
45
45
|
},
|
|
46
|
-
jpeg2000: {
|
|
47
|
-
ext: "jp2",
|
|
48
|
-
contentType: "image/jp2"
|
|
49
|
-
},
|
|
50
46
|
gif: {
|
|
51
47
|
ext: "gif",
|
|
52
48
|
contentType: "image/gif"
|
|
@@ -56,6 +52,18 @@ var RASTER_MEDIA = {
|
|
|
56
52
|
contentType: "image/bmp"
|
|
57
53
|
}
|
|
58
54
|
};
|
|
55
|
+
/**
|
|
56
|
+
* Why an image was not written, in terms of the image — for the loss report,
|
|
57
|
+
* which used to say "image bytes missing" whatever the reason, including for
|
|
58
|
+
* bytes that were all there and in a format the format does not admit.
|
|
59
|
+
*/
|
|
60
|
+
function imageRefusal(resource, state) {
|
|
61
|
+
const bytes = resource === void 0 ? void 0 : state.resources.get(resource);
|
|
62
|
+
if (!bytes) return "image bytes missing";
|
|
63
|
+
const format = detectImageFormat(bytes);
|
|
64
|
+
if (format === "jpeg2000") return "JPEG 2000 picture dropped — §15.2.14 admits no such image part, and no reader of a .docx shows one";
|
|
65
|
+
return `picture dropped — ${format ?? "an unrecognised"} is not an image part a .docx may carry`;
|
|
66
|
+
}
|
|
59
67
|
function mediaInfo(bytes) {
|
|
60
68
|
const raster = detectImageFormat(bytes);
|
|
61
69
|
if (raster) return RASTER_MEDIA[raster];
|
|
@@ -137,9 +145,7 @@ function writeDocx(flow) {
|
|
|
137
145
|
if (i === sections.length - 1) finalSectPr = sp;
|
|
138
146
|
else sectPrByClosingIndex.set(sec.endIndex - 1, sp);
|
|
139
147
|
});
|
|
140
|
-
flow.body
|
|
141
|
-
emitBlock(body, el, losses, state, docScope, sectPrByClosingIndex.get(idx));
|
|
142
|
-
});
|
|
148
|
+
emitBody(body, flow.body, losses, state, docScope, sectPrByClosingIndex);
|
|
143
149
|
if (finalSectPr) body.push(finalSectPr);
|
|
144
150
|
const documentXml = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?><w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"><w:body>${body.join("")}</w:body></w:document>`;
|
|
145
151
|
const numberingPart = flow.body.some((el) => el.kind === "paragraph" && el.paragraph.properties.numbering !== void 0) && flow.numbering ? {
|
|
@@ -365,6 +371,59 @@ var docxWriter = {
|
|
|
365
371
|
supports: new Set([FEATURES.text]),
|
|
366
372
|
write: (doc) => writeDocx(doc)
|
|
367
373
|
};
|
|
374
|
+
/**
|
|
375
|
+
* The document body, with consecutive floating drawings gathered into one
|
|
376
|
+
* carrier paragraph.
|
|
377
|
+
*
|
|
378
|
+
* §20.4.2.3 — a floating drawing is placed by its anchor and not by where its
|
|
379
|
+
* paragraph lands, so the paragraph is only somewhere for the anchor to hang
|
|
380
|
+
* from. Given one paragraph EACH, a page of placed artwork is that many
|
|
381
|
+
* paragraphs of flow: 160F-2019.pdf's one-page form is 355 drawings, and Word
|
|
382
|
+
* ran it to sixteen pages of empty lines with the artwork anchored to them.
|
|
383
|
+
* Gathered, the page costs one paragraph however much is placed on it.
|
|
384
|
+
*
|
|
385
|
+
* A block that closes a section keeps its own paragraph — the section break
|
|
386
|
+
* rides that paragraph's properties, and it must be the last one in the
|
|
387
|
+
* section.
|
|
388
|
+
*/
|
|
389
|
+
function emitBody(out, blocks, losses, state, scope, sectPrByClosingIndex) {
|
|
390
|
+
let carried = [];
|
|
391
|
+
const flush = () => {
|
|
392
|
+
if (carried.length > 0) out.push(`<w:p>${carried.join("")}</w:p>`);
|
|
393
|
+
carried = [];
|
|
394
|
+
};
|
|
395
|
+
blocks.forEach((el, idx) => {
|
|
396
|
+
const closing = sectPrByClosingIndex.get(idx);
|
|
397
|
+
const anchored = closing === void 0 ? floatingDrawingRun(el, losses, state, scope) : void 0;
|
|
398
|
+
if (anchored !== void 0) {
|
|
399
|
+
carried.push(anchored);
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
flush();
|
|
403
|
+
emitBlock(out, el, losses, state, scope, closing);
|
|
404
|
+
});
|
|
405
|
+
flush();
|
|
406
|
+
}
|
|
407
|
+
/**
|
|
408
|
+
* The run holding one block's drawing, when that block states where on the page
|
|
409
|
+
* it goes — `undefined` for everything that flows, which the ordinary block
|
|
410
|
+
* emitter handles.
|
|
411
|
+
*/
|
|
412
|
+
function floatingDrawingRun(el, losses, state, scope) {
|
|
413
|
+
if (el.kind === "image" && el.image.float) {
|
|
414
|
+
const drawing = drawingXml(el.image.resource, el.image.width, el.image.height, el.image.altText, state, scope, el.image.float);
|
|
415
|
+
if (drawing === "") {
|
|
416
|
+
losses.push({
|
|
417
|
+
severity: "dropped",
|
|
418
|
+
feature: FEATURES.images,
|
|
419
|
+
detail: imageRefusal(el.image.resource, state)
|
|
420
|
+
});
|
|
421
|
+
return "";
|
|
422
|
+
}
|
|
423
|
+
return `<w:r>${drawing}</w:r>`;
|
|
424
|
+
}
|
|
425
|
+
if (el.kind === "shape" && el.shape.float) return `<w:r>${shapeDrawingXml(el.shape, losses, state, scope)}</w:r>`;
|
|
426
|
+
}
|
|
368
427
|
function emitBlock(out, el, losses, state, scope, closingSectPr) {
|
|
369
428
|
if (el.kind === "paragraph") {
|
|
370
429
|
out.push(paragraphXml(el.paragraph, state, scope, closingSectPr));
|
|
@@ -376,13 +435,13 @@ function emitBlock(out, el, losses, state, scope, closingSectPr) {
|
|
|
376
435
|
return;
|
|
377
436
|
}
|
|
378
437
|
if (el.kind === "image") {
|
|
379
|
-
const drawing = drawingXml(el.image.resource, el.image.width, el.image.height, el.image.altText, state, scope);
|
|
438
|
+
const drawing = drawingXml(el.image.resource, el.image.width, el.image.height, el.image.altText, state, scope, el.image.float);
|
|
380
439
|
if (drawing) out.push(`<w:p>${pPrWithSect(el.image.paragraphProperties, closingSectPr)}<w:r>${drawing}</w:r></w:p>`);
|
|
381
440
|
else {
|
|
382
441
|
losses.push({
|
|
383
442
|
severity: "dropped",
|
|
384
443
|
feature: FEATURES.images,
|
|
385
|
-
detail:
|
|
444
|
+
detail: imageRefusal(el.image.resource, state)
|
|
386
445
|
});
|
|
387
446
|
if (closingSectPr) out.push(`<w:p><w:pPr>${closingSectPr}</w:pPr></w:p>`);
|
|
388
447
|
}
|
|
@@ -425,14 +484,82 @@ function chartBlockXml(chart, state, scope, losses) {
|
|
|
425
484
|
const id = ++state.drawingSeq;
|
|
426
485
|
return `<w:drawing><wp:inline xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing"><wp:extent cx="${cx}" cy="${cy}"/><wp:docPr id="${id}" name="Chart ${id}"${chart.altText ? ` descr="${escapeAttr(chart.altText)}"` : ""}/><a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"><a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/chart"><c:chart xmlns:c="http://schemas.openxmlformats.org/drawingml/2006/chart" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" r:id="${relId}"/></a:graphicData></a:graphic></wp:inline></w:drawing>`;
|
|
427
486
|
}
|
|
428
|
-
|
|
487
|
+
/**
|
|
488
|
+
* §20.4.2.3 — the frame a drawing is placed by: `wp:anchor` where the block
|
|
489
|
+
* states where on the page it belongs, `wp:inline` where it belongs in the run
|
|
490
|
+
* of text.
|
|
491
|
+
*
|
|
492
|
+
* Everything used to be inline. The document model has carried the anchor since
|
|
493
|
+
* the reader learned to read one, and the PDF reconstruction fills it in for
|
|
494
|
+
* every line and rule it lifts off a page — and all of it was thrown away here,
|
|
495
|
+
* so a converted page came out as a column of drawings stacked in document
|
|
496
|
+
* order. S2.pdf's two colour wheels marched down the left margin as eighteen
|
|
497
|
+
* separate wedges; 160F-2019.pdf's one-page form ran to sixteen pages, because
|
|
498
|
+
* each of its 355 drawings took a paragraph of its own in the flow.
|
|
499
|
+
*
|
|
500
|
+
* The attribute list is not decoration: CT_Anchor requires `simplePos`,
|
|
501
|
+
* `relativeHeight`, `behindDoc`, `locked`, `layoutInCell` and `allowOverlap`,
|
|
502
|
+
* and the children are a SEQUENCE — position, extent, wrap, docPr, graphic —
|
|
503
|
+
* that Word refuses out of order.
|
|
504
|
+
*
|
|
505
|
+
* @param float The placement, or `undefined` for a drawing that flows.
|
|
506
|
+
* @param cx Width in EMU.
|
|
507
|
+
* @param cy Height in EMU.
|
|
508
|
+
* @param head The `wp:docPr` (and anything else) that precedes the graphic.
|
|
509
|
+
* @param graphic The `a:graphic` element the frame carries.
|
|
510
|
+
*/
|
|
511
|
+
function drawingFrame(float, cx, cy, head, graphic, state, rotation60k) {
|
|
512
|
+
const WP_NS = " xmlns:wp=\"http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing\"";
|
|
513
|
+
if (!float) return `<w:drawing><wp:inline${WP_NS}><wp:extent cx="${cx}" cy="${cy}"/>${head}${graphic}</wp:inline></w:drawing>`;
|
|
514
|
+
const emu = (pt) => Number.isFinite(pt) ? Math.round((pt ?? 0) * EMU_PER_PT) : 0;
|
|
515
|
+
const d = float.wrapDist;
|
|
516
|
+
const dist = ` distT="${String(emu(d?.topPt))}" distB="${String(emu(d?.bottomPt))}" distL="${String(emu(d?.leftPt))}" distR="${String(emu(d?.rightPt))}"`;
|
|
517
|
+
const z = float.zOrder ?? ++state.drawingSeq;
|
|
518
|
+
const attrs = `${dist} simplePos="0" relativeHeight="${String(z)}" behindDoc="${float.behind ? "1" : "0"}" locked="0" layoutInCell="${float.inCell === false ? "0" : "1"}" allowOverlap="1"`;
|
|
519
|
+
const pos = (tag, p, fallback) => {
|
|
520
|
+
const from = p?.relativeFrom ?? fallback;
|
|
521
|
+
const body = p?.align !== void 0 ? `<wp:align>${p.align}</wp:align>` : `<wp:posOffset>${String(emu(p?.offsetPt))}</wp:posOffset>`;
|
|
522
|
+
return `<${tag} relativeFrom="${escapeAttr(from)}">${body}</${tag}>`;
|
|
523
|
+
};
|
|
524
|
+
const side = ` wrapText="${float.wrapSide ?? "bothSides"}"`;
|
|
525
|
+
const wrap = float.wrap === "square" ? `<wp:wrapSquare${side}/>` : float.wrap === "tight" ? `<wp:wrapTight${side}/>` : float.wrap === "through" ? `<wp:wrapThrough${side}/>` : float.wrap === "topAndBottom" || float.wrap === "notBeside" ? "<wp:wrapTopAndBottom/>" : "<wp:wrapNone/>";
|
|
526
|
+
return `<w:drawing><wp:anchor${WP_NS}${attrs}><wp:simplePos x="0" y="0"/>` + pos("wp:positionH", float.posH, "column") + pos("wp:positionV", float.posV, "paragraph") + `<wp:extent cx="${cx}" cy="${cy}"/>` + effectExtentXml(cx, cy, rotation60k) + wrap + head + graphic + "</wp:anchor></w:drawing>";
|
|
527
|
+
}
|
|
528
|
+
/**
|
|
529
|
+
* §20.4.2.3 `wp:effectExtent` — how far the drawing reaches PAST the extent.
|
|
530
|
+
*
|
|
531
|
+
* `wp:extent` is the shape's own size, unrotated: fdo75722-dml.docx states
|
|
532
|
+
* 1964690 × 1240790 there and repeats it in `a:ext`, then carries the turn's
|
|
533
|
+
* overhang here (l 198120, t 433705, r 199390, b 430530). Written as zeroes —
|
|
534
|
+
* which they always were — a renderer reserves the flat box for a shape that
|
|
535
|
+
* draws across the turned one, and 160F-2019.pdf's "Nature", set on its side
|
|
536
|
+
* down the middle of a column, came back lying flat across it.
|
|
537
|
+
*
|
|
538
|
+
* A box `w × h` turned by θ about its centre spans `|w·cosθ| + |h·sinθ|`
|
|
539
|
+
* across and `|w·sinθ| + |h·cosθ|` down; half of each growth hangs off each
|
|
540
|
+
* side. A turn that makes the box no wider hangs off by nothing.
|
|
541
|
+
*/
|
|
542
|
+
function effectExtentXml(cx, cy, rotation60k) {
|
|
543
|
+
const none = "<wp:effectExtent l=\"0\" t=\"0\" r=\"0\" b=\"0\"/>";
|
|
544
|
+
if (rotation60k === void 0 || !Number.isFinite(rotation60k) || rotation60k % 216e5 === 0) return none;
|
|
545
|
+
const rad = rotation60k / 6e4 * Math.PI / 180;
|
|
546
|
+
const c = Math.abs(Math.cos(rad));
|
|
547
|
+
const s = Math.abs(Math.sin(rad));
|
|
548
|
+
const overhang = (span, turned) => Math.max(0, Math.round((turned - span) / 2));
|
|
549
|
+
const h = overhang(cx, cx * c + cy * s);
|
|
550
|
+
const v = overhang(cy, cx * s + cy * c);
|
|
551
|
+
return h === 0 && v === 0 ? none : `<wp:effectExtent l="${String(h)}" t="${String(v)}" r="${String(h)}" b="${String(v)}"/>`;
|
|
552
|
+
}
|
|
553
|
+
function drawingXml(resource, widthPt, heightPt, altText, state, scope, float) {
|
|
429
554
|
if (resource === void 0) return "";
|
|
430
555
|
const relId = mediaRelId(resource, state, scope);
|
|
431
556
|
if (relId === void 0) return "";
|
|
432
557
|
const cx = Math.round(widthPt * EMU_PER_PT);
|
|
433
558
|
const cy = Math.round(heightPt * EMU_PER_PT);
|
|
434
559
|
const id = ++state.drawingSeq;
|
|
435
|
-
|
|
560
|
+
const descr = altText ? ` descr="${escapeAttr(altText)}"` : "";
|
|
561
|
+
const graphic = `<a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"><a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture"><pic:pic xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture"><pic:nvPicPr><pic:cNvPr id="${id}" name="Image ${id}"/><pic:cNvPicPr/></pic:nvPicPr><pic:blipFill><a:blip r:embed="${relId}"/><a:stretch><a:fillRect/></a:stretch></pic:blipFill><pic:spPr><a:xfrm><a:off x="0" y="0"/><a:ext cx="${cx}" cy="${cy}"/></a:xfrm><a:prstGeom prst="rect"><a:avLst/></a:prstGeom></pic:spPr></pic:pic></a:graphicData></a:graphic>`;
|
|
562
|
+
return drawingFrame(float, cx, cy, `<wp:docPr id="${id}" name="Image ${id}"${descr}/>`, graphic, state);
|
|
436
563
|
}
|
|
437
564
|
var WPS_URI = "http://schemas.microsoft.com/office/word/2010/wordprocessingShape";
|
|
438
565
|
function shapeDrawingXml(shape, losses, state, scope) {
|
|
@@ -442,7 +569,8 @@ function shapeDrawingXml(shape, losses, state, scope) {
|
|
|
442
569
|
const descr = shape.altText ? ` descr="${escapeAttr(shape.altText)}"` : "";
|
|
443
570
|
const spPr = `<wps:spPr>${xfrmXml(shape.transform, cx, cy)}${geomXml(shape.geometry)}${fillXml(shape.fill)}${shape.line ? lineXml(shape.line) : ""}</wps:spPr>`;
|
|
444
571
|
const txbx = shape.text ? txbxXml(shape.text, losses, state, scope) : "";
|
|
445
|
-
|
|
572
|
+
const graphic = `<a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"><a:graphicData uri="${WPS_URI}"><wps:wsp xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape"><wps:cNvSpPr/>` + spPr + txbx + bodyPrXml(shape.text) + "</wps:wsp></a:graphicData></a:graphic>";
|
|
573
|
+
return drawingFrame(shape.float, cx, cy, `<wp:docPr id="${id}" name="Shape ${id}"${descr}/>`, graphic, state, shape.transform?.rotation60k);
|
|
446
574
|
}
|
|
447
575
|
function xfrmXml(t, cx, cy) {
|
|
448
576
|
return `<a:xfrm${t?.rotation60k !== void 0 ? ` rot="${t.rotation60k}"` : ""}${t?.flipH ? " flipH=\"1\"" : ""}${t?.flipV ? " flipV=\"1\"" : ""}><a:off x="0" y="0"/><a:ext cx="${cx}" cy="${cy}"/></a:xfrm>`;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "reamkit",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.26.0",
|
|
4
4
|
"description": "Ream — convert DOCX, XLSX, PPTX and PDF to PDF, SVG, HTML, DOCX and XLSX, built from scratch on the ECMA-376 and ISO 32000 specifications. Parse once, convert anywhere.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Alex Krassavin <info@reamkit.dev>",
|