reamkit 1.5.0 → 1.7.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.
Files changed (58) hide show
  1. package/README.md +2 -2
  2. package/dist/esm/core/converter/facade.js +6 -1
  3. package/dist/esm/core/converter/ream.js +2 -1
  4. package/dist/esm/core/document-model/types.d.ts +9 -1
  5. package/dist/esm/core/drawingml/chart-serializer.d.ts +2 -0
  6. package/dist/esm/core/drawingml/chart-serializer.js +53 -0
  7. package/dist/esm/core/spreadsheet-model/index.d.ts +1 -1
  8. package/dist/esm/core/spreadsheet-model/types.d.ts +5 -0
  9. package/dist/esm/excel/column-bands.d.ts +7 -0
  10. package/dist/esm/excel/column-bands.js +87 -0
  11. package/dist/esm/excel/conditional-format.js +22 -0
  12. package/dist/esm/excel/print-model.js +33 -11
  13. package/dist/esm/excel/worksheet-parser.js +26 -0
  14. package/dist/esm/excel/xlsx-writer.js +88 -17
  15. package/dist/esm/html/html-writer.js +100 -5
  16. package/dist/esm/layout/styled-layout.js +88 -19
  17. package/dist/esm/pdf-reader/cmap.d.ts +5 -0
  18. package/dist/esm/pdf-reader/cmap.js +72 -0
  19. package/dist/esm/pdf-reader/content.d.ts +52 -0
  20. package/dist/esm/pdf-reader/content.js +420 -0
  21. package/dist/esm/pdf-reader/crypto.d.ts +7 -0
  22. package/dist/esm/pdf-reader/crypto.js +609 -0
  23. package/dist/esm/pdf-reader/decrypt.d.ts +5 -0
  24. package/dist/esm/pdf-reader/decrypt.js +199 -0
  25. package/dist/esm/pdf-reader/document.d.ts +30 -0
  26. package/dist/esm/pdf-reader/document.js +413 -0
  27. package/dist/esm/pdf-reader/flow-build.d.ts +19 -0
  28. package/dist/esm/pdf-reader/flow-build.js +126 -0
  29. package/dist/esm/pdf-reader/font.d.ts +4 -0
  30. package/dist/esm/pdf-reader/font.js +69 -0
  31. package/dist/esm/pdf-reader/image-decode.d.ts +15 -0
  32. package/dist/esm/pdf-reader/image-decode.js +442 -0
  33. package/dist/esm/pdf-reader/images.d.ts +16 -0
  34. package/dist/esm/pdf-reader/images.js +90 -0
  35. package/dist/esm/pdf-reader/layout.d.ts +3 -0
  36. package/dist/esm/pdf-reader/layout.js +103 -0
  37. package/dist/esm/pdf-reader/lexer.d.ts +43 -0
  38. package/dist/esm/pdf-reader/lexer.js +250 -0
  39. package/dist/esm/pdf-reader/parser.d.ts +10 -0
  40. package/dist/esm/pdf-reader/parser.js +86 -0
  41. package/dist/esm/pdf-reader/png-encode.d.ts +2 -0
  42. package/dist/esm/pdf-reader/png-encode.js +98 -0
  43. package/dist/esm/pdf-reader/predictor.d.ts +7 -0
  44. package/dist/esm/pdf-reader/predictor.js +61 -0
  45. package/dist/esm/pdf-reader/reader.d.ts +4 -0
  46. package/dist/esm/pdf-reader/reader.js +50 -0
  47. package/dist/esm/pdf-reader/struct-tree.d.ts +14 -0
  48. package/dist/esm/pdf-reader/struct-tree.js +92 -0
  49. package/dist/esm/pdf-reader/tagged.d.ts +3 -0
  50. package/dist/esm/pdf-reader/tagged.js +141 -0
  51. package/dist/esm/pdf-reader/text.d.ts +3 -0
  52. package/dist/esm/pdf-reader/text.js +65 -0
  53. package/dist/esm/pdf-reader/vector.d.ts +12 -0
  54. package/dist/esm/pdf-reader/vector.js +54 -0
  55. package/dist/esm/word/docx-writer.js +96 -7
  56. package/dist/esm/word/omml-serializer.d.ts +2 -0
  57. package/dist/esm/word/omml-serializer.js +48 -0
  58. package/package.json +2 -2
@@ -356,6 +356,21 @@ function emitTable(out, table, ctx) {
356
356
  return start;
357
357
  });
358
358
  });
359
+ const frozen = table.properties.frozen;
360
+ const leftOffsets = [];
361
+ const topOffsets = [];
362
+ if (frozen) {
363
+ let left = 0;
364
+ for (const w of table.grid) {
365
+ leftOffsets.push(left);
366
+ left += w;
367
+ }
368
+ let top = 0;
369
+ for (const row of table.rows) {
370
+ topOffsets.push(top);
371
+ top += row.properties.height ?? 15;
372
+ }
373
+ }
359
374
  for (let ri = 0; ri < table.rows.length; ri++) {
360
375
  const row = table.rows[ri];
361
376
  out.push("<tr>");
@@ -363,14 +378,17 @@ function emitTable(out, table, ctx) {
363
378
  const cell = row.cells[ci];
364
379
  const merge = cell.properties.merge;
365
380
  if (merge === "middle" || merge === "end") continue;
366
- const rowSpan = merge === "start" ? mergeRowSpan(table, colStarts, ri, colStarts[ri][ci]) : 1;
381
+ const cs = colStarts[ri][ci];
382
+ const rowSpan = merge === "start" ? mergeRowSpan(table, colStarts, ri, cs) : 1;
367
383
  emitCell(out, cell, table, ctx, {
368
384
  isHeader: row.properties.isHeader === true,
369
385
  firstRow: ri === 0,
370
386
  lastRow: ri === table.rows.length - 1,
371
- firstCol: colStarts[ri][ci] === 0,
372
- lastCol: colStarts[ri][ci] + (cell.properties.colSpan ?? 1) >= table.grid.length,
373
- rowSpan
387
+ firstCol: cs === 0,
388
+ lastCol: cs + (cell.properties.colSpan ?? 1) >= table.grid.length,
389
+ rowSpan,
390
+ ...frozen && ri < frozen.rows ? { stickyTop: topOffsets[ri] } : {},
391
+ ...frozen && cs < frozen.cols ? { stickyLeft: leftOffsets[cs] } : {}
374
392
  });
375
393
  }
376
394
  out.push("</tr>");
@@ -417,6 +435,14 @@ function emitCell(out, cell, table, ctx, pos) {
417
435
  const padBottom = margins?.bottom ?? 0;
418
436
  const padLeft = margins?.left ?? 5.4;
419
437
  css.push(`padding:${fmt(padTop)}pt ${fmt(padRight)}pt ${fmt(padBottom)}pt ${fmt(padLeft)}pt`);
438
+ if (pos.stickyTop !== void 0 || pos.stickyLeft !== void 0) {
439
+ css.push("position:sticky");
440
+ if (pos.stickyTop !== void 0) css.push(`top:${fmt(pos.stickyTop)}pt`);
441
+ if (pos.stickyLeft !== void 0) css.push(`left:${fmt(pos.stickyLeft)}pt`);
442
+ const z = pos.stickyTop !== void 0 && pos.stickyLeft !== void 0 ? 3 : pos.stickyTop !== void 0 ? 2 : 1;
443
+ css.push(`z-index:${z}`);
444
+ if (!cell.properties.shading) css.push("background-color:#fff");
445
+ }
420
446
  out.push(`<${tag}${attrs.length > 0 ? ` ${attrs.join(" ")}` : ""} style="${css.join(";")}">`);
421
447
  if (cell.properties.icon) out.push(cellIconSvg(cell.properties.icon));
422
448
  if (cell.properties.sparkline) out.push(cellSparklineSvg(cell.properties.sparkline));
@@ -436,8 +462,77 @@ function cellSparklineSvg(sp) {
436
462
  }
437
463
  return `<svg width="${W}" height="${H}" viewBox="0 0 ${W} ${H}" style="vertical-align:middle"><g transform="translate(0,${H}) scale(1,-1)">${parts.join("")}</g></svg>`;
438
464
  }
465
+ var ICON_EMPTY_HEX = "BFBFBF";
439
466
  function cellIconSvg(icon) {
440
- return `<svg width="10" height="10" viewBox="0 0 10 10" fill="${`#${icon.colorHex}`}" style="vertical-align:middle;margin-right:3px">${icon.shape === "square" ? `<rect x="1" y="1" width="8" height="8"/>` : icon.shape === "diamond" ? `<polygon points="5,1 9,5 5,9 1,5"/>` : icon.shape === "triangleUp" ? `<polygon points="5,1 9,9 1,9"/>` : icon.shape === "triangleDown" ? `<polygon points="1,1 9,1 5,9"/>` : icon.shape === "triangleRight" ? `<polygon points="9,5 1,1 1,9"/>` : `<circle cx="5" cy="5" r="4"/>`}</svg>`;
467
+ const fill = `#${icon.colorHex}`;
468
+ let body;
469
+ switch (icon.shape) {
470
+ case "square":
471
+ body = `<rect x="1" y="1" width="8" height="8" fill="${fill}"/>`;
472
+ break;
473
+ case "diamond":
474
+ body = `<polygon points="5,1 9,5 5,9 1,5" fill="${fill}"/>`;
475
+ break;
476
+ case "triangleUp":
477
+ body = `<polygon points="5,1 9,9 1,9" fill="${fill}"/>`;
478
+ break;
479
+ case "triangleDown":
480
+ body = `<polygon points="1,1 9,1 5,9" fill="${fill}"/>`;
481
+ break;
482
+ case "triangleRight":
483
+ body = `<polygon points="9,5 1,1 1,9" fill="${fill}"/>`;
484
+ break;
485
+ case "check":
486
+ body = `<polyline points="1.6,5 4,7.4 8.4,2.6" fill="none" stroke="${fill}" stroke-width="1.6"/>`;
487
+ break;
488
+ case "cross":
489
+ body = `<path d="M2.4 2.4 L7.6 7.6 M2.4 7.6 L7.6 2.4" fill="none" stroke="${fill}" stroke-width="1.6"/>`;
490
+ break;
491
+ case "exclamation":
492
+ body = `<rect x="4.1" y="1" width="1.8" height="5.6" fill="${fill}"/><rect x="4.1" y="7.4" width="1.8" height="1.6" fill="${fill}"/>`;
493
+ break;
494
+ case "bars":
495
+ body = barsIconSvg(icon.fill, fill, `#${ICON_EMPTY_HEX}`);
496
+ break;
497
+ case "pie":
498
+ body = pieIconSvg(icon.fill, fill, `#${ICON_EMPTY_HEX}`);
499
+ break;
500
+ case "circle":
501
+ body = `<circle cx="5" cy="5" r="4" fill="${fill}"/>`;
502
+ break;
503
+ }
504
+ return `<svg width="10" height="10" viewBox="0 0 10 10" style="vertical-align:middle;margin-right:3px">${body}</svg>`;
505
+ }
506
+ var round2 = (n) => (Math.round(n * 100) / 100).toString();
507
+ function barsIconSvg(fill, color, empty) {
508
+ const n = Math.max(1, fill?.levels ?? 4);
509
+ const filled = fill?.filled ?? 0;
510
+ const gap = 10 * .12;
511
+ const bw = (10 - gap * (n - 1)) / n;
512
+ let out = "";
513
+ for (let i = 0; i < n; i++) {
514
+ const h = 10 * (.32 + .68 * (i + 1) / n);
515
+ out += `<rect x="${round2(i * (bw + gap))}" y="${round2(10 - h)}" width="${round2(bw)}" height="${round2(h)}" fill="${i < filled ? color : empty}"/>`;
516
+ }
517
+ return out;
518
+ }
519
+ function pieIconSvg(fill, color, empty) {
520
+ const cx = 5;
521
+ const cy = 5;
522
+ const r = 4.4;
523
+ const levels = Math.max(1, fill?.levels ?? 4);
524
+ const filled = Math.max(0, Math.min(levels, fill?.filled ?? 0));
525
+ let out = `<circle cx="${cx}" cy="${cy}" r="${r}" fill="${empty}"/>`;
526
+ if (filled >= levels) out += `<circle cx="${cx}" cy="${cy}" r="${r}" fill="${color}"/>`;
527
+ else if (filled > 0) {
528
+ const frac = filled / levels;
529
+ const ang = -Math.PI / 2 + frac * 2 * Math.PI;
530
+ const ex = cx + r * Math.cos(ang);
531
+ const ey = cy + r * Math.sin(ang);
532
+ const large = frac > .5 ? 1 : 0;
533
+ out += `<path d="M${cx} ${cy} L${cx} ${round2(cy - r)} A${r} ${r} 0 ${large} 1 ${round2(ex)} ${round2(ey)} Z" fill="${color}"/>`;
534
+ }
535
+ return out;
441
536
  }
442
537
  function pushBorder(css, side, border) {
443
538
  if (!border || border.style === "none") return;
@@ -563,11 +563,35 @@ function rectAtPath(x, y, w, h) {
563
563
  }
564
564
  var CF_ICON_SIZE_PT = 9;
565
565
  var CF_ICON_GUTTER_PT = 12;
566
- function buildCellIconShape(icon, size) {
567
- return {
568
- paths: [cellIconPath(icon.shape, size)],
569
- fillColorHex: icon.colorHex
570
- };
566
+ var CF_ICON_EMPTY_HEX = "BFBFBF";
567
+ function buildCellIconShape(icon, s) {
568
+ const color = icon.colorHex;
569
+ switch (icon.shape) {
570
+ case "bars": return barsIconPrims(s, color, icon.fill);
571
+ case "pie": return pieIconPrims(s, color, icon.fill);
572
+ case "check": return [{
573
+ paths: [checkPath(s)],
574
+ stroke: {
575
+ colorHex: color,
576
+ widthPt: s * .16
577
+ }
578
+ }];
579
+ case "cross": return [{
580
+ paths: crossPaths(s),
581
+ stroke: {
582
+ colorHex: color,
583
+ widthPt: s * .16
584
+ }
585
+ }];
586
+ case "exclamation": return [{
587
+ paths: [rectAtPath(s * .41, s * .34, s * .18, s * .56), rectAtPath(s * .41, s * .1, s * .18, s * .16)],
588
+ fillColorHex: color
589
+ }];
590
+ default: return [{
591
+ paths: [cellIconPath(icon.shape, s)],
592
+ fillColorHex: color
593
+ }];
594
+ }
571
595
  }
572
596
  function cellIconPath(shape, s) {
573
597
  switch (shape) {
@@ -579,6 +603,52 @@ function cellIconPath(shape, s) {
579
603
  case "circle": return circlePath(s / 2, s / 2, s * .42);
580
604
  }
581
605
  }
606
+ function barsIconPrims(s, color, fill) {
607
+ const n = Math.max(1, fill?.levels ?? 4);
608
+ const filled = fill?.filled ?? 0;
609
+ const gap = s * .12;
610
+ const bw = (s - gap * (n - 1)) / n;
611
+ const prims = [];
612
+ for (let i = 0; i < n; i++) {
613
+ const h = s * (.32 + .68 * (i + 1) / n);
614
+ prims.push({
615
+ paths: [rectAtPath(i * (bw + gap), 0, bw, h)],
616
+ fillColorHex: i < filled ? color : CF_ICON_EMPTY_HEX
617
+ });
618
+ }
619
+ return prims;
620
+ }
621
+ function pieIconPrims(s, color, fill) {
622
+ const cx = s / 2;
623
+ const cy = s / 2;
624
+ const r = s * .46;
625
+ const levels = Math.max(1, fill?.levels ?? 4);
626
+ const filled = Math.max(0, Math.min(levels, fill?.filled ?? 0));
627
+ const prims = [{
628
+ paths: [circlePath(cx, cy, r)],
629
+ fillColorHex: CF_ICON_EMPTY_HEX
630
+ }];
631
+ if (filled >= levels) prims.push({
632
+ paths: [circlePath(cx, cy, r)],
633
+ fillColorHex: color
634
+ });
635
+ else if (filled > 0) {
636
+ const start = Math.PI / 2;
637
+ const sweep = -(filled / levels) * 2 * Math.PI;
638
+ const [sx, sy] = arcPoint(cx, cy, r, r, start);
639
+ prims.push({
640
+ paths: [new PathBuilder().moveTo(cx, cy).lineTo(sx, sy).append(arcToBeziers(cx, cy, r, r, start, sweep)).close().build()],
641
+ fillColorHex: color
642
+ });
643
+ }
644
+ return prims;
645
+ }
646
+ function checkPath(s) {
647
+ return new PathBuilder().moveTo(s * .16, s * .5).lineTo(s * .4, s * .26).lineTo(s * .84, s * .78).build();
648
+ }
649
+ function crossPaths(s) {
650
+ return [new PathBuilder().moveTo(s * .24, s * .24).lineTo(s * .76, s * .76).build(), new PathBuilder().moveTo(s * .24, s * .76).lineTo(s * .76, s * .24).build()];
651
+ }
582
652
  function trianglePath(a, b, c) {
583
653
  return new PathBuilder().moveTo(a[0], a[1]).lineTo(b[0], b[1]).lineTo(c[0], c[1]).close().build();
584
654
  }
@@ -2129,22 +2199,21 @@ function emitRowChunk(out, row, marginLeft, cursorY, pageHeight, colCount, cellS
2129
2199
  if (cell.icon && cell.mergeRole !== "middle" && cell.mergeRole !== "end") {
2130
2200
  const iconSize = Math.min(CF_ICON_SIZE_PT, Math.max(0, row.heightPt - 1));
2131
2201
  if (iconSize > 0) {
2132
- const iconX = cellX + (CF_ICON_GUTTER_PT - iconSize) / 2;
2133
- const iconBottomYUp = rowBottom + (row.heightPt - iconSize) / 2;
2134
- const { paths, fillColorHex } = buildCellIconShape(cell.icon, iconSize);
2135
- out.push({
2202
+ const iconTransform = flipTransform([
2203
+ 1,
2204
+ 0,
2205
+ 0,
2206
+ 1,
2207
+ cellX + (CF_ICON_GUTTER_PT - iconSize) / 2,
2208
+ rowBottom + (row.heightPt - iconSize) / 2
2209
+ ], pageHeight);
2210
+ for (const prim of buildCellIconShape(cell.icon, iconSize)) out.push({
2136
2211
  type: "shape",
2137
2212
  shape: {
2138
- paths,
2139
- fillColorHex,
2140
- transform: flipTransform([
2141
- 1,
2142
- 0,
2143
- 0,
2144
- 1,
2145
- iconX,
2146
- iconBottomYUp
2147
- ], pageHeight)
2213
+ paths: prim.paths,
2214
+ ...prim.fillColorHex ? { fillColorHex: prim.fillColorHex } : {},
2215
+ ...prim.stroke ? { stroke: prim.stroke } : {},
2216
+ transform: iconTransform
2148
2217
  }
2149
2218
  });
2150
2219
  }
@@ -0,0 +1,5 @@
1
+ export interface ToUnicode {
2
+ readonly map: ReadonlyMap<number, string>;
3
+ readonly codeBytes: 1 | 2;
4
+ }
5
+ export declare function parseToUnicodeCMap(bytes: Uint8Array): ToUnicode;
@@ -0,0 +1,72 @@
1
+ import { Lexer } from "./lexer.js";
2
+ //#region src/pdf-reader/cmap.ts
3
+ var MAX_RANGE = 65536;
4
+ function parseToUnicodeCMap(bytes) {
5
+ const lexer = new Lexer(bytes);
6
+ const map = /* @__PURE__ */ new Map();
7
+ let codeBytes = 1;
8
+ for (;;) {
9
+ const tok = lexer.nextToken();
10
+ if (tok.kind === "eof") break;
11
+ if (tok.kind !== "keyword") continue;
12
+ if (tok.value === "begincodespacerange") for (;;) {
13
+ const t = lexer.nextToken();
14
+ if (t.kind === "eof" || t.kind === "keyword" && t.value === "endcodespacerange") break;
15
+ if (t.kind === "hexstr") {
16
+ if (t.bytes.length >= 2) codeBytes = 2;
17
+ lexer.nextToken();
18
+ }
19
+ }
20
+ else if (tok.value === "beginbfchar") for (;;) {
21
+ const src = lexer.nextToken();
22
+ if (src.kind === "eof" || src.kind === "keyword" && src.value === "endbfchar") break;
23
+ if (src.kind !== "hexstr") continue;
24
+ const dst = lexer.nextToken();
25
+ if (dst.kind !== "hexstr") continue;
26
+ map.set(bytesToInt(src.bytes), utf16be(dst.bytes));
27
+ }
28
+ else if (tok.value === "beginbfrange") for (;;) {
29
+ const lo = lexer.nextToken();
30
+ if (lo.kind === "eof" || lo.kind === "keyword" && lo.value === "endbfrange") break;
31
+ if (lo.kind !== "hexstr") continue;
32
+ const hi = lexer.nextToken();
33
+ if (hi.kind !== "hexstr") continue;
34
+ const loN = bytesToInt(lo.bytes);
35
+ const hiN = bytesToInt(hi.bytes);
36
+ const dst = lexer.nextToken();
37
+ if (dst.kind === "hexstr") {
38
+ const base = utf16be(dst.bytes);
39
+ for (let i = 0; loN + i <= hiN && i < MAX_RANGE; i++) map.set(loN + i, incString(base, i));
40
+ } else if (dst.kind === "arrayOpen") {
41
+ let i = 0;
42
+ for (;;) {
43
+ const el = lexer.nextToken();
44
+ if (el.kind === "arrayClose" || el.kind === "eof") break;
45
+ if (el.kind === "hexstr") map.set(loN + i++, utf16be(el.bytes));
46
+ }
47
+ }
48
+ }
49
+ }
50
+ return {
51
+ map,
52
+ codeBytes
53
+ };
54
+ }
55
+ function bytesToInt(bytes) {
56
+ let n = 0;
57
+ for (const b of bytes) n = n * 256 + b;
58
+ return n;
59
+ }
60
+ function utf16be(bytes) {
61
+ let s = "";
62
+ for (let i = 0; i + 1 < bytes.length; i += 2) s += String.fromCharCode(bytes[i] << 8 | bytes[i + 1]);
63
+ if (bytes.length % 2 === 1) s += String.fromCharCode(bytes[bytes.length - 1]);
64
+ return s;
65
+ }
66
+ function incString(base, i) {
67
+ if (i === 0) return base;
68
+ if (base.length === 1) return String.fromCharCode(base.charCodeAt(0) + i);
69
+ return base;
70
+ }
71
+ //#endregion
72
+ export { parseToUnicodeCMap };
@@ -0,0 +1,52 @@
1
+ export interface ContentFont {
2
+ readonly bytesPerCode: 1 | 2;
3
+ decode: (codes: ReadonlyArray<number>) => string;
4
+ width: (code: number) => number;
5
+ }
6
+ export interface TextRun {
7
+ readonly text: string;
8
+ readonly x: number;
9
+ readonly y: number;
10
+ readonly fontSizePt: number;
11
+ readonly fontKey: string;
12
+ readonly mcid?: number;
13
+ readonly href?: string;
14
+ }
15
+ export interface ImagePlacement {
16
+ readonly name: string;
17
+ readonly ctm: Matrix;
18
+ readonly mcid?: number;
19
+ }
20
+ export type PathSeg = {
21
+ readonly op: 'move';
22
+ readonly x: number;
23
+ readonly y: number;
24
+ } | {
25
+ readonly op: 'line';
26
+ readonly x: number;
27
+ readonly y: number;
28
+ } | {
29
+ readonly op: 'cubic';
30
+ readonly x1: number;
31
+ readonly y1: number;
32
+ readonly x2: number;
33
+ readonly y2: number;
34
+ readonly x: number;
35
+ readonly y: number;
36
+ } | {
37
+ readonly op: 'close';
38
+ };
39
+ export interface VectorPlacement {
40
+ readonly segs: ReadonlyArray<PathSeg>;
41
+ readonly fillHex: string;
42
+ readonly mcid?: number;
43
+ }
44
+ export interface InterpretResult {
45
+ readonly texts: Array<TextRun>;
46
+ readonly images: Array<ImagePlacement>;
47
+ readonly vectors: Array<VectorPlacement>;
48
+ }
49
+ export type Matrix = readonly [number, number, number, number, number, number];
50
+ export declare const IDENTITY: Matrix;
51
+ export declare function multiply(a: Matrix, b: Matrix): Matrix;
52
+ export declare function interpretContent(bytes: Uint8Array, fonts: ReadonlyMap<string, ContentFont>, initialCtm?: Matrix): InterpretResult;