@doccloak/core 0.12.1 → 0.14.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 (79) hide show
  1. package/CHANGELOG.md +386 -0
  2. package/NOTICE +5 -0
  3. package/README.md +148 -9
  4. package/dist/dom/errors.d.ts +1 -1
  5. package/dist/dom/ocr.d.ts +33 -7
  6. package/dist/dom/ocr.js +98 -4
  7. package/dist/dom/office.d.ts +22 -6
  8. package/dist/dom/office.js +45 -11
  9. package/dist/engine.js +4 -5
  10. package/dist/env.d.ts +3 -3
  11. package/dist/pdf/cmap.d.ts +83 -0
  12. package/dist/pdf/cmap.js +659 -0
  13. package/dist/pdf/encodings.d.ts +49 -0
  14. package/dist/pdf/encodings.js +181 -0
  15. package/dist/pdf/extract.d.ts +108 -0
  16. package/dist/pdf/extract.js +1164 -0
  17. package/dist/pdf/fallback-fonts.d.ts +146 -0
  18. package/dist/pdf/fallback-fonts.js +312 -0
  19. package/dist/pdf/fit.d.ts +35 -0
  20. package/dist/pdf/fit.js +60 -0
  21. package/dist/pdf/fonts.d.ts +82 -0
  22. package/dist/pdf/fonts.js +465 -0
  23. package/dist/pdf/glyphlist.d.ts +37 -0
  24. package/dist/pdf/glyphlist.js +485 -0
  25. package/dist/pdf/index.d.ts +21 -0
  26. package/dist/pdf/index.js +7 -0
  27. package/dist/pdf/lexer.d.ts +61 -0
  28. package/dist/pdf/lexer.js +554 -0
  29. package/dist/pdf/objects.d.ts +57 -0
  30. package/dist/pdf/objects.js +217 -0
  31. package/dist/pdf/oracle.d.ts +149 -0
  32. package/dist/pdf/oracle.js +384 -0
  33. package/dist/pdf/raster.d.ts +119 -0
  34. package/dist/pdf/raster.js +405 -0
  35. package/dist/pdf/read.d.ts +36 -0
  36. package/dist/pdf/read.js +65 -0
  37. package/dist/pdf/serializer.d.ts +21 -0
  38. package/dist/pdf/serializer.js +106 -0
  39. package/dist/pdf/standard-metrics.d.ts +27 -0
  40. package/dist/pdf/standard-metrics.js +72 -0
  41. package/dist/pdf/surgery.d.ts +131 -0
  42. package/dist/pdf/surgery.js +847 -0
  43. package/dist/pdf/textstate.d.ts +88 -0
  44. package/dist/pdf/textstate.js +293 -0
  45. package/dist/pdf/types.d.ts +206 -0
  46. package/dist/pdf/types.js +11 -0
  47. package/dist/pdf/verify.d.ts +33 -0
  48. package/dist/pdf/verify.js +446 -0
  49. package/dist/pdf/write.d.ts +62 -0
  50. package/dist/pdf/write.js +750 -0
  51. package/dist/pipeline.d.ts +15 -0
  52. package/dist/pipeline.js +123 -8
  53. package/dist/providers/bardsai.d.ts +1 -1
  54. package/dist/providers/bardsai.js +5 -1
  55. package/dist/providers/gliner-base.d.ts +1 -1
  56. package/dist/providers/gliner-base.js +5 -1
  57. package/dist/providers/gliner.d.ts +1 -1
  58. package/dist/providers/gliner.js +5 -1
  59. package/dist/regex/rules.data.js +13 -8
  60. package/dist/types.d.ts +17 -2
  61. package/dist/types.js +17 -0
  62. package/dist/worker-protocol.d.ts +11 -0
  63. package/dist/worker-protocol.js +41 -8
  64. package/fonts/liberation/LICENSE +102 -0
  65. package/fonts/liberation/LiberationMono-Bold.ttf +0 -0
  66. package/fonts/liberation/LiberationMono-BoldItalic.ttf +0 -0
  67. package/fonts/liberation/LiberationMono-Italic.ttf +0 -0
  68. package/fonts/liberation/LiberationMono-Regular.ttf +0 -0
  69. package/fonts/liberation/LiberationSans-Bold.ttf +0 -0
  70. package/fonts/liberation/LiberationSans-BoldItalic.ttf +0 -0
  71. package/fonts/liberation/LiberationSans-Italic.ttf +0 -0
  72. package/fonts/liberation/LiberationSans-Regular.ttf +0 -0
  73. package/fonts/liberation/LiberationSerif-Bold.ttf +0 -0
  74. package/fonts/liberation/LiberationSerif-BoldItalic.ttf +0 -0
  75. package/fonts/liberation/LiberationSerif-Italic.ttf +0 -0
  76. package/fonts/liberation/LiberationSerif-Regular.ttf +0 -0
  77. package/package.json +11 -2
  78. package/rules/pl.json +7 -3
  79. package/rules/universal.json +6 -5
@@ -0,0 +1,72 @@
1
+ /**
2
+ * @doccloak/core/pdf - metrics of the standard 14 fonts (T209).
3
+ *
4
+ * Fonts that are not embedded and carry no /Widths (the standard 14 and their
5
+ * common aliases: Arial, Times New Roman, Courier New) get their advance
6
+ * widths from the AFM metrics vendored by @cantoo/pdf-lib.
7
+ */
8
+ import { Font as AfmFont } from '@cantoo/pdf-lib/standard-fonts';
9
+ const CACHE = new Map();
10
+ function normalizeBaseFont(baseFont) {
11
+ return baseFont.replace(/^[A-Z]{6}\+/, '').replace(/[\s_]/g, '').toLowerCase();
12
+ }
13
+ /**
14
+ * Map a /BaseFont to a standard 14 font, or undefined. Handles the aliases
15
+ * from the PDF 1.7 implementation notes (Arial, TimesNewRoman, CourierNew)
16
+ * and the ",Bold" / "-BoldItalic" / "PS-BoldMT" style suffixes.
17
+ */
18
+ export function standardFontFor(baseFont) {
19
+ const n = normalizeBaseFont(baseFont);
20
+ const bold = /bold|black|heavy|semibold|demibold/.test(n);
21
+ const italic = /italic|oblique/.test(n);
22
+ let family;
23
+ if (n.startsWith('courier'))
24
+ family = 'Courier';
25
+ else if (n.startsWith('helvetica') || n.startsWith('arial'))
26
+ family = 'Helvetica';
27
+ else if (n.startsWith('times'))
28
+ family = 'Times';
29
+ else if (n === 'symbol' || n.startsWith('symbol,') || n === 'symbolmt')
30
+ family = 'Symbol';
31
+ else if (n.startsWith('zapfdingbats') || n === 'dingbats')
32
+ family = 'ZapfDingbats';
33
+ if (!family)
34
+ return undefined;
35
+ if (family === 'Symbol' || family === 'ZapfDingbats')
36
+ return family;
37
+ if (family === 'Times') {
38
+ if (bold && italic)
39
+ return 'Times-BoldItalic';
40
+ if (bold)
41
+ return 'Times-Bold';
42
+ if (italic)
43
+ return 'Times-Italic';
44
+ return 'Times-Roman';
45
+ }
46
+ const suffix = bold && italic ? '-BoldOblique' : bold ? '-Bold' : italic ? '-Oblique' : '';
47
+ return `${family}${suffix}`;
48
+ }
49
+ export function loadStandardMetrics(name) {
50
+ let afm = CACHE.get(name);
51
+ if (!afm) {
52
+ afm = AfmFont.load(name);
53
+ CACHE.set(name, afm);
54
+ }
55
+ const font = afm;
56
+ const byName = new Map();
57
+ const builtin = new Array(256).fill(undefined);
58
+ for (const m of font.CharMetrics) {
59
+ byName.set(m.N, m.WX);
60
+ if (typeof m.C === 'number' && m.C >= 0 && m.C < 256)
61
+ builtin[m.C] = m.N;
62
+ }
63
+ return {
64
+ name,
65
+ widthOfGlyph: (g) => byName.get(g),
66
+ hasGlyph: (g) => byName.has(g),
67
+ builtinEncoding: () => builtin,
68
+ ascender: font.Ascender ?? 718,
69
+ descender: font.Descender ?? -207,
70
+ capHeight: font.CapHeight ?? 718,
71
+ };
72
+ }
@@ -0,0 +1,131 @@
1
+ /**
2
+ * @doccloak/core/pdf - content-stream surgery (T213).
3
+ *
4
+ * Turns flat-text replacements into operator-level edits and rewrites the
5
+ * affected content streams:
6
+ *
7
+ * - the glyphs of a redacted span are cut out of their text-showing operator
8
+ * (string operands are split at code boundaries; kerning numbers between
9
+ * kept glyphs are preserved, numbers adjacent to removed glyphs are dropped);
10
+ * - the placeholder is written as a new show in the original font when that
11
+ * font can encode it, else in the matched fallback face, sized by fit.ts;
12
+ * - every show after an edited one in the same positioning scope is
13
+ * re-anchored with an absolute Tm computed from the ORIGINAL geometry, so
14
+ * the implicit advance chain cannot shift (and the residual positions of
15
+ * surviving glyphs cannot encode what was removed);
16
+ * - when the placeholder is wider than the gap even after shrinking, the rest
17
+ * of the line (in the same stream) moves right by the overflow;
18
+ * - the line matrix is restored before the next relative positioning
19
+ * operator, so later lines land exactly where they did.
20
+ *
21
+ * Operators that are not touched are copied byte-for-byte.
22
+ */
23
+ import type { GlyphRun, PlaceholderFit } from './types.js';
24
+ import type { LoadedFont } from './fonts.js';
25
+ import type { StreamRecord, PdfModel } from './extract.js';
26
+ import type { FitResult } from './fit.js';
27
+ export interface Replacement {
28
+ start: number;
29
+ end: number;
30
+ replacement: string;
31
+ }
32
+ /** A placeholder resolved to concrete bytes in a concrete font resource. */
33
+ export interface PlaceholderSpec {
34
+ text: string;
35
+ bytes: Uint8Array;
36
+ /** Resource name (in the stream's /Resources /Font) of the font to show it with. */
37
+ resourceName: string;
38
+ /** True when the original font is reused (no resource to add). */
39
+ originalFont: boolean;
40
+ fit: FitResult;
41
+ /** Codes shown in the original font (for ToUnicode scrubbing); empty for fallback fonts. */
42
+ codes: number[];
43
+ /**
44
+ * Negative when the placeholder is narrower than the gap: the text that
45
+ * follows in the same positioning chain moves left by this much (unscaled
46
+ * text space of the run) so no hole is left before the next word. Zero
47
+ * otherwise (overflow is handled line-wide through LineShift).
48
+ */
49
+ slack: number;
50
+ }
51
+ /** One contiguous glyph range of one run that a replacement covers. */
52
+ export interface Segment {
53
+ run: GlyphRun;
54
+ /** Glyph index range [from, to). */
55
+ from: number;
56
+ to: number;
57
+ /** Set on the first segment of a replacement: the placeholder to show there. */
58
+ placeholder?: PlaceholderSpec;
59
+ replacementIndex: number;
60
+ /** True when this segment is the only one of its replacement (its codes are the complete value in one run). */
61
+ whole?: boolean;
62
+ /**
63
+ * Set on the segment where the replacement's gap ends: how far the glyphs
64
+ * after it in the same run move (unscaled text space of the run; negative
65
+ * closes the slack of a narrow placeholder, positive pushes an overflow).
66
+ */
67
+ shiftAfter?: number;
68
+ }
69
+ /** Key of a run inside a plan: stream key + operator index. */
70
+ export declare function runKey(run: GlyphRun): string;
71
+ /**
72
+ * Resolve a font for a placeholder: returns the encoded bytes with the
73
+ * original font, or asks the host for a fallback (which must already be
74
+ * embedded so its bytes are final).
75
+ */
76
+ export interface PlaceholderResolver {
77
+ (font: LoadedFont, text: string, streamKey: string): Promise<{
78
+ bytes: Uint8Array;
79
+ widthPerEm: number;
80
+ resourceName: string;
81
+ originalFont: boolean;
82
+ codes: number[];
83
+ }>;
84
+ }
85
+ /**
86
+ * Map flat-text replacements to per-run glyph segments. Runs must be in
87
+ * flat-text order (as the extractor produced them). Oracle runs (raster-only
88
+ * pages) are returned as segments too; the caller routes them to the
89
+ * rasterizer.
90
+ */
91
+ export declare function segmentsFor(runs: GlyphRun[], replacements: Replacement[]): Segment[];
92
+ /** User units per unscaled text-space unit along the baseline of a run. */
93
+ export declare function unitScale(run: GlyphRun): number;
94
+ export interface Plan {
95
+ /** Segments grouped by stream key; each stream's segments sorted by (opIndex, from). */
96
+ byStream: Map<string, Segment[]>;
97
+ /** Runs that move as a whole (run key -> shift in user units along their baseline). */
98
+ shiftedRuns: Map<string, number>;
99
+ /** Fallback resource names needed per stream key. */
100
+ resourcesNeeded: Map<string, Set<string>>;
101
+ shiftedLines: number;
102
+ warnings: string[];
103
+ }
104
+ /**
105
+ * Decide, for every replacement, where the placeholder goes and how it is
106
+ * fitted. The first segment (flat-text order) carries the placeholder; other
107
+ * segments are excised. The gap is the width of every segment of the same
108
+ * replacement that sits on the same line as the first, so a name split over
109
+ * two shows on one line gets the whole width.
110
+ */
111
+ export declare function planEdits(model: PdfModel, allRuns: GlyphRun[], segments: Segment[], replacements: Replacement[], resolve: PlaceholderResolver, fitPolicy?: PlaceholderFit): Promise<Plan>;
112
+ export interface RewriteResult {
113
+ bytes: Uint8Array;
114
+ /** Codes still shown per font key after the rewrite (for ToUnicode scrubbing). */
115
+ usedCodes: Map<string, Set<number>>;
116
+ /** Original code sequences removed (per font key), for the verifier's byte scan. */
117
+ removedSequences: Array<{
118
+ fontKey: string;
119
+ bytes: Uint8Array;
120
+ codeLength: number;
121
+ }>;
122
+ /** Fonts whose glyphs were removed. */
123
+ editedFonts: Set<string>;
124
+ edits: number;
125
+ }
126
+ /**
127
+ * Rewrite one stream. `runsByOp` gives the GlyphRun of every text-showing
128
+ * operator (first instance for shared XObjects). `segments` are the edits in
129
+ * this stream. Every unaffected operator is copied verbatim.
130
+ */
131
+ export declare function rewriteStream(model: PdfModel, stream: StreamRecord, runsByOp: Map<number, GlyphRun>, segments: Segment[], shiftedRuns: Map<string, number>): RewriteResult;