@imgly/pdf-importer 0.1.0-rc.2 → 0.2.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/CHANGELOG.md +55 -0
- package/LICENSE.md +137 -650
- package/README.md +23 -4
- package/dist/browser.d.cts +854 -0
- package/dist/browser.d.ts +580 -26
- package/dist/browser.js +13 -12
- package/dist/node.cjs +16 -0
- package/dist/node.d.cts +854 -0
- package/dist/node.d.ts +580 -26
- package/dist/node.js +13 -12
- package/package.json +25 -24
package/dist/node.d.cts
ADDED
|
@@ -0,0 +1,854 @@
|
|
|
1
|
+
// Generated by dts-bundle-generator v9.5.1
|
|
2
|
+
|
|
3
|
+
import CreativeEngine from '@cesdk/engine';
|
|
4
|
+
import { AssetAPI, Font, FontStyle, FontWeight, Typeface } from '@cesdk/engine';
|
|
5
|
+
|
|
6
|
+
type WarningSeverity = "error" | "warning" | "info";
|
|
7
|
+
interface WarningDefinition {
|
|
8
|
+
/** Default + sole severity. Call sites do not override. */
|
|
9
|
+
severity: WarningSeverity;
|
|
10
|
+
/**
|
|
11
|
+
* Template with `{name}` placeholders. Renderer throws if a placeholder
|
|
12
|
+
* has no matching key in `params` — guards against silent typos.
|
|
13
|
+
*/
|
|
14
|
+
template: string;
|
|
15
|
+
}
|
|
16
|
+
interface LogMessage<TCode extends string = string> {
|
|
17
|
+
/** Stable machine-readable identifier — never rename once shipped. */
|
|
18
|
+
code: TCode;
|
|
19
|
+
/** Inherited from the code definition. */
|
|
20
|
+
type: WarningSeverity;
|
|
21
|
+
/** Human-readable rendered string. */
|
|
22
|
+
message: string;
|
|
23
|
+
/** Raw structured fields — superset of all `{name}` placeholders. */
|
|
24
|
+
params: Record<string, unknown>;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Generic structured logger. Severity is registry-driven (PostgreSQL
|
|
28
|
+
* SQLSTATE pattern) — call sites cannot override. To change severity,
|
|
29
|
+
* edit the registry.
|
|
30
|
+
*/
|
|
31
|
+
export declare class Logger<R extends Record<string, WarningDefinition>> {
|
|
32
|
+
private readonly registry;
|
|
33
|
+
private messages;
|
|
34
|
+
constructor(registry: R);
|
|
35
|
+
emit<K extends keyof R & string>(code: K, params?: Record<string, unknown>): void;
|
|
36
|
+
getMessages(): LogMessage<keyof R & string>[];
|
|
37
|
+
}
|
|
38
|
+
type AssetQueryAPI = Pick<AssetAPI, "findAllSources" | "addLocalAssetSourceFromJSONURI" | "findAssets">;
|
|
39
|
+
type AssetEngine = {
|
|
40
|
+
asset: AssetQueryAPI;
|
|
41
|
+
};
|
|
42
|
+
interface TypefaceParams {
|
|
43
|
+
family: string;
|
|
44
|
+
style?: Font["style"];
|
|
45
|
+
weight?: Font["weight"];
|
|
46
|
+
}
|
|
47
|
+
interface FontResolverOptions {
|
|
48
|
+
/**
|
|
49
|
+
* When the requested weight is not available in the matched typeface,
|
|
50
|
+
* pick the closest available weight using the CSS Font Matching algorithm.
|
|
51
|
+
* Defaults to false — return null instead so the caller can decide what
|
|
52
|
+
* to do (e.g. log a warning, use a different font).
|
|
53
|
+
*
|
|
54
|
+
* Only enable when the typeface name is known to be a good match. The
|
|
55
|
+
* typeface query uses fuzzy matching, so applying weight fallback to a
|
|
56
|
+
* poor name match can silently produce wildly wrong results.
|
|
57
|
+
*/
|
|
58
|
+
closestWeightMatch?: boolean;
|
|
59
|
+
}
|
|
60
|
+
interface FontResolverResult {
|
|
61
|
+
typeface: Typeface;
|
|
62
|
+
font: Font;
|
|
63
|
+
/**
|
|
64
|
+
* Set to the originally requested family name when the typeface came from
|
|
65
|
+
* the proprietary-fallbacks source (e.g. requested "Helvetica", got Roboto).
|
|
66
|
+
* Undefined when the family matched the main Google Fonts catalog directly.
|
|
67
|
+
* Always populated when applicable; consumers may ignore it.
|
|
68
|
+
*/
|
|
69
|
+
substitutedFrom?: string;
|
|
70
|
+
}
|
|
71
|
+
type TypefaceResolver = (params: TypefaceParams, engine: AssetEngine, options?: FontResolverOptions) => Promise<FontResolverResult | null>;
|
|
72
|
+
/**
|
|
73
|
+
* Register the @imgly/gfonts asset sources (Google Fonts catalog + proprietary
|
|
74
|
+
* font fallbacks) with the CE.SDK engine.
|
|
75
|
+
*
|
|
76
|
+
* Adds two sources:
|
|
77
|
+
* - `ly.img.gfonts` — 1,394 Google Fonts typefaces (fuzzy-matched).
|
|
78
|
+
* - `ly.img.gfonts-fallbacks` — 16 proprietary-font alias entries
|
|
79
|
+
* (e.g. Helvetica → Roboto), strict-matched.
|
|
80
|
+
*/
|
|
81
|
+
export declare function addGfontsAssetLibrary(engine: AssetEngine): Promise<void>;
|
|
82
|
+
declare const WARNING_CODES: {
|
|
83
|
+
readonly DOC_PAGE_COUNT: {
|
|
84
|
+
readonly severity: "info";
|
|
85
|
+
readonly template: "PDF has {count} page(s)";
|
|
86
|
+
};
|
|
87
|
+
readonly DOC_PAGE_BLOCK_COUNT: {
|
|
88
|
+
readonly severity: "info";
|
|
89
|
+
readonly template: "Page {page}: {imageCount} image, {vectorCount} vector, {textCount} text, {outlineCount} outline";
|
|
90
|
+
};
|
|
91
|
+
readonly DOC_PAGE_ROTATION_DROPPED: {
|
|
92
|
+
readonly severity: "warning";
|
|
93
|
+
readonly template: "{prefix}PDF declares /Rotate {pageRotation}; the importer does not apply page rotation, so the imported page is in its un-rotated (native) orientation. Viewer-rendered output may differ from the source's display orientation.";
|
|
94
|
+
};
|
|
95
|
+
readonly BLOCK_KIND_UNKNOWN: {
|
|
96
|
+
readonly severity: "error";
|
|
97
|
+
readonly template: "An unknown block kind \"{kind}\" was encountered and was skipped.";
|
|
98
|
+
};
|
|
99
|
+
readonly PAGE_INDEX_OUT_OF_RANGE: {
|
|
100
|
+
readonly severity: "warning";
|
|
101
|
+
readonly template: "Requested page index {requested} is out of range; PDF has {available} page(s). No blocks were emitted.";
|
|
102
|
+
};
|
|
103
|
+
readonly FONT_OPENTYPE_PARSE_FAILED: {
|
|
104
|
+
readonly severity: "warning";
|
|
105
|
+
readonly template: "{prefix}font \"{fontName}\" could not be parsed as OpenType{reason}. Glyph outlines will fall back to pdf.js raster paths \u2014 some shapes may render without stroke/anti-aliasing detail.";
|
|
106
|
+
};
|
|
107
|
+
readonly FONT_CMAP_AUGMENTED: {
|
|
108
|
+
readonly severity: "info";
|
|
109
|
+
readonly template: "Font \"{fontName}\" character map was augmented (cmap patches={cmapPatches}, injected glyphs={injectedGlyphs}).";
|
|
110
|
+
};
|
|
111
|
+
readonly FONT_CMAP_AUGMENT_FAILED: {
|
|
112
|
+
readonly severity: "warning";
|
|
113
|
+
readonly template: "Font \"{fontName}\" character map could not be augmented. Using the original font data \u2014 some glyphs may render incorrectly.";
|
|
114
|
+
};
|
|
115
|
+
readonly FONT_RESOLVER_MISS: {
|
|
116
|
+
readonly severity: "warning";
|
|
117
|
+
readonly template: "Font \"{fontFamily}\" could not be resolved. The text was rendered as a vector outline.";
|
|
118
|
+
};
|
|
119
|
+
readonly FONT_NOT_FOUND_IN_ASSETS: {
|
|
120
|
+
readonly severity: "warning";
|
|
121
|
+
readonly template: "Font \"{fontFamily}\" was not found in the asset library. The text was rendered as a vector outline.";
|
|
122
|
+
};
|
|
123
|
+
readonly FONT_SUBSTITUTED: {
|
|
124
|
+
readonly severity: "info";
|
|
125
|
+
readonly template: "Font \"{fontFamily}\" was substituted with \"{substitutedName}\" from the asset library.";
|
|
126
|
+
};
|
|
127
|
+
readonly FONT_REF_NOT_EXTRACTED: {
|
|
128
|
+
readonly severity: "error";
|
|
129
|
+
readonly template: "Text run references font \"{fontRef}\" which was not extracted. The text was skipped.";
|
|
130
|
+
};
|
|
131
|
+
readonly FONT_SUBSTITUTIONS: {
|
|
132
|
+
readonly severity: "warning";
|
|
133
|
+
readonly template: "Substituted {count} font famil{plural} during import: {pairs}.";
|
|
134
|
+
};
|
|
135
|
+
readonly FONT_SUBSET_FALLBACK: {
|
|
136
|
+
readonly severity: "warning";
|
|
137
|
+
readonly template: string;
|
|
138
|
+
};
|
|
139
|
+
readonly TEXT_OUTLINE_NO_FONT_FAMILY: {
|
|
140
|
+
readonly severity: "warning";
|
|
141
|
+
readonly template: "Text outline has no declared font family. The run was skipped.";
|
|
142
|
+
};
|
|
143
|
+
readonly TEXT_RUN_SKIPPED_NO_RESOLUTION: {
|
|
144
|
+
readonly severity: "warning";
|
|
145
|
+
readonly template: "No typeface or glyph outlines for \"{fontFamily}\"; run skipped.";
|
|
146
|
+
};
|
|
147
|
+
readonly TEXT_RENDER_MODE_SKIPPED: {
|
|
148
|
+
readonly severity: "warning";
|
|
149
|
+
readonly template: "Text item{pageTag}: skipped \"{text}\" \u2014 PDF text rendering mode {modeLabel}. This text paints no ink; for mode 7 it acts as a clipping mask for following images, an effect the importer does not currently reproduce.";
|
|
150
|
+
};
|
|
151
|
+
readonly TEXT_OVERFLOW_AFTER_AUTOSIZE: {
|
|
152
|
+
readonly severity: "warning";
|
|
153
|
+
readonly template: "Text \"{text}\" did not fit after auto-sizing; it still overflows by {overflowLines} line(s). The text was kept; some content may be clipped.";
|
|
154
|
+
};
|
|
155
|
+
readonly TEXT_CLIP_MODE_7_DROPPED: {
|
|
156
|
+
readonly severity: "warning";
|
|
157
|
+
readonly template: "{prefix}{label} at ({bbox}) {bboxSize} pt: dropped because the surrounding region was clipped by text in PDF render mode 7 (text-as-clipping-mask). The masked artwork cannot be reproduced as text-clipped content.";
|
|
158
|
+
};
|
|
159
|
+
readonly IMAGE_ENCODER_MISS: {
|
|
160
|
+
readonly severity: "warning";
|
|
161
|
+
readonly template: "{prefix}an image{idLabel} ({width}\u00D7{height} raw pixels{kind}) could not be encoded ({reason}). The image was dropped from the imported design.";
|
|
162
|
+
};
|
|
163
|
+
readonly IMAGE_PDFJS_UNRESOLVED: {
|
|
164
|
+
readonly severity: "error";
|
|
165
|
+
readonly template: "{prefix}image placement {idLabel} at ({bboxX}, {bboxY}) {bboxW}\u00D7{bboxH} pt could not be resolved by pdf.js (reason={reason}) and was dropped.";
|
|
166
|
+
};
|
|
167
|
+
readonly IMAGE_NO_PIXELS: {
|
|
168
|
+
readonly severity: "warning";
|
|
169
|
+
readonly template: "An image element has no pixel data and was skipped.";
|
|
170
|
+
};
|
|
171
|
+
readonly IMAGE_FLIP_UNSUPPORTED: {
|
|
172
|
+
readonly severity: "warning";
|
|
173
|
+
readonly template: "Image flip could not be applied (engine version too old). The image will display without flip.";
|
|
174
|
+
};
|
|
175
|
+
readonly IMAGE_SKEW_DROPPED: {
|
|
176
|
+
readonly severity: "warning";
|
|
177
|
+
readonly template: "{prefix}an image{idLabel} at ({bboxX}, {bboxY}) {bboxW}\u00D7{bboxH} pt has a skewed transform ctm={ctm}{residualStr} that cannot be represented. Placed axis-aligned \u2014 image content will appear un-skewed.";
|
|
178
|
+
};
|
|
179
|
+
readonly IMAGE_CLIPPED_NO_BYTES: {
|
|
180
|
+
readonly severity: "warning";
|
|
181
|
+
readonly template: "{prefix}a clipped image at {bbox} had no decoded bytes; the placement was dropped before combining clip shapes.";
|
|
182
|
+
};
|
|
183
|
+
readonly IMAGE_CLIP_UNUSABLE: {
|
|
184
|
+
readonly severity: "warning";
|
|
185
|
+
readonly template: "{prefix}a clipped image at {bbox} with {clipCount} clip path(s) has no usable clip \u2014 {degenerateCount} degenerate, {disjointCount} disjoint from the image. The image was dropped.";
|
|
186
|
+
};
|
|
187
|
+
readonly IMAGE_CLIP_EMPTY_INTERSECTION: {
|
|
188
|
+
readonly severity: "warning";
|
|
189
|
+
readonly template: "{prefix}a clipped image at {bbox} with {clipCount} clip path(s) had an empty intersection. The image was dropped.";
|
|
190
|
+
};
|
|
191
|
+
readonly IMAGE_CLIP_COMBINE_FAILED: {
|
|
192
|
+
readonly severity: "error";
|
|
193
|
+
readonly template: "{prefix}a clipped image at {bbox} with {clipCount} clip path(s) could not be combined. The image was dropped from the imported design.";
|
|
194
|
+
};
|
|
195
|
+
readonly IMAGE_MASK_NO_FILL_COLOR: {
|
|
196
|
+
readonly severity: "warning";
|
|
197
|
+
readonly template: "{prefix}a stencil ImageMask paint (objId={objId}) had no current fill colour to composite with. The mask was dropped from the imported design.";
|
|
198
|
+
};
|
|
199
|
+
readonly IMAGE_MASK_COMPOSITE_FAIL: {
|
|
200
|
+
readonly severity: "warning";
|
|
201
|
+
readonly template: "{prefix}a stencil ImageMask (objId={objId}) at ({bboxX}, {bboxY}) {bboxW}\u00D7{bboxH} pt could not be composited with the current fill colour (space={colourSpace}). The mask was dropped from the imported design.";
|
|
202
|
+
};
|
|
203
|
+
readonly IMAGE_MASK_GROUP_UNSUPPORTED: {
|
|
204
|
+
readonly severity: "warning";
|
|
205
|
+
readonly template: "{prefix}a paintImageMaskXObjectGroup batch of {count} stencil paints is not supported by the importer. The masks were dropped.";
|
|
206
|
+
};
|
|
207
|
+
readonly IMAGE_MASK_REPEAT_UNSUPPORTED: {
|
|
208
|
+
readonly severity: "warning";
|
|
209
|
+
readonly template: "{prefix}a paintImageMaskXObjectRepeat tiling {count} stencil paints is not supported by the importer. The masks were dropped.";
|
|
210
|
+
};
|
|
211
|
+
readonly CLIP_DEGENERATE_FALLBACK: {
|
|
212
|
+
readonly severity: "warning";
|
|
213
|
+
readonly template: "{prefix}a clipped vector path at {bbox} with {clipCount} clip path(s) has no usable clip \u2014 {degenerateCount} degenerate (zero width or height). Falling back to the unclipped path.";
|
|
214
|
+
};
|
|
215
|
+
readonly CLIP_COMBINE_STROKE_ONLY: {
|
|
216
|
+
readonly severity: "warning";
|
|
217
|
+
readonly template: "{prefix}a clipped vector path at {bbox} with {clipCount} clip path(s) has no fill color (stroke-only) which cannot survive combine. Falling back to the unclipped path.";
|
|
218
|
+
};
|
|
219
|
+
readonly CLIP_COMBINE_FAILED: {
|
|
220
|
+
readonly severity: "warning";
|
|
221
|
+
readonly template: "{prefix}a vector path at {bbox} with {clipCount} clip path(s) could not be combined. Rendered without its clip \u2014 some content may extend beyond the intended mask.";
|
|
222
|
+
};
|
|
223
|
+
readonly CLIP_COMBINE_TOO_FEW_INPUTS: {
|
|
224
|
+
readonly severity: "warning";
|
|
225
|
+
readonly template: "{prefix}clip combine was called with {inputCount} input block(s) (need at least 2). The owner block was emitted without its clips.";
|
|
226
|
+
};
|
|
227
|
+
readonly CLIP_COMBINE_NOT_COMBINABLE: {
|
|
228
|
+
readonly severity: "warning";
|
|
229
|
+
readonly template: "{prefix}clip combine rejected {inputCount} input block(s) as not combinable (nested or incompatible shapes). The owner block was emitted without its clips.";
|
|
230
|
+
};
|
|
231
|
+
readonly CLIP_COMBINE_THREW: {
|
|
232
|
+
readonly severity: "warning";
|
|
233
|
+
readonly template: "{prefix}clip combine of {inputCount} input block(s) failed ({reason}). The owner block was emitted without its clips.";
|
|
234
|
+
};
|
|
235
|
+
readonly COLOR_TYPE_UNSUPPORTED: {
|
|
236
|
+
readonly severity: "warning";
|
|
237
|
+
readonly template: "{prefix}{subject}color of type \"{colorType}\" is not supported. Rendered as black.";
|
|
238
|
+
};
|
|
239
|
+
readonly COLOR_SPACE_UNSUPPORTED: {
|
|
240
|
+
readonly severity: "warning";
|
|
241
|
+
readonly template: "{prefix}{elementLabel}color space \"{space}\" ({color}) at {bbox} is not supported. Rendered as black.";
|
|
242
|
+
};
|
|
243
|
+
readonly SPOT_COLOR_NO_ALTERNATE: {
|
|
244
|
+
readonly severity: "warning";
|
|
245
|
+
readonly template: "Spot color \"{name}\" has no resolvable alternate; leaving at engine default.";
|
|
246
|
+
};
|
|
247
|
+
readonly SPOT_COLOR_REGISTER_FAILED: {
|
|
248
|
+
readonly severity: "warning";
|
|
249
|
+
readonly template: "Failed to register spot color \"{name}\": {error}";
|
|
250
|
+
};
|
|
251
|
+
readonly VECTOR_PATH_FILL_RULE_UNSUPPORTED: {
|
|
252
|
+
readonly severity: "warning";
|
|
253
|
+
readonly template: "CE.SDK does not expose `{property}` on `vector_path` shapes (added in CE.SDK {sinceVersion}); the source PDF used non-zero winding fill, but imported paths render with the engine default (even-odd) winding. Self-overlapping or compound paths may render with holes inverted. Upgrade `@cesdk/engine` to {sinceVersion} or newer to preserve the source winding rule.";
|
|
254
|
+
};
|
|
255
|
+
readonly BLEND_MODE_UNSUPPORTED: {
|
|
256
|
+
readonly severity: "warning";
|
|
257
|
+
readonly template: "Blend mode \"{mode}\" is not supported. Using \"Normal\" as the default.";
|
|
258
|
+
};
|
|
259
|
+
readonly SHADING_UNRESOLVED: {
|
|
260
|
+
readonly severity: "error";
|
|
261
|
+
readonly template: "{prefix}gradient shading could not be resolved by pdf.js and was removed. The painted region will be missing in the imported scene.";
|
|
262
|
+
};
|
|
263
|
+
readonly SHADING_MESH_UNSUPPORTED: {
|
|
264
|
+
readonly severity: "warning";
|
|
265
|
+
readonly template: "{prefix}gradient shading uses an unsupported mesh variant (PDF ShadingType 4\u20137). The region was dropped because mesh gradients can't be represented as a CE.SDK gradient fill.";
|
|
266
|
+
};
|
|
267
|
+
readonly SHADING_UNKNOWN_IR_TAG: {
|
|
268
|
+
readonly severity: "error";
|
|
269
|
+
readonly template: "{prefix}gradient shading reported unknown IR tag \"{tag}\" and was dropped.";
|
|
270
|
+
};
|
|
271
|
+
readonly SHADING_INSUFFICIENT_STOPS: {
|
|
272
|
+
readonly severity: "warning";
|
|
273
|
+
readonly template: "{prefix}gradient shading produced fewer than two color stops and was dropped.";
|
|
274
|
+
};
|
|
275
|
+
readonly SHADING_NO_CLIP_FALLBACK_BBOX: {
|
|
276
|
+
readonly severity: "info";
|
|
277
|
+
readonly template: "{prefix}gradient shading was painted without an active clip path. Falling back to the shading /BBox; if this scene shows gradient bands outside the intended shape, file a bug.";
|
|
278
|
+
};
|
|
279
|
+
readonly SHADING_CLIP_DEGENERATE: {
|
|
280
|
+
readonly severity: "warning";
|
|
281
|
+
readonly template: "{prefix}gradient shading clip path was degenerate and the region was dropped.";
|
|
282
|
+
};
|
|
283
|
+
readonly SHADING_RADIAL_FOCAL_DROPPED: {
|
|
284
|
+
readonly severity: "info";
|
|
285
|
+
readonly template: "{prefix}radial gradient declared a non-zero inner radius (PDF Shading Type 3 focal point). It was approximated as a centered radial; the focal offset was dropped.";
|
|
286
|
+
};
|
|
287
|
+
readonly SHADING_UNKNOWN_RADIAL_SUBTYPE: {
|
|
288
|
+
readonly severity: "error";
|
|
289
|
+
readonly template: "{prefix}gradient shading reported unknown RadialAxial subtype \"{kind}\" and was dropped.";
|
|
290
|
+
};
|
|
291
|
+
readonly SHADING_NO_PATTERN_REF: {
|
|
292
|
+
readonly severity: "error";
|
|
293
|
+
readonly template: "{prefix}gradient shading was emitted without a pattern reference and was dropped.";
|
|
294
|
+
};
|
|
295
|
+
readonly TILING_PATTERN_AS_IMAGE: {
|
|
296
|
+
readonly severity: "info";
|
|
297
|
+
readonly template: "{prefix}tiling pattern \"{patternId}\" was imported as an image (single-image tiling pattern, e.g. Skia/Chrome PDF export of an embedded bitmap).";
|
|
298
|
+
};
|
|
299
|
+
readonly TILING_PATTERN_UNSUPPORTED: {
|
|
300
|
+
readonly severity: "warning";
|
|
301
|
+
readonly template: "{prefix}tiling pattern \"{patternId}\" contains {imageCount} image XObject(s) and {otherOpCount} other paint op(s); only single-image tiling patterns are imported. The pattern fill was dropped.";
|
|
302
|
+
};
|
|
303
|
+
readonly TILING_PATTERN_UNRESOLVED: {
|
|
304
|
+
readonly severity: "error";
|
|
305
|
+
readonly template: "{prefix}tiling pattern \"{patternId}\" could not be resolved by pdf.js and was dropped.";
|
|
306
|
+
};
|
|
307
|
+
readonly TILING_PATTERN_IMAGE_DECODE_FAILED: {
|
|
308
|
+
readonly severity: "warning";
|
|
309
|
+
readonly template: "{prefix}tiling pattern \"{patternId}\" referenced image \"{imageObjId}\" but the image bytes could not be decoded. The pattern fill was dropped.";
|
|
310
|
+
};
|
|
311
|
+
};
|
|
312
|
+
interface Color {
|
|
313
|
+
space: "rgb" | "cmyk" | "gray";
|
|
314
|
+
/** in [0..1]. rgb:[r,g,b] cmyk:[c,m,y,k] gray:[g] */
|
|
315
|
+
values: number[];
|
|
316
|
+
/** in [0..1]; defaults to 1 */
|
|
317
|
+
alpha?: number;
|
|
318
|
+
}
|
|
319
|
+
type CesdkFontWeight = "thin" | "extraLight" | "light" | "normal" | "medium" | "semiBold" | "bold" | "extraBold" | "heavy";
|
|
320
|
+
interface TextOutline {
|
|
321
|
+
kind: "text-outline";
|
|
322
|
+
/** pt, run bbox top-left */
|
|
323
|
+
x: number;
|
|
324
|
+
y: number;
|
|
325
|
+
width: number;
|
|
326
|
+
height: number;
|
|
327
|
+
/** SVG path data (all glyphs concatenated) */
|
|
328
|
+
d: string;
|
|
329
|
+
/** Original text (for diffing / accessibility) */
|
|
330
|
+
text: string;
|
|
331
|
+
/**
|
|
332
|
+
* Family base parsed from the PDF PostScript name (subset prefix and
|
|
333
|
+
* recognized weight/style/width suffix stripped — e.g.
|
|
334
|
+
* `WTNEYF+Poppins-ExtraBold` → `Poppins`). Falls back to the full
|
|
335
|
+
* subset-stripped name when no recognized suffix is present, so families
|
|
336
|
+
* with internal hyphens like `SVN-BlogScript` survive intact. Suitable
|
|
337
|
+
* as a font-resolver query.
|
|
338
|
+
*/
|
|
339
|
+
fontFamily: string;
|
|
340
|
+
/** pt */
|
|
341
|
+
fontSize: number;
|
|
342
|
+
/** Derived from fontObj.italic + name suffix. */
|
|
343
|
+
fontStyle?: "normal" | "italic";
|
|
344
|
+
/**
|
|
345
|
+
* CE.SDK weight string. Together with `fontStyle` and `fontFamily` lets
|
|
346
|
+
* the font-resolver substitute the correct typeface variant for an
|
|
347
|
+
* editable text block, or — on resolver miss — be preserved as block
|
|
348
|
+
* metadata.
|
|
349
|
+
*/
|
|
350
|
+
fontWeight?: CesdkFontWeight;
|
|
351
|
+
fill: Color | null;
|
|
352
|
+
/**
|
|
353
|
+
* pt, pen x of the first glyph in device coords. Used by the
|
|
354
|
+
* resolver-substitution path to place the editable text block at the
|
|
355
|
+
* generator's setPositionX rather than the ink-bbox left edge (which is
|
|
356
|
+
* shifted by the first glyph's LSB, typically ~1–2pt for caps).
|
|
357
|
+
*/
|
|
358
|
+
textOriginX?: number;
|
|
359
|
+
/**
|
|
360
|
+
* Radians in CE.SDK screen (y-down) frame, 0 for horizontal. Optional;
|
|
361
|
+
* absent on truly horizontal runs. Mirrors the `rotation` field on
|
|
362
|
+
* TextRun so both emit paths can apply `setRotation` from the same
|
|
363
|
+
* source. Sign convention: PDF's y-up Tm rotation atan2(b,a) negated to
|
|
364
|
+
* match CE.SDK's y-down screen frame.
|
|
365
|
+
*/
|
|
366
|
+
rotation?: number;
|
|
367
|
+
/**
|
|
368
|
+
* pt, ink-bbox width in the un-rotated text frame. Equals `width` for
|
|
369
|
+
* horizontal runs; differs for ±90°/180° runs where `width`/`height`
|
|
370
|
+
* describe the rotated AABB.
|
|
371
|
+
*/
|
|
372
|
+
unrotWidth?: number;
|
|
373
|
+
/**
|
|
374
|
+
* pt, ink-bbox height in the un-rotated text frame. Pair with
|
|
375
|
+
* `unrotWidth` to size the editable text block at its natural
|
|
376
|
+
* pre-rotation dimensions; CE.SDK then auto-fits to its own typeface
|
|
377
|
+
* metrics.
|
|
378
|
+
*/
|
|
379
|
+
unrotHeight?: number;
|
|
380
|
+
/**
|
|
381
|
+
* [0..1], default 1. Like `VectorPath.opacity` and `ImageBox.opacity`,
|
|
382
|
+
* lets the emitter apply `setOpacity` to text-outline blocks (the
|
|
383
|
+
* walker uses this for runs that inherited a reduced fill alpha).
|
|
384
|
+
*/
|
|
385
|
+
opacity?: number;
|
|
386
|
+
/**
|
|
387
|
+
* pt, baseline y in device (top-down) coords. Pen origin's y, used by
|
|
388
|
+
* the resolver-substitution path to position the editable text block
|
|
389
|
+
* at the baseline rather than the ink-bbox top.
|
|
390
|
+
*/
|
|
391
|
+
textOriginY?: number;
|
|
392
|
+
}
|
|
393
|
+
interface EmbeddedFont {
|
|
394
|
+
/**
|
|
395
|
+
* Unique per subset. When a PDF embeds multiple subsets that share a PS
|
|
396
|
+
* family name (common: one subset per chapter/page), this field is
|
|
397
|
+
* suffixed with pdf.js's `loadedName` (e.g.
|
|
398
|
+
* `PublicSans-Light#g_d0_f3`) so each subset keeps its own entry in
|
|
399
|
+
* `Document.fonts`. Use `family` for display.
|
|
400
|
+
*/
|
|
401
|
+
postScriptName: string;
|
|
402
|
+
/**
|
|
403
|
+
* Human typeface name from the font's opentype name table (falls back to
|
|
404
|
+
* the PS family name).
|
|
405
|
+
*/
|
|
406
|
+
family: string;
|
|
407
|
+
/** 400 | 700 | 900 (pdf.js bold/black flags) */
|
|
408
|
+
weight?: number;
|
|
409
|
+
style?: "normal" | "italic";
|
|
410
|
+
/**
|
|
411
|
+
* Width-axis label (OS/2 `usWidthClass` mapped to a normalized string,
|
|
412
|
+
* or parsed from the PostScript suffix's width token: `cond`,
|
|
413
|
+
* `extended`, `narrow`, …). Distinguishes condensed-width subsets
|
|
414
|
+
* from normal-width subsets so the merger does not collapse them.
|
|
415
|
+
* Absent when neither source carries width information.
|
|
416
|
+
*/
|
|
417
|
+
width?: string;
|
|
418
|
+
/** Raw TTF/OTF bytes */
|
|
419
|
+
data: Uint8Array;
|
|
420
|
+
/** 'font/otf' | 'font/ttf' */
|
|
421
|
+
mimeType: string;
|
|
422
|
+
}
|
|
423
|
+
interface ColorSpan {
|
|
424
|
+
from: number;
|
|
425
|
+
to: number;
|
|
426
|
+
fill: Color | null;
|
|
427
|
+
}
|
|
428
|
+
interface StyleSpan {
|
|
429
|
+
from: number;
|
|
430
|
+
to: number;
|
|
431
|
+
/** PostScript name from the originating run. */
|
|
432
|
+
fontRef: string;
|
|
433
|
+
/** CSS 100..900; matches `EmbeddedFont.weight`. */
|
|
434
|
+
fontWeight?: number;
|
|
435
|
+
/** Matches `EmbeddedFont.style`. */
|
|
436
|
+
fontStyle?: "normal" | "italic";
|
|
437
|
+
}
|
|
438
|
+
interface TextRun {
|
|
439
|
+
kind: "text-run";
|
|
440
|
+
/** pt, unrotated bbox top-left */
|
|
441
|
+
x: number;
|
|
442
|
+
/** pt */
|
|
443
|
+
y: number;
|
|
444
|
+
/** pt (with a small advance padding) */
|
|
445
|
+
width: number;
|
|
446
|
+
/** pt (ascender - descender, scaled by fontSize) */
|
|
447
|
+
height: number;
|
|
448
|
+
/** Rendered string (Unicode, not glyph codes) */
|
|
449
|
+
text: string;
|
|
450
|
+
/** postScriptName; resolves via Document.fonts */
|
|
451
|
+
fontRef: string;
|
|
452
|
+
/**
|
|
453
|
+
* Logical font family (subset prefix + weight/style suffix stripped),
|
|
454
|
+
* mirroring `EmbeddedFont.family`. Populated by `text-items.ts` from
|
|
455
|
+
* the resolved EmbeddedFont so `postprocess-text.ts::canGroup` can
|
|
456
|
+
* decide whether two distinct `fontRef`s (e.g. `Helvetica` +
|
|
457
|
+
* `Helvetica-Bold`) belong to the same logical typeface and should
|
|
458
|
+
* merge into one block with `styleSpans`. Absent on legacy inputs
|
|
459
|
+
* (synthetic IR, older callers) — `canGroup` then falls back to the
|
|
460
|
+
* stricter `fontRef === fontRef` test and keeps the runs split.
|
|
461
|
+
*/
|
|
462
|
+
family?: string;
|
|
463
|
+
/**
|
|
464
|
+
* CSS 100..900, mirroring `EmbeddedFont.weight`. Used as the per-run
|
|
465
|
+
* weight contribution when the merger bridges variants of the same
|
|
466
|
+
* `family`. Absent on legacy inputs (merger then refuses to merge
|
|
467
|
+
* across `fontRef` mismatches — see `family`).
|
|
468
|
+
*/
|
|
469
|
+
fontWeight?: number;
|
|
470
|
+
/** Mirrors `EmbeddedFont.style`. Pairs with `fontWeight`. */
|
|
471
|
+
fontStyle?: "normal" | "italic";
|
|
472
|
+
/**
|
|
473
|
+
* Width-axis label, mirroring `EmbeddedFont.width`. Distinguishes
|
|
474
|
+
* `Helvetica-Condensed` from `Helvetica-Regular` so the merger does
|
|
475
|
+
* not collapse them — CE.SDK's per-range setters (`setTextFontWeight`,
|
|
476
|
+
* `setTextFontStyle`) have no width parameter and would silently
|
|
477
|
+
* render condensed glyphs at normal width.
|
|
478
|
+
*
|
|
479
|
+
* Values follow OS/2 `usWidthClass` semantics, normalized to a small
|
|
480
|
+
* string set: `'ultraCondensed' | 'extraCondensed' | 'condensed' |
|
|
481
|
+
* 'semiCondensed' | 'normal' | 'semiExpanded' | 'expanded' |
|
|
482
|
+
* 'extraExpanded' | 'ultraExpanded'`. Absent on legacy inputs.
|
|
483
|
+
*/
|
|
484
|
+
fontWidth?: string;
|
|
485
|
+
/** pt */
|
|
486
|
+
fontSize: number;
|
|
487
|
+
/**
|
|
488
|
+
* Radians, 0 for horizontal text. x/y place the block so rotation around
|
|
489
|
+
* its center matches the PDF.
|
|
490
|
+
*/
|
|
491
|
+
rotation: number;
|
|
492
|
+
fill: Color | null;
|
|
493
|
+
/**
|
|
494
|
+
* pt, pen origin x in PDF view-frame (top-left origin), pre-pivot-comp.
|
|
495
|
+
* Populated by `text-items.ts`; used by `groupLineRuns` to test
|
|
496
|
+
* pen-origin continuity between runs that pdf.js split mid-line for
|
|
497
|
+
* kerning.
|
|
498
|
+
*/
|
|
499
|
+
baselineXPt?: number;
|
|
500
|
+
/** pt, pen origin y, same frame. */
|
|
501
|
+
baselineYPt?: number;
|
|
502
|
+
/**
|
|
503
|
+
* pt, raw along-baseline advance from pdf.js (`item.width`). Distinct
|
|
504
|
+
* from `width`, which carries a small rendering padding that is
|
|
505
|
+
* intentionally invisible to merger logic.
|
|
506
|
+
*/
|
|
507
|
+
advanceWidthPt?: number;
|
|
508
|
+
/**
|
|
509
|
+
* Per-character (UTF-16) color ranges within `text`. Set by `mergeRuns`
|
|
510
|
+
* only when constituent runs differ in fill; absent for single-run
|
|
511
|
+
* blocks and for merged groups with uniform fill (back-compat). Range
|
|
512
|
+
* indices match `engine.block.setTextColor(id, color, from, to)`'s
|
|
513
|
+
* contract.
|
|
514
|
+
*/
|
|
515
|
+
colorSpans?: ColorSpan[];
|
|
516
|
+
/**
|
|
517
|
+
* Per-character (UTF-16) weight/style ranges within `text`. Set by
|
|
518
|
+
* `mergeRuns` only when the merger bridged adjacent same-family runs
|
|
519
|
+
* that use different weight/style variants (e.g. inline bold inside a
|
|
520
|
+
* paragraph). Absent for single-run blocks and for merged groups with
|
|
521
|
+
* uniform variant. Range indices match `engine.block.setTextFontWeight
|
|
522
|
+
* (id, weight, from, to)` / `setTextFontStyle(id, style, from, to)`.
|
|
523
|
+
*/
|
|
524
|
+
styleSpans?: StyleSpan[];
|
|
525
|
+
/**
|
|
526
|
+
* Lazy builder for the run's glyph outline as a vector path. Captures
|
|
527
|
+
* the walker's pending run + glyph + font references; invoked by
|
|
528
|
+
* `emit/cesdk.ts::emitGlyphsAsVectorPath` only when the font-strategy
|
|
529
|
+
* cascade returns null and emission needs a fallback. Returns the SVG
|
|
530
|
+
* `d` plus bbox geometry, or null when path extraction is unavailable
|
|
531
|
+
* (Type 3 glyph charproc missing, opentype parse failure).
|
|
532
|
+
*
|
|
533
|
+
* Populated by `text-items.ts::extractTextRuns` from a per-BT/ET queue
|
|
534
|
+
* stashed by the walker (`placeholder._lazyGlyphOutlines`). Holds
|
|
535
|
+
* references — discarded when the IR is GC'd after emit. Builder is
|
|
536
|
+
* called at most once per run (cascade-null is rare for asset-library
|
|
537
|
+
* coverage).
|
|
538
|
+
*/
|
|
539
|
+
_buildGlyphOutline?: () => GlyphOutlineData | null;
|
|
540
|
+
}
|
|
541
|
+
interface GlyphOutlineData {
|
|
542
|
+
/** SVG path data in local bbox coordinates (top-left origin). */
|
|
543
|
+
d: string;
|
|
544
|
+
/** pt, bbox top-left in page coords. */
|
|
545
|
+
x: number;
|
|
546
|
+
/** pt */
|
|
547
|
+
y: number;
|
|
548
|
+
/** pt */
|
|
549
|
+
width: number;
|
|
550
|
+
/** pt */
|
|
551
|
+
height: number;
|
|
552
|
+
}
|
|
553
|
+
/**
|
|
554
|
+
* Per-run input to the cascade and emission layers. Built by
|
|
555
|
+
* `lib/make-request.ts` from the source IR block (either `TextRun` or
|
|
556
|
+
* `TextOutline`).
|
|
557
|
+
*
|
|
558
|
+
* Vector-outline data has two shapes depending on source kind:
|
|
559
|
+
* - `TextOutline` sources carry `glyphPaths` eagerly (the walker built
|
|
560
|
+
* the path because the font wasn't embeddable — Type 3 / restricted /
|
|
561
|
+
* PUA).
|
|
562
|
+
* - `TextRun` sources carry `buildGlyphOutline`, a lazy builder set up
|
|
563
|
+
* by the walker + text-items pairing. Emission only invokes it when
|
|
564
|
+
* the cascade returns null and a vector fallback is needed — most
|
|
565
|
+
* documents have asset-library coverage and never call it.
|
|
566
|
+
*/
|
|
567
|
+
export interface FontRequest {
|
|
568
|
+
/** Display family (subset prefix stripped). */
|
|
569
|
+
family: string;
|
|
570
|
+
style: "normal" | "italic";
|
|
571
|
+
weight: Font["weight"];
|
|
572
|
+
/** Original text content; preserved for metadata + recovery. */
|
|
573
|
+
text: string;
|
|
574
|
+
/** Embedded subset bytes — present when the source was a TextRun. */
|
|
575
|
+
embeddedFont?: EmbeddedFont;
|
|
576
|
+
/** Concatenated glyph paths in local coords — present when the source was a TextOutline. */
|
|
577
|
+
glyphPaths?: string;
|
|
578
|
+
/** Lazy glyph-outline builder (TextRun sources). Built by walker;
|
|
579
|
+
* invoked at most once by emission when the cascade returns null. */
|
|
580
|
+
buildGlyphOutline?: () => GlyphOutlineData | null;
|
|
581
|
+
/** Original IR block — used by emission for geometry, fills, rotation, etc. */
|
|
582
|
+
source: TextRun | TextOutline;
|
|
583
|
+
}
|
|
584
|
+
export type CascadeResolution = {
|
|
585
|
+
kind: "typeface";
|
|
586
|
+
typeface: Typeface;
|
|
587
|
+
font?: Font;
|
|
588
|
+
/** Identifies which stage produced this resolution. */
|
|
589
|
+
provenance: string;
|
|
590
|
+
/** Forwarded from `FontResolverResult.substitutedFrom`. When set, the
|
|
591
|
+
* emission layer treats the resolution as substituted and recomputes
|
|
592
|
+
* layout. */
|
|
593
|
+
substitutedFrom?: string;
|
|
594
|
+
} | {
|
|
595
|
+
kind: "subset";
|
|
596
|
+
embeddedFont: EmbeddedFont;
|
|
597
|
+
provenance: "embedded-subset";
|
|
598
|
+
};
|
|
599
|
+
/**
|
|
600
|
+
* Stage outcome. Distinguishing "pass with reason" from `null` lets debug
|
|
601
|
+
* logs explain *why* the cascade reached a given stage's neighbour. Cheap
|
|
602
|
+
* to carry now; expensive to retrofit.
|
|
603
|
+
*/
|
|
604
|
+
export type StageOutcome = CascadeResolution | {
|
|
605
|
+
kind: "pass";
|
|
606
|
+
reason: string;
|
|
607
|
+
};
|
|
608
|
+
interface CascadeLogger {
|
|
609
|
+
emit?: (code: string, params: Record<string, unknown>) => void;
|
|
610
|
+
log?: (message: string, level?: string) => void;
|
|
611
|
+
}
|
|
612
|
+
export interface FontStageContext {
|
|
613
|
+
engine: CreativeEngine;
|
|
614
|
+
resolver: TypefaceResolver | null;
|
|
615
|
+
/**
|
|
616
|
+
* Per-import-call cache. Same `family|style|weight` resolves once per
|
|
617
|
+
* `PDFParser.fromFile` invocation; reopening the PDF produces a fresh
|
|
618
|
+
* cache. Created in the parser entry, discarded on completion.
|
|
619
|
+
*/
|
|
620
|
+
resolverCache: Map<string, FontResolverResult | null>;
|
|
621
|
+
logger: CascadeLogger | null;
|
|
622
|
+
}
|
|
623
|
+
export interface FontStage {
|
|
624
|
+
/** Stable identifier for logs and tests. */
|
|
625
|
+
readonly name: string;
|
|
626
|
+
resolve(req: FontRequest, ctx: FontStageContext): Promise<StageOutcome>;
|
|
627
|
+
}
|
|
628
|
+
export interface FontCascade {
|
|
629
|
+
readonly stages: readonly FontStage[];
|
|
630
|
+
resolve(req: FontRequest, ctx: FontStageContext): Promise<CascadeResolution | null>;
|
|
631
|
+
}
|
|
632
|
+
/**
|
|
633
|
+
* Result of a single emission call. The emission layer may produce zero,
|
|
634
|
+
* one, or more blocks; the `blocks` array is in z-order (back to front).
|
|
635
|
+
* `substituted` is true when the cascade's answer triggered a
|
|
636
|
+
* substitution that the dispatcher should account against the
|
|
637
|
+
* per-import substitution-count log.
|
|
638
|
+
*/
|
|
639
|
+
export interface EmissionResult {
|
|
640
|
+
/** CE.SDK block ids created. Empty array means the run was skipped. */
|
|
641
|
+
blocks: number[];
|
|
642
|
+
/** True when the resolution involved a font substitution. */
|
|
643
|
+
substituted: boolean;
|
|
644
|
+
/** Display name of the typeface the run resolved to, if any. */
|
|
645
|
+
resolvedFamily?: string;
|
|
646
|
+
}
|
|
647
|
+
/**
|
|
648
|
+
* Block-creation primitives that emission delegates to. The dispatcher
|
|
649
|
+
* fills these in so emission stays decoupled from `engine.block.*` and
|
|
650
|
+
* from the geometry helpers that already live in `emit/cesdk.ts`. Keeps
|
|
651
|
+
* the emission policy testable in isolation: each callback can be
|
|
652
|
+
* stubbed.
|
|
653
|
+
*/
|
|
654
|
+
export interface EmissionHelpers {
|
|
655
|
+
/**
|
|
656
|
+
* Create an editable text block with the request's geometry and the
|
|
657
|
+
* caller-supplied `applyFont` callback (called between layout and
|
|
658
|
+
* properties — order matters for CE.SDK's `replaceText` wrap-marker).
|
|
659
|
+
* `layoutIr` may be the original block or a typeface-aware substitute
|
|
660
|
+
* (see `resolveLayoutForSubstitution` below).
|
|
661
|
+
*/
|
|
662
|
+
createEditableText(req: FontRequest, layoutIr: TextOutline | TextRun, applyFont: (engine: CreativeEngine, block: number) => void): number;
|
|
663
|
+
/**
|
|
664
|
+
* Emit the request's `glyphPaths` as a `vector_path` graphic block at
|
|
665
|
+
* the source bbox. Returns null when the request carries no
|
|
666
|
+
* `glyphPaths` (TextRun source).
|
|
667
|
+
*/
|
|
668
|
+
emitGlyphsAsVectorPath(req: FontRequest): number | null;
|
|
669
|
+
/**
|
|
670
|
+
* Compute the layout-aware IR for a substituted typeface. For TextRun
|
|
671
|
+
* sources this is a no-op (returns `req.source`); for TextOutline
|
|
672
|
+
* sources it derives the unrotated bbox CE.SDK needs using the
|
|
673
|
+
* substitute's font metrics.
|
|
674
|
+
*/
|
|
675
|
+
resolveLayoutForSubstitution(req: FontRequest, resolution: CascadeResolution): Promise<TextOutline | TextRun>;
|
|
676
|
+
}
|
|
677
|
+
export interface EmissionContext {
|
|
678
|
+
engine: CreativeEngine;
|
|
679
|
+
logger: CascadeLogger | null;
|
|
680
|
+
/** Page index (1-based) for diagnostic context. */
|
|
681
|
+
pageIndex?: number;
|
|
682
|
+
helpers: EmissionHelpers;
|
|
683
|
+
}
|
|
684
|
+
export interface FontEmission {
|
|
685
|
+
readonly name: string;
|
|
686
|
+
emit(req: FontRequest, resolution: CascadeResolution | null, ctx: EmissionContext): Promise<EmissionResult>;
|
|
687
|
+
}
|
|
688
|
+
export interface FontStrategy {
|
|
689
|
+
readonly cascade: FontCascade;
|
|
690
|
+
readonly emission: FontEmission;
|
|
691
|
+
}
|
|
692
|
+
export declare const perfectMatchResolverStage: FontStage;
|
|
693
|
+
export declare const embeddedSubsetStage: FontStage;
|
|
694
|
+
export declare const anyMatchResolverStage: FontStage;
|
|
695
|
+
export declare const defaultEmission: FontEmission;
|
|
696
|
+
/**
|
|
697
|
+
* Build a cascade from an ordered list of stages. The cascade walks the
|
|
698
|
+
* list and returns the first non-pass outcome. When every stage passes,
|
|
699
|
+
* the cascade returns `null` (emission decides what to do).
|
|
700
|
+
*/
|
|
701
|
+
export declare function createFontCascade(stages: FontStage[]): FontCascade;
|
|
702
|
+
interface FontStrategyDef {
|
|
703
|
+
cascade: FontCascade;
|
|
704
|
+
emission: FontEmission;
|
|
705
|
+
}
|
|
706
|
+
export declare function createFontStrategy(def: FontStrategyDef): FontStrategy;
|
|
707
|
+
/**
|
|
708
|
+
* Default for `PDFParser.fromFile({ fontStrategy })`. Embedded subset
|
|
709
|
+
* bytes are used as an intermediate fallback to preserve the source's
|
|
710
|
+
* exact rendering when the family isn't in the asset library — vector
|
|
711
|
+
* outline extraction can produce incorrect bboxes or partial glyph
|
|
712
|
+
* coverage for some fonts, while the engine renders subset bytes
|
|
713
|
+
* faithfully.
|
|
714
|
+
*
|
|
715
|
+
* - Run's family resolves perfectly in the asset library →
|
|
716
|
+
* perfect-match typeface (HTTPS URI).
|
|
717
|
+
* - Embedded subset present (TextRun source) → register the bytes and
|
|
718
|
+
* emit as editable text with `setFont`. The resulting scene depends
|
|
719
|
+
* on the bytes living in a `buffer://` URI; this is the offline-safe
|
|
720
|
+
* path.
|
|
721
|
+
* - Otherwise → any-match resolver (possibly substituted via the
|
|
722
|
+
* fallbacks source; a per-import warning summarizes substitutions).
|
|
723
|
+
* - Neither hits → cascade returns null → emission falls through to a
|
|
724
|
+
* vector outline (TextOutline-source runs always have glyph paths;
|
|
725
|
+
* TextRun-source runs use the Phase-2 lazy closure built by the
|
|
726
|
+
* walker).
|
|
727
|
+
*
|
|
728
|
+
* For tools that explicitly want vectorization over subset bytes
|
|
729
|
+
* (e.g. brand-locked editors), use `assetLibraryStrategy`.
|
|
730
|
+
*/
|
|
731
|
+
export declare const editableFirstStrategy: FontStrategy;
|
|
732
|
+
/**
|
|
733
|
+
* For print finalization, PDF-viewer-style integrations, and anywhere a
|
|
734
|
+
* silent Helvetica → Roboto substitution is unacceptable. Skips
|
|
735
|
+
* `anyMatchResolverStage`; non-embeddable runs without a perfect match
|
|
736
|
+
* fall through to vector outline.
|
|
737
|
+
*/
|
|
738
|
+
export declare const exactFidelityStrategy: FontStrategy;
|
|
739
|
+
/**
|
|
740
|
+
* For brand-locked tools: every editable text must come from the asset
|
|
741
|
+
* library (or the resolver's alias fallbacks). Drops the subset stage so
|
|
742
|
+
* PDF-embedded subset bytes never leak through; runs whose family isn't
|
|
743
|
+
* in the library go straight to the any-match resolver.
|
|
744
|
+
*/
|
|
745
|
+
export declare const assetLibraryStrategy: FontStrategy;
|
|
746
|
+
export declare const defaultStrategy: FontStrategy;
|
|
747
|
+
type PageBounds = "trim" | "media";
|
|
748
|
+
type PdfLogger = Logger<typeof WARNING_CODES>;
|
|
749
|
+
export declare class PDFParser {
|
|
750
|
+
private engine;
|
|
751
|
+
private pdfBytes;
|
|
752
|
+
private fontResolver;
|
|
753
|
+
private fontStrategy;
|
|
754
|
+
private pageBounds;
|
|
755
|
+
private logger;
|
|
756
|
+
private ir?;
|
|
757
|
+
private constructor();
|
|
758
|
+
/**
|
|
759
|
+
* Create a PDFParser instance from a PDF file.
|
|
760
|
+
*
|
|
761
|
+
* @param engine - CE.SDK engine instance
|
|
762
|
+
* @param file - PDF file as Blob, File, or ArrayBuffer
|
|
763
|
+
* @param options - Optional configuration
|
|
764
|
+
* @param options.fontResolver - Custom font resolver. Invoked by the
|
|
765
|
+
* cascade's resolver-using stages (`perfectMatchResolverStage`,
|
|
766
|
+
* `anyMatchResolverStage`). Requires `addGfontsAssetLibrary` to be
|
|
767
|
+
* called on the engine before parse.
|
|
768
|
+
* @param options.fontStrategy - Strategy controlling how text runs
|
|
769
|
+
* become blocks. Default: `editableFirstStrategy` — prefers a perfect
|
|
770
|
+
* asset-library match, falls back to the PDF-embedded subset, then to
|
|
771
|
+
* resolver substitution (any-match), and finally to vector outline
|
|
772
|
+
* when nothing else hits. Other shipped presets:
|
|
773
|
+
* `exactFidelityStrategy` (never substitute), `assetLibraryStrategy`
|
|
774
|
+
* (drop subset). Build custom strategies with `createFontStrategy({
|
|
775
|
+
* cascade, emission })`. See `packages/pdf-importer/CLAUDE.md` →
|
|
776
|
+
* "Font resolution" for the mental model and offline-safe recipe.
|
|
777
|
+
* @returns A new PDFParser instance
|
|
778
|
+
*/
|
|
779
|
+
static fromFile(engine: CreativeEngine, file: Blob | File | ArrayBuffer, options?: {
|
|
780
|
+
fontResolver?: TypefaceResolver;
|
|
781
|
+
fontStrategy?: FontStrategy;
|
|
782
|
+
/**
|
|
783
|
+
* Which PDF page box the emitted CE.SDK pages are sized to. Defaults
|
|
784
|
+
* to `"trim"` (designed page + bleed margin, the end-user view).
|
|
785
|
+
* `"media"` keeps pages at MediaBox (aka `page.view`) dimensions
|
|
786
|
+
* with children unshifted — used by the regression pixel-diff harness
|
|
787
|
+
* so CE.SDK exports match `pdftoppm`'s full-MediaBox reference images.
|
|
788
|
+
*/
|
|
789
|
+
pageBounds?: PageBounds;
|
|
790
|
+
}): Promise<PDFParser>;
|
|
791
|
+
/**
|
|
792
|
+
* @deprecated Use options object instead: `fromFile(engine, file, { fontResolver })`
|
|
793
|
+
*/
|
|
794
|
+
static fromFile(engine: CreativeEngine, file: Blob | File | ArrayBuffer, fontResolver?: TypefaceResolver): Promise<PDFParser>;
|
|
795
|
+
/**
|
|
796
|
+
* Parse the PDF file and emit a CE.SDK scene with all pages.
|
|
797
|
+
*
|
|
798
|
+
* Pipeline: pdf.js → IR (`extractDocument`) → line-run grouping →
|
|
799
|
+
* CE.SDK scene (`emitInto`). Text extraction always produces full text
|
|
800
|
+
* blocks: one block per line from pdf.js `getTextContent`, with adjacent
|
|
801
|
+
* lines that share font/size and horizontal overlap merged into a single
|
|
802
|
+
* multi-line block.
|
|
803
|
+
*
|
|
804
|
+
* Mirrors `engine.scene.loadFromString`: replaces the engine's current
|
|
805
|
+
* scene with the imported PDF.
|
|
806
|
+
*
|
|
807
|
+
* @returns Parse result containing the scene ID and logger
|
|
808
|
+
*/
|
|
809
|
+
parse(): Promise<{
|
|
810
|
+
scene: number;
|
|
811
|
+
logger: PdfLogger;
|
|
812
|
+
}>;
|
|
813
|
+
/**
|
|
814
|
+
* Parse the PDF and return the imported pages as detached CE.SDK blocks.
|
|
815
|
+
*
|
|
816
|
+
* Mirrors `engine.block.loadFromString`: returned blocks are NOT attached
|
|
817
|
+
* to a scene. Caller appends and positions them however they want.
|
|
818
|
+
*
|
|
819
|
+
* Each PDF page yields one returned `page` block, sized to the PDF's
|
|
820
|
+
* MediaBox in inches with the page's content as children. CE.SDK pages
|
|
821
|
+
* are the right wrapper here — `setWidth`/`setHeight` scales children
|
|
822
|
+
* proportionally (so callers can fit a PDF page into an arbitrary host
|
|
823
|
+
* frame), and pages clip to their bounds (matching IDML's frame
|
|
824
|
+
* semantics when content overflows).
|
|
825
|
+
*
|
|
826
|
+
* @param options
|
|
827
|
+
* @param options.pageIndex 0-based page to load. Omit to load all pages
|
|
828
|
+
* (returns one block per page, in document order).
|
|
829
|
+
* @returns Detached page block IDs (length 1 for single-page mode,
|
|
830
|
+
* `pdf.numPages` for all-pages mode), plus the logger so callers can
|
|
831
|
+
* forward parser warnings into their own diagnostic stream.
|
|
832
|
+
*/
|
|
833
|
+
loadAsBlocks(options?: {
|
|
834
|
+
pageIndex?: number;
|
|
835
|
+
}): Promise<{
|
|
836
|
+
blocks: number[];
|
|
837
|
+
logger: PdfLogger;
|
|
838
|
+
}>;
|
|
839
|
+
/**
|
|
840
|
+
* Number of pages in the PDF document.
|
|
841
|
+
*
|
|
842
|
+
* Triggers a full IR extraction on first call (the same work `parse` /
|
|
843
|
+
* `loadAsBlocks` does), then caches it. Subsequent calls — including
|
|
844
|
+
* `parse` and `loadAsBlocks` themselves — reuse the cached IR.
|
|
845
|
+
*/
|
|
846
|
+
getPageCount(): Promise<number>;
|
|
847
|
+
/**
|
|
848
|
+
* Get the logger for this parser instance.
|
|
849
|
+
*/
|
|
850
|
+
getLogger(): PdfLogger;
|
|
851
|
+
private ensureIR;
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
export {};
|