reamkit 1.17.0 → 1.18.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/dist/esm/core/document-model/types.d.ts +53 -1
- package/dist/esm/core/images.d.ts +2 -2
- package/dist/esm/core/images.js +38 -0
- package/dist/esm/core/lzw.d.ts +17 -0
- package/dist/esm/core/lzw.js +83 -0
- package/dist/esm/core/metafile/emf.d.ts +16 -0
- package/dist/esm/core/metafile/emf.js +635 -0
- package/dist/esm/core/metafile/picture.d.ts +106 -0
- package/dist/esm/core/metafile/picture.js +55 -0
- package/dist/esm/core/metafile/wmf.d.ts +9 -0
- package/dist/esm/core/metafile/wmf.js +371 -0
- package/dist/esm/core/tiff.d.ts +20 -0
- package/dist/esm/core/tiff.js +339 -0
- package/dist/esm/core/vector.d.ts +5 -0
- package/dist/esm/excel/print-model.js +3 -1
- package/dist/esm/html/html-writer.js +3 -2
- package/dist/esm/layout/page-doc.d.ts +46 -3
- package/dist/esm/layout/styled-layout.js +486 -81
- package/dist/esm/pdf/styled-page-emitter.js +78 -3
- package/dist/esm/pdf/vector-graphics.d.ts +1 -1
- package/dist/esm/pdf/vector-graphics.js +2 -1
- package/dist/esm/pdf-reader/image-decode.js +7 -75
- package/dist/esm/svg/svg-writer.js +1 -1
- package/dist/esm/word/document-parser.js +3 -0
- package/dist/esm/word/drawing-parser.d.ts +5 -0
- package/dist/esm/word/drawing-parser.js +95 -12
- package/package.json +1 -1
|
@@ -15,6 +15,33 @@ import { addSignaturePlaceholder } from "./signature.js";
|
|
|
15
15
|
import { buildXmpPacket } from "./xmp.js";
|
|
16
16
|
//#region src/pdf/styled-page-emitter.ts
|
|
17
17
|
var encoder = new TextEncoder();
|
|
18
|
+
function washVeil(wash) {
|
|
19
|
+
if (!wash) return void 0;
|
|
20
|
+
const alpha = 1 - wash.gain;
|
|
21
|
+
if (!(alpha > .004)) return void 0;
|
|
22
|
+
const offset = .5 * (1 - wash.gain) + wash.black;
|
|
23
|
+
return {
|
|
24
|
+
alpha: Math.min(1, alpha),
|
|
25
|
+
grey: Math.max(0, Math.min(1, offset / alpha))
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* The veil operators for a washed picture, to follow its own `/Im Do`: the
|
|
30
|
+
* placement matrix maps the unit square onto the picture as drawn, so the wash
|
|
31
|
+
* covers exactly it — cropped, rotated and flipped along with it.
|
|
32
|
+
*/
|
|
33
|
+
function washItems(wash, alphaStateNames) {
|
|
34
|
+
const veil = washVeil(wash);
|
|
35
|
+
if (!veil) return [];
|
|
36
|
+
const g = formatNumber(veil.grey);
|
|
37
|
+
const state = veil.alpha < 1 ? alphaStateNames?.get(Math.round(veil.alpha * 1e3) / 1e3) : void 0;
|
|
38
|
+
return [
|
|
39
|
+
...state === void 0 ? [] : [`/${state} gs`],
|
|
40
|
+
`${g} ${g} ${g} rg`,
|
|
41
|
+
"0 0 1 1 re",
|
|
42
|
+
"f"
|
|
43
|
+
];
|
|
44
|
+
}
|
|
18
45
|
/**
|
|
19
46
|
* The emit phase: turn a laid-out document into PDF objects (ISO 32000) and
|
|
20
47
|
* serialize it. The counterpart of `layoutStyledDocument` (the seam of
|
|
@@ -113,8 +140,13 @@ function assembleStyledPdf(laid, options, doc) {
|
|
|
113
140
|
for (const item of plan.shapes) {
|
|
114
141
|
const s = item.shape.shadow;
|
|
115
142
|
if (s) wantAlpha(shadowBlurLayers(s).alpha);
|
|
143
|
+
wantAlpha(item.shape.fillAlpha);
|
|
144
|
+
}
|
|
145
|
+
for (const img of plan.images) wantAlpha(washVeil(img.wash)?.alpha);
|
|
146
|
+
for (const line of plan.lines) for (const tok of line.line.tokens) {
|
|
147
|
+
if (tok.kind === "image" && tok.shadow) wantAlpha(shadowBlurLayers(tok.shadow).alpha);
|
|
148
|
+
if (tok.kind === "image") wantAlpha(washVeil(tok.wash)?.alpha);
|
|
116
149
|
}
|
|
117
|
-
for (const line of plan.lines) for (const tok of line.line.tokens) if (tok.kind === "image" && tok.shadow) wantAlpha(shadowBlurLayers(tok.shadow).alpha);
|
|
118
150
|
}
|
|
119
151
|
const resourcesDict = dict({
|
|
120
152
|
Font: fontResourceDict,
|
|
@@ -391,7 +423,10 @@ function defaultPageCtx() {
|
|
|
391
423
|
}
|
|
392
424
|
function embedImageResources(doc, laid) {
|
|
393
425
|
const out = /* @__PURE__ */ new Map();
|
|
394
|
-
for (const [resourceId, res] of laid.imageResources)
|
|
426
|
+
for (const [resourceId, res] of laid.imageResources) {
|
|
427
|
+
if (!res.prepared) continue;
|
|
428
|
+
out.set(resourceId, addImage(doc, res.prepared).ref);
|
|
429
|
+
}
|
|
395
430
|
return out;
|
|
396
431
|
}
|
|
397
432
|
function embedFontResources(doc, laid, pdfaProfile) {
|
|
@@ -528,6 +563,7 @@ function emitPageContent(page, tagging, gradientNames, alphaStateNames) {
|
|
|
528
563
|
}
|
|
529
564
|
out.push(...placeImage(img.x, H - img.y - img.height, img.width, img.height, img.crop, img.rotationDeg, img.flipH, img.flipV));
|
|
530
565
|
out.push(`/${img.imageResourceName} Do`);
|
|
566
|
+
out.push(...washItems(img.wash, alphaStateNames));
|
|
531
567
|
out.push("Q");
|
|
532
568
|
});
|
|
533
569
|
const borders = plan.borders;
|
|
@@ -615,7 +651,9 @@ function emitPageContent(page, tagging, gradientNames, alphaStateNames) {
|
|
|
615
651
|
};
|
|
616
652
|
const shadowLayer = sh.shape.shadow ? shadowBlurLayers(sh.shape.shadow) : void 0;
|
|
617
653
|
const alphaState = shadowLayer && shadowLayer.alpha < 1 ? alphaStateNames?.get(Math.round(shadowLayer.alpha * 1e3) / 1e3) : void 0;
|
|
618
|
-
|
|
654
|
+
const fillAlpha = sh.shape.fillAlpha;
|
|
655
|
+
const fillAlphaState = fillAlpha !== void 0 && fillAlpha < 1 ? alphaStateNames?.get(Math.round(fillAlpha * 1e3) / 1e3) : void 0;
|
|
656
|
+
for (const op of emitVectorShape(shape, gradientNames?.get(sh.shape), alphaState, fillAlphaState)) out.push(op);
|
|
619
657
|
});
|
|
620
658
|
const lines = plan.lines;
|
|
621
659
|
if (lines.length > 0) {
|
|
@@ -643,6 +681,42 @@ function emitPageContent(page, tagging, gradientNames, alphaStateNames) {
|
|
|
643
681
|
}
|
|
644
682
|
};
|
|
645
683
|
const emitImageToken = (tok, x, baselineY) => {
|
|
684
|
+
const meta = tok.metafile;
|
|
685
|
+
if (meta) {
|
|
686
|
+
if (inBT) {
|
|
687
|
+
out.push("ET");
|
|
688
|
+
inBT = false;
|
|
689
|
+
}
|
|
690
|
+
const b = tok.drawBox;
|
|
691
|
+
const ox = x + (b?.dxPt ?? 0);
|
|
692
|
+
const oy = baselineY + (b?.dyPt ?? 0);
|
|
693
|
+
for (const sh of meta.shapes) for (const op of emitVectorShape({
|
|
694
|
+
...sh,
|
|
695
|
+
transform: [
|
|
696
|
+
1,
|
|
697
|
+
0,
|
|
698
|
+
0,
|
|
699
|
+
1,
|
|
700
|
+
ox,
|
|
701
|
+
oy
|
|
702
|
+
]
|
|
703
|
+
})) out.push(op);
|
|
704
|
+
for (const t of meta.texts) {
|
|
705
|
+
const first = t.line.tokens.find((k) => k.kind === "text");
|
|
706
|
+
if (!first) continue;
|
|
707
|
+
const [r, g, bl] = hexToRgb01(first.resolvedRun.colorHex);
|
|
708
|
+
out.push("BT");
|
|
709
|
+
out.push(`/${first.font.resourceName} ${formatNumber(first.fontSizePt)} Tf`);
|
|
710
|
+
out.push(`${formatNumber(r)} ${formatNumber(g)} ${formatNumber(bl)} rg`);
|
|
711
|
+
out.push(`1 0 0 1 ${formatNumber(ox + t.x)} ${formatNumber(oy + t.y)} Tm`);
|
|
712
|
+
out.push(first.font.measure.showText(first.text));
|
|
713
|
+
out.push("ET");
|
|
714
|
+
}
|
|
715
|
+
lastFont = "";
|
|
716
|
+
lastSize = -1;
|
|
717
|
+
lastColor = "";
|
|
718
|
+
return;
|
|
719
|
+
}
|
|
646
720
|
if (!tok.imageResourceName) return;
|
|
647
721
|
if (inBT) {
|
|
648
722
|
out.push("ET");
|
|
@@ -672,6 +746,7 @@ function emitPageContent(page, tagging, gradientNames, alphaStateNames) {
|
|
|
672
746
|
const b = tok.drawBox;
|
|
673
747
|
out.push(...b ? placeImage(x + b.dxPt, baselineY + b.dyPt, b.widthPt, b.heightPt, tok.crop, tok.rotationDeg, tok.flipH, tok.flipV) : placeImage(x, baselineY, tok.widthPt, tok.heightPt, tok.crop, tok.rotationDeg, tok.flipH, tok.flipV));
|
|
674
748
|
out.push(`/${tok.imageResourceName} Do`);
|
|
749
|
+
out.push(...washItems(tok.wash, alphaStateNames));
|
|
675
750
|
out.push("Q");
|
|
676
751
|
const frame = tok.outline;
|
|
677
752
|
if (frame) {
|
|
@@ -31,7 +31,7 @@ export declare function shadowBlurLayers(shadow: {
|
|
|
31
31
|
count: number;
|
|
32
32
|
alpha: number;
|
|
33
33
|
};
|
|
34
|
-
export declare function emitVectorShape(shape: VectorShape, patternName?: string, alphaStateName?: string): Array<string>;
|
|
34
|
+
export declare function emitVectorShape(shape: VectorShape, patternName?: string, alphaStateName?: string, fillAlphaStateName?: string): Array<string>;
|
|
35
35
|
/**
|
|
36
36
|
* The operators that make `paths` the current CLIP, under `transform` — the
|
|
37
37
|
* same local→y-up-page matrix {@link emitVectorShape} takes. Emitted inside the
|
|
@@ -53,7 +53,7 @@ function shadowBbox(shape) {
|
|
|
53
53
|
maxY
|
|
54
54
|
} : void 0;
|
|
55
55
|
}
|
|
56
|
-
function emitVectorShape(shape, patternName, alphaStateName) {
|
|
56
|
+
function emitVectorShape(shape, patternName, alphaStateName, fillAlphaStateName) {
|
|
57
57
|
const out = [];
|
|
58
58
|
const [a, b, c, d, e, f] = shape.transform;
|
|
59
59
|
const shadow = shape.shadow;
|
|
@@ -88,6 +88,7 @@ function emitVectorShape(shape, patternName, alphaStateName) {
|
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
90
|
out.push("q");
|
|
91
|
+
if (fillAlphaStateName !== void 0) out.push(`/${fillAlphaStateName} gs`);
|
|
91
92
|
out.push(`${num(a)} ${num(b)} ${num(c)} ${num(d)} ${num(e)} ${num(f)} cm`);
|
|
92
93
|
const stroke = shape.stroke;
|
|
93
94
|
if (stroke) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { PDF_NULL, PdfHexString, PdfName, PdfStream } from "../pdf/objects.js";
|
|
2
|
+
import { lzwDecodeMsb } from "../core/lzw.js";
|
|
2
3
|
import { reversePredictor } from "./predictor.js";
|
|
3
4
|
import { decodeCcitt } from "./ccitt.js";
|
|
4
5
|
import { encodePng } from "./png-encode.js";
|
|
@@ -342,9 +343,7 @@ function decodeChain(file, stream, filters) {
|
|
|
342
343
|
return;
|
|
343
344
|
}
|
|
344
345
|
else if (f === "LZWDecode" || f === "LZW") {
|
|
345
|
-
|
|
346
|
-
if (!dec) return void 0;
|
|
347
|
-
data = dec;
|
|
346
|
+
data = lzwDecode(data, lzwEarlyChange(file, stream.dict));
|
|
348
347
|
mayPredict = true;
|
|
349
348
|
} else if (f === "RunLengthDecode" || f === "RL") data = runLengthDecode(data);
|
|
350
349
|
else if (f === "ASCII85Decode" || f === "A85") data = ascii85Decode(data);
|
|
@@ -359,7 +358,7 @@ function applyChainExceptLast(filters, raw) {
|
|
|
359
358
|
if (f === "FlateDecode" || f === "Fl") try {
|
|
360
359
|
data = unzlibSync(data);
|
|
361
360
|
} catch {}
|
|
362
|
-
else if (f === "LZWDecode" || f === "LZW") data = lzwDecode(data, 1)
|
|
361
|
+
else if (f === "LZWDecode" || f === "LZW") data = lzwDecode(data, 1);
|
|
363
362
|
else if (f === "RunLengthDecode" || f === "RL") data = runLengthDecode(data);
|
|
364
363
|
else if (f === "ASCII85Decode" || f === "A85") data = ascii85Decode(data);
|
|
365
364
|
else if (f === "ASCIIHexDecode" || f === "AHx") data = asciiHexDecode(data);
|
|
@@ -380,77 +379,10 @@ function applyPredictor(file, d, data) {
|
|
|
380
379
|
}
|
|
381
380
|
var MAX_LZW_OUT = MAX_PIXELS * 4;
|
|
382
381
|
function lzwDecode(data, earlyChange) {
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
if (outLen + e.length > out.length) {
|
|
388
|
-
let cap = out.length * 2;
|
|
389
|
-
while (cap < outLen + e.length) cap *= 2;
|
|
390
|
-
const grown = new Uint8Array(cap);
|
|
391
|
-
grown.set(out.subarray(0, outLen));
|
|
392
|
-
out = grown;
|
|
393
|
-
}
|
|
394
|
-
out.set(e, outLen);
|
|
395
|
-
outLen += e.length;
|
|
396
|
-
return true;
|
|
397
|
-
};
|
|
398
|
-
let bitBuffer = 0;
|
|
399
|
-
let bitCount = 0;
|
|
400
|
-
let pos = 0;
|
|
401
|
-
let codeLength = 9;
|
|
402
|
-
const readCode = () => {
|
|
403
|
-
while (bitCount < codeLength) {
|
|
404
|
-
if (pos >= data.length) return -1;
|
|
405
|
-
bitBuffer = (bitBuffer << 8 | data[pos++]) >>> 0;
|
|
406
|
-
bitCount += 8;
|
|
407
|
-
}
|
|
408
|
-
bitCount -= codeLength;
|
|
409
|
-
return bitBuffer >>> bitCount & (1 << codeLength) - 1;
|
|
410
|
-
};
|
|
411
|
-
const dict = new Array(4096);
|
|
412
|
-
let nextCode = 258;
|
|
413
|
-
let prev = -1;
|
|
414
|
-
const reset = () => {
|
|
415
|
-
for (let i = 0; i < 256; i++) dict[i] = Uint8Array.of(i);
|
|
416
|
-
nextCode = 258;
|
|
417
|
-
codeLength = 9;
|
|
418
|
-
prev = -1;
|
|
419
|
-
};
|
|
420
|
-
reset();
|
|
421
|
-
for (;;) {
|
|
422
|
-
const code = readCode();
|
|
423
|
-
if (code < 0 || code === 257) break;
|
|
424
|
-
if (code === 256) {
|
|
425
|
-
reset();
|
|
426
|
-
continue;
|
|
427
|
-
}
|
|
428
|
-
if (prev < 0) {
|
|
429
|
-
const first = dict[code];
|
|
430
|
-
if (!first || !emit(first)) break;
|
|
431
|
-
prev = code;
|
|
432
|
-
continue;
|
|
433
|
-
}
|
|
434
|
-
const prevEntry = dict[prev];
|
|
435
|
-
let entry = code < nextCode ? dict[code] : void 0;
|
|
436
|
-
if (!entry) {
|
|
437
|
-
entry = new Uint8Array(prevEntry.length + 1);
|
|
438
|
-
entry.set(prevEntry);
|
|
439
|
-
entry[prevEntry.length] = prevEntry[0];
|
|
440
|
-
}
|
|
441
|
-
if (!emit(entry)) break;
|
|
442
|
-
if (nextCode < 4096) {
|
|
443
|
-
const added = new Uint8Array(prevEntry.length + 1);
|
|
444
|
-
added.set(prevEntry);
|
|
445
|
-
added[prevEntry.length] = entry[0];
|
|
446
|
-
dict[nextCode++] = added;
|
|
447
|
-
if (nextCode + earlyChange === 512) codeLength = 10;
|
|
448
|
-
else if (nextCode + earlyChange === 1024) codeLength = 11;
|
|
449
|
-
else if (nextCode + earlyChange === 2048) codeLength = 12;
|
|
450
|
-
}
|
|
451
|
-
prev = code;
|
|
452
|
-
}
|
|
453
|
-
return out.subarray(0, outLen);
|
|
382
|
+
return lzwDecodeMsb(data, {
|
|
383
|
+
earlyChange,
|
|
384
|
+
limit: MAX_LZW_OUT
|
|
385
|
+
});
|
|
454
386
|
}
|
|
455
387
|
function lzwEarlyChange(file, d) {
|
|
456
388
|
const ec = decodeParmsOf(file, d)?.get("EarlyChange");
|
|
@@ -156,7 +156,7 @@ function imageHref(resourceName, laid) {
|
|
|
156
156
|
for (const [resourceId, res] of laid.imageResources) {
|
|
157
157
|
if (res.resourceName !== resourceName) continue;
|
|
158
158
|
const bytes = laid.resources.get(resourceId);
|
|
159
|
-
if (!bytes) return void 0;
|
|
159
|
+
if (!bytes || !res.prepared) return void 0;
|
|
160
160
|
return `data:${res.prepared.mimeType};base64,${toBase64(bytes)}`;
|
|
161
161
|
}
|
|
162
162
|
}
|
|
@@ -457,6 +457,7 @@ function blocksForDrawing(content, paragraphProperties, ctx) {
|
|
|
457
457
|
...resource ? { resource } : {},
|
|
458
458
|
...content.outline ? { outline: content.outline } : {},
|
|
459
459
|
...content.shadow ? { shadow: content.shadow } : {},
|
|
460
|
+
...content.wash ? { wash: content.wash } : {},
|
|
460
461
|
width: content.width,
|
|
461
462
|
height: content.height,
|
|
462
463
|
...content.crop ? { crop: content.crop } : {},
|
|
@@ -935,6 +936,7 @@ function parseRun(r, ctx, anchored) {
|
|
|
935
936
|
...resource ? { resource } : {},
|
|
936
937
|
...content.outline ? { outline: content.outline } : {},
|
|
937
938
|
...content.shadow ? { shadow: content.shadow } : {},
|
|
939
|
+
...content.wash ? { wash: content.wash } : {},
|
|
938
940
|
width: content.width,
|
|
939
941
|
height: content.height,
|
|
940
942
|
...content.crop ? { crop: content.crop } : {},
|
|
@@ -953,6 +955,7 @@ function parseRun(r, ctx, anchored) {
|
|
|
953
955
|
resource,
|
|
954
956
|
...content.outline ? { outline: content.outline } : {},
|
|
955
957
|
...content.shadow ? { shadow: content.shadow } : {},
|
|
958
|
+
...content.wash ? { wash: content.wash } : {},
|
|
956
959
|
width: content.width,
|
|
957
960
|
height: content.height
|
|
958
961
|
};
|
|
@@ -57,6 +57,11 @@ export type DrawingContent = {
|
|
|
57
57
|
readonly outline?: PictureOutline;
|
|
58
58
|
/** §20.1.8.40 `a:outerShdw` on the same `pic:spPr` — the picture's shadow. */
|
|
59
59
|
readonly shadow?: ShapeShadow;
|
|
60
|
+
/** §14.1.2.10 `@gain`/`@blacklevel` — the wash the picture is drawn through. */
|
|
61
|
+
readonly wash?: {
|
|
62
|
+
readonly gain: number;
|
|
63
|
+
readonly black: number;
|
|
64
|
+
};
|
|
60
65
|
/** §20.1.8.55 `a:srcRect` — the part of the source the frame shows. */
|
|
61
66
|
readonly crop?: ImageCrop;
|
|
62
67
|
/** §20.1.7.6 `a:xfrm @rot` — the picture's rotation (1/60000°, clockwise). */
|
|
@@ -25,10 +25,16 @@ function parseFloatAnchor(anchor) {
|
|
|
25
25
|
const behindRaw = poAttr(anchor, "behindDoc");
|
|
26
26
|
const behind = behindRaw === "1" || behindRaw === "true";
|
|
27
27
|
let wrap = "none";
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
28
|
+
let wrapSide;
|
|
29
|
+
for (const child of poChildren(anchor)) {
|
|
30
|
+
if (poIs(child, "wp:wrapSquare")) wrap = "square";
|
|
31
|
+
else if (poIs(child, "wp:wrapTight")) wrap = "tight";
|
|
32
|
+
else if (poIs(child, "wp:wrapThrough")) wrap = "through";
|
|
33
|
+
else if (poIs(child, "wp:wrapTopAndBottom")) wrap = "topAndBottom";
|
|
34
|
+
else continue;
|
|
35
|
+
const side = poAttr(child, "wrapText");
|
|
36
|
+
wrapSide = side === "left" || side === "right" || side === "largest" ? side : "bothSides";
|
|
37
|
+
}
|
|
32
38
|
const zOrder = poIntAttr(anchor, "relativeHeight");
|
|
33
39
|
const posH = parseAnchorPos(anchor, "wp:positionH", [
|
|
34
40
|
"margin",
|
|
@@ -53,8 +59,12 @@ function parseFloatAnchor(anchor) {
|
|
|
53
59
|
rightPt: dist("distR")
|
|
54
60
|
};
|
|
55
61
|
const anyDist = Object.values(wrapDist).some((v) => v > 0);
|
|
62
|
+
const inCellRaw = poAttr(anchor, "layoutInCell");
|
|
63
|
+
const inCell = !(inCellRaw === "0" || inCellRaw === "false");
|
|
56
64
|
return {
|
|
57
65
|
wrap,
|
|
66
|
+
...wrapSide ? { wrapSide } : {},
|
|
67
|
+
...inCell ? {} : { inCell: false },
|
|
58
68
|
...behind ? { behind: true } : {},
|
|
59
69
|
...zOrder !== void 0 ? { zOrder } : {},
|
|
60
70
|
...anyDist ? { wrapDist } : {},
|
|
@@ -355,12 +365,14 @@ function parseVmlPicture(node, parseBody) {
|
|
|
355
365
|
const shapeType = typeRef !== void 0 ? vmlShapeTypes(node).get(typeRef) : void 0;
|
|
356
366
|
const stroked = shape ? poAttr(shape, "stroked") ?? (shapeType ? poAttr(shapeType, "stroked") : void 0) : void 0;
|
|
357
367
|
const outline = shape && (stroked === "t" || stroked === "true") ? pictureOutline(vmlLine(shape, shapeType)) : void 0;
|
|
368
|
+
const wash = vmlWash(imagedata);
|
|
358
369
|
return {
|
|
359
370
|
kind: "image",
|
|
360
371
|
imageId,
|
|
361
372
|
width,
|
|
362
373
|
height,
|
|
363
374
|
...outline ? { outline } : {},
|
|
375
|
+
...wash ? { wash } : {},
|
|
364
376
|
...float ? { float } : {},
|
|
365
377
|
...altText ? { altText } : {}
|
|
366
378
|
};
|
|
@@ -404,13 +416,29 @@ function parseVmlShape(node, parseBody) {
|
|
|
404
416
|
const data = vmlShapeData(shape, tag, pt(Math.max(1, boxW)), pt(Math.max(1, boxH)), parseBody, vmlShapeTypes(node));
|
|
405
417
|
if (!data) return null;
|
|
406
418
|
const float = vmlFloat(style, poIntAttr(shape, "z-index"), shape);
|
|
419
|
+
const placed = float && from && to ? vmlLinePlaced(float, from, to) : float;
|
|
407
420
|
return {
|
|
408
421
|
kind: "shape",
|
|
409
422
|
data,
|
|
410
|
-
...
|
|
423
|
+
...placed ? { float: placed } : {},
|
|
411
424
|
...poAttr(shape, "alt")?.trim() ? { altText: poAttr(shape, "alt").trim() } : {}
|
|
412
425
|
};
|
|
413
426
|
}
|
|
427
|
+
function vmlLinePlaced(float, from, to) {
|
|
428
|
+
const x = Math.min(from.x, to.x);
|
|
429
|
+
const y = Math.min(from.y, to.y);
|
|
430
|
+
return {
|
|
431
|
+
...float,
|
|
432
|
+
...float.posH?.align === void 0 ? { posH: {
|
|
433
|
+
...float.posH ?? { relativeFrom: "column" },
|
|
434
|
+
offsetPt: pt(x)
|
|
435
|
+
} } : {},
|
|
436
|
+
...float.posV?.align === void 0 ? { posV: {
|
|
437
|
+
...float.posV ?? { relativeFrom: "paragraph" },
|
|
438
|
+
offsetPt: pt(y)
|
|
439
|
+
} } : {}
|
|
440
|
+
};
|
|
441
|
+
}
|
|
414
442
|
/**
|
|
415
443
|
* One VML primitive as {@link ShapeData}: its preset geometry, fill, outline
|
|
416
444
|
* and the words in its text box.
|
|
@@ -821,9 +849,11 @@ function vmlFill(shape, shapeType, resolveImage) {
|
|
|
821
849
|
kind: "gradient",
|
|
822
850
|
gradient
|
|
823
851
|
};
|
|
852
|
+
const opacity = vmlOpacity(poAttr(shape, "opacity") ?? (fillEl ? poAttr(fillEl, "opacity") : void 0));
|
|
824
853
|
return {
|
|
825
854
|
kind: "solid",
|
|
826
|
-
colorHex: base
|
|
855
|
+
colorHex: base,
|
|
856
|
+
...opacity !== void 0 ? { alpha: opacity } : {}
|
|
827
857
|
};
|
|
828
858
|
}
|
|
829
859
|
function vmlGradient(fillEl, base) {
|
|
@@ -878,6 +908,33 @@ function vmlFocusStops(raw, base, color2) {
|
|
|
878
908
|
}
|
|
879
909
|
];
|
|
880
910
|
}
|
|
911
|
+
function vmlWash(imagedata) {
|
|
912
|
+
const gain = vmlFraction(poAttr(imagedata, "gain"));
|
|
913
|
+
const black = vmlFraction(poAttr(imagedata, "blacklevel"));
|
|
914
|
+
if (gain === void 0 && black === void 0) return void 0;
|
|
915
|
+
const g = Math.max(0, gain ?? 1);
|
|
916
|
+
const b = black ?? 0;
|
|
917
|
+
return Math.abs(g - 1) < .01 && Math.abs(b) < .01 ? void 0 : {
|
|
918
|
+
gain: g,
|
|
919
|
+
black: b
|
|
920
|
+
};
|
|
921
|
+
}
|
|
922
|
+
function vmlFraction(raw) {
|
|
923
|
+
if (raw === void 0 || raw.trim() === "") return void 0;
|
|
924
|
+
const t = raw.trim();
|
|
925
|
+
const pct = t.endsWith("%");
|
|
926
|
+
const n = Number.parseFloat(pct ? t.slice(0, -1) : t.replace(/f$/iu, ""));
|
|
927
|
+
if (!Number.isFinite(n)) return void 0;
|
|
928
|
+
return pct ? n / 100 : Math.abs(n) > 1 ? n / 65536 : n;
|
|
929
|
+
}
|
|
930
|
+
function vmlOpacity(raw) {
|
|
931
|
+
if (raw === void 0 || raw.trim() === "") return void 0;
|
|
932
|
+
const pct = raw.trim().endsWith("%");
|
|
933
|
+
const n = Number.parseFloat(pct ? raw.trim().slice(0, -1) : raw.replace(/f$/iu, ""));
|
|
934
|
+
if (!Number.isFinite(n)) return void 0;
|
|
935
|
+
const v = pct ? n / 100 : n > 1 ? n / 65536 : n;
|
|
936
|
+
return v >= 1 ? void 0 : Math.max(0, v);
|
|
937
|
+
}
|
|
881
938
|
function vmlStops(raw) {
|
|
882
939
|
if (raw === void 0 || raw.trim() === "") return void 0;
|
|
883
940
|
const stops = [];
|
|
@@ -1020,6 +1077,7 @@ function vmlFloat(style, zIndexAttr, shape) {
|
|
|
1020
1077
|
const zIndex = prop("z-index") ?? zIndexAttr;
|
|
1021
1078
|
return {
|
|
1022
1079
|
wrap: vmlWrap(shape),
|
|
1080
|
+
...poAttrLocal(shape, "allowincell") === "f" ? { inCell: false } : {},
|
|
1023
1081
|
...zIndex !== void 0 && zIndex < 0 ? { behind: true } : {},
|
|
1024
1082
|
...zIndex !== void 0 ? { zOrder: Math.abs(zIndex) } : {},
|
|
1025
1083
|
posH: {
|
|
@@ -1530,11 +1588,17 @@ function withStyleFontColor(text, style, resolveColor) {
|
|
|
1530
1588
|
}
|
|
1531
1589
|
function parseTextBox(wsp, parseBody) {
|
|
1532
1590
|
const txbx = poChildren(wsp).find((c) => poIs(c, "wps:txbx"));
|
|
1533
|
-
|
|
1534
|
-
const
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1591
|
+
const linked = poChildren(wsp).find((c) => poIs(c, "wps:linkedTxbx"));
|
|
1592
|
+
const chainId = poAttr(txbx, "id") ?? poAttr(linked, "id");
|
|
1593
|
+
const chain = chainId === void 0 ? void 0 : {
|
|
1594
|
+
id: chainId,
|
|
1595
|
+
seq: linked ? poIntAttr(linked, "seq") ?? 1 : 0
|
|
1596
|
+
};
|
|
1597
|
+
if (!txbx && !linked) return void 0;
|
|
1598
|
+
const txContent = txbx ? poChildren(txbx).find((c) => poIs(c, "w:txbxContent")) : void 0;
|
|
1599
|
+
if (txbx && !txContent) return void 0;
|
|
1600
|
+
const content = txContent ? parseBody(poChildren(txContent)) : [];
|
|
1601
|
+
if (content.length === 0 && !linked) return void 0;
|
|
1538
1602
|
const bodyPr = poChildren(wsp).find((c) => poIs(c, "wps:bodyPr"));
|
|
1539
1603
|
const lIns = bodyPr ? poIntAttr(bodyPr, "lIns") : void 0;
|
|
1540
1604
|
const tIns = bodyPr ? poIntAttr(bodyPr, "tIns") : void 0;
|
|
@@ -1547,6 +1611,7 @@ function parseTextBox(wsp, parseBody) {
|
|
|
1547
1611
|
const autoFit = bodyPr !== void 0 && poChildren(bodyPr).some((c) => poIs(c, "a:spAutoFit"));
|
|
1548
1612
|
return {
|
|
1549
1613
|
content,
|
|
1614
|
+
...chain ? { chain } : {},
|
|
1550
1615
|
...vertical ? { vertical } : {},
|
|
1551
1616
|
...autoFit ? { autoFit: true } : {},
|
|
1552
1617
|
...lIns !== void 0 ? { insetLeft: emuToPt(lIns) } : {},
|
|
@@ -1742,9 +1807,11 @@ function fillFromNode(child, resolveColor, resolveImage) {
|
|
|
1742
1807
|
}
|
|
1743
1808
|
if (poIs(child, "a:solidFill")) {
|
|
1744
1809
|
const hex = colorFromContainer(child, resolveColor);
|
|
1810
|
+
const alpha = containerAlpha(child);
|
|
1745
1811
|
return hex ? {
|
|
1746
1812
|
kind: "solid",
|
|
1747
|
-
colorHex: hex
|
|
1813
|
+
colorHex: alpha === void 0 ? hex : unblendWhite(hex, alpha),
|
|
1814
|
+
...alpha !== void 0 ? { alpha } : {}
|
|
1748
1815
|
} : { kind: "none" };
|
|
1749
1816
|
}
|
|
1750
1817
|
if (poIs(child, "a:pattFill")) {
|
|
@@ -1997,6 +2064,22 @@ function normalizeDash(v) {
|
|
|
1997
2064
|
if (v === "lgDashDotDot") return "lgDashDot";
|
|
1998
2065
|
if (v === "sysDashDot" || v === "sysDashDotDot") return "sysDash";
|
|
1999
2066
|
}
|
|
2067
|
+
function unblendWhite(hex, alpha) {
|
|
2068
|
+
if (alpha <= .004) return hex;
|
|
2069
|
+
const n = parseInt(hex, 16);
|
|
2070
|
+
if (Number.isNaN(n)) return hex;
|
|
2071
|
+
const ch = (shift) => {
|
|
2072
|
+
const raw = ((n >> shift & 255) / 255 - (1 - alpha)) / alpha;
|
|
2073
|
+
return Math.round(Math.max(0, Math.min(1, raw)) * 255).toString(16).padStart(2, "0");
|
|
2074
|
+
};
|
|
2075
|
+
return (ch(16) + ch(8) + ch(0)).toUpperCase();
|
|
2076
|
+
}
|
|
2077
|
+
function containerAlpha(parent) {
|
|
2078
|
+
for (const c of poChildren(parent)) {
|
|
2079
|
+
const mod = readColorMods(c).find((m) => m.kind === "alpha");
|
|
2080
|
+
if (mod) return Math.max(0, Math.min(1, mod.val));
|
|
2081
|
+
}
|
|
2082
|
+
}
|
|
2000
2083
|
function colorFromContainer(parent, resolveColor) {
|
|
2001
2084
|
for (const c of poChildren(parent)) {
|
|
2002
2085
|
const hex = resolveColorNode(c, resolveColor);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "reamkit",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.18.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>",
|