// Generated by dts-bundle-generator v9.5.1 import CreativeEngine from '@cesdk/engine'; import { AssetAPI, Font, FontStyle, FontWeight, Typeface } from '@cesdk/engine'; type WarningSeverity = "error" | "warning" | "info"; interface WarningDefinition { /** Default + sole severity. Call sites do not override. */ severity: WarningSeverity; /** * Template with `{name}` placeholders. Renderer throws if a placeholder * has no matching key in `params` — guards against silent typos. */ template: string; } interface LogMessage { /** Stable machine-readable identifier — never rename once shipped. */ code: TCode; /** Inherited from the code definition. */ type: WarningSeverity; /** Human-readable rendered string. */ message: string; /** Raw structured fields — superset of all `{name}` placeholders. */ params: Record; } /** * Generic structured logger. Severity is registry-driven (PostgreSQL * SQLSTATE pattern) — call sites cannot override. To change severity, * edit the registry. */ export declare class Logger> { private readonly registry; private messages; constructor(registry: R); emit(code: K, params?: Record): void; getMessages(): LogMessage[]; } type AssetQueryAPI = Pick; type AssetEngine = { asset: AssetQueryAPI; }; interface TypefaceParams { family: string; style?: Font["style"]; weight?: Font["weight"]; } interface FontResolverOptions { /** * When the requested weight is not available in the matched typeface, * pick the closest available weight using the CSS Font Matching algorithm. * Defaults to false — return null instead so the caller can decide what * to do (e.g. log a warning, use a different font). * * Only enable when the typeface name is known to be a good match. The * typeface query uses fuzzy matching, so applying weight fallback to a * poor name match can silently produce wildly wrong results. */ closestWeightMatch?: boolean; } interface FontResolverResult { typeface: Typeface; font: Font; /** * Set to the originally requested family name when the typeface came from * the proprietary-fallbacks source (e.g. requested "Helvetica", got Roboto). * Undefined when the family matched the main Google Fonts catalog directly. * Always populated when applicable; consumers may ignore it. */ substitutedFrom?: string; } type TypefaceResolver = (params: TypefaceParams, engine: AssetEngine, options?: FontResolverOptions) => Promise; /** * Register the @imgly/gfonts asset sources (Google Fonts catalog + proprietary * font fallbacks) with the CE.SDK engine. * * Adds two sources: * - `ly.img.gfonts` — 1,394 Google Fonts typefaces (fuzzy-matched). * - `ly.img.gfonts-fallbacks` — 16 proprietary-font alias entries * (e.g. Helvetica → Roboto), strict-matched. */ export declare function addGfontsAssetLibrary(engine: AssetEngine): Promise; declare const WARNING_CODES: { readonly DOC_PAGE_COUNT: { readonly severity: "info"; readonly template: "PDF has {count} page(s)"; }; readonly DOC_PAGE_BLOCK_COUNT: { readonly severity: "info"; readonly template: "Page {page}: {imageCount} image, {vectorCount} vector, {textCount} text, {outlineCount} outline"; }; readonly DOC_PAGE_ROTATION_DROPPED: { readonly severity: "warning"; 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."; }; readonly BLOCK_KIND_UNKNOWN: { readonly severity: "error"; readonly template: "An unknown block kind \"{kind}\" was encountered and was skipped."; }; readonly PAGE_INDEX_OUT_OF_RANGE: { readonly severity: "warning"; readonly template: "Requested page index {requested} is out of range; PDF has {available} page(s). No blocks were emitted."; }; readonly FONT_OPENTYPE_PARSE_FAILED: { readonly severity: "warning"; 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."; }; readonly FONT_CMAP_AUGMENTED: { readonly severity: "info"; readonly template: "Font \"{fontName}\" character map was augmented (cmap patches={cmapPatches}, injected glyphs={injectedGlyphs})."; }; readonly FONT_CMAP_AUGMENT_FAILED: { readonly severity: "warning"; readonly template: "Font \"{fontName}\" character map could not be augmented. Using the original font data \u2014 some glyphs may render incorrectly."; }; readonly FONT_RESOLVER_MISS: { readonly severity: "warning"; readonly template: "Font \"{fontFamily}\" could not be resolved. The text was rendered as a vector outline."; }; readonly FONT_NOT_FOUND_IN_ASSETS: { readonly severity: "warning"; readonly template: "Font \"{fontFamily}\" was not found in the asset library. The text was rendered as a vector outline."; }; readonly FONT_SUBSTITUTED: { readonly severity: "info"; readonly template: "Font \"{fontFamily}\" was substituted with \"{substitutedName}\" from the asset library."; }; readonly FONT_REF_NOT_EXTRACTED: { readonly severity: "error"; readonly template: "Text run references font \"{fontRef}\" which was not extracted. The text was skipped."; }; readonly FONT_SUBSTITUTIONS: { readonly severity: "warning"; readonly template: "Substituted {count} font famil{plural} during import: {pairs}."; }; readonly FONT_SUBSET_FALLBACK: { readonly severity: "warning"; readonly template: string; }; readonly TEXT_OUTLINE_NO_FONT_FAMILY: { readonly severity: "warning"; readonly template: "Text outline has no declared font family. The run was skipped."; }; readonly TEXT_RUN_SKIPPED_NO_RESOLUTION: { readonly severity: "warning"; readonly template: "No typeface or glyph outlines for \"{fontFamily}\"; run skipped."; }; readonly TEXT_RENDER_MODE_SKIPPED: { readonly severity: "warning"; 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."; }; readonly TEXT_OVERFLOW_AFTER_AUTOSIZE: { readonly severity: "warning"; 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."; }; readonly TEXT_CLIP_MODE_7_DROPPED: { readonly severity: "warning"; 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."; }; readonly IMAGE_ENCODER_MISS: { readonly severity: "warning"; 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."; }; readonly IMAGE_PDFJS_UNRESOLVED: { readonly severity: "error"; 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."; }; readonly IMAGE_NO_PIXELS: { readonly severity: "warning"; readonly template: "An image element has no pixel data and was skipped."; }; readonly IMAGE_FLIP_UNSUPPORTED: { readonly severity: "warning"; readonly template: "Image flip could not be applied (engine version too old). The image will display without flip."; }; readonly IMAGE_PLACEMENT_UNSUPPORTED: { readonly severity: "warning"; readonly template: "Image placement could not be applied (engine version too old). The image will be scaled evenly to cover its box and can be cut off."; }; readonly IMAGE_SKEW_DROPPED: { readonly severity: "warning"; 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."; }; readonly IMAGE_CLIPPED_NO_BYTES: { readonly severity: "warning"; readonly template: "{prefix}a clipped image at {bbox} had no decoded bytes; the placement was dropped before combining clip shapes."; }; readonly IMAGE_CLIP_UNUSABLE: { readonly severity: "warning"; 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."; }; readonly IMAGE_CLIPPED_TO_EMPTY: { readonly severity: "info"; readonly template: "{prefix}a clipped image at {bbox} with {clipCount} clip path(s) lies entirely outside its clip region ({disjointCount} clip path(s) disjoint from the image); the source draws nothing there, so the placement was skipped."; }; readonly IMAGE_CLIP_EMPTY_INTERSECTION: { readonly severity: "warning"; readonly template: "{prefix}a clipped image at {bbox} with {clipCount} clip path(s) had an empty intersection. The image was dropped."; }; readonly IMAGE_CLIP_COMBINE_FAILED: { readonly severity: "error"; 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."; }; readonly IMAGE_MASK_NO_FILL_COLOR: { readonly severity: "warning"; 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."; }; readonly IMAGE_MASK_COMPOSITE_FAIL: { readonly severity: "warning"; 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."; }; readonly IMAGE_MASK_GROUP_UNSUPPORTED: { readonly severity: "warning"; readonly template: "{prefix}a paintImageMaskXObjectGroup batch of {count} stencil paints is not supported by the importer. The masks were dropped."; }; readonly IMAGE_MASK_REPEAT_UNSUPPORTED: { readonly severity: "warning"; readonly template: "{prefix}a paintImageMaskXObjectRepeat tiling {count} stencil paints is not supported by the importer. The masks were dropped."; }; readonly CLIP_DEGENERATE_FALLBACK: { readonly severity: "warning"; 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."; }; readonly CLIP_COMBINE_STROKE_ONLY: { readonly severity: "warning"; 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."; }; readonly CLIP_COMBINE_FAILED: { readonly severity: "warning"; 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."; }; readonly CLIP_COMBINE_TOO_FEW_INPUTS: { readonly severity: "warning"; readonly template: "{prefix}clip combine was called with {inputCount} input block(s) (need at least 2). The owner block was emitted without its clips."; }; readonly CLIP_COMBINE_NOT_COMBINABLE: { readonly severity: "warning"; 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."; }; readonly CLIP_COMBINE_THREW: { readonly severity: "warning"; readonly template: "{prefix}clip combine of {inputCount} input block(s) failed ({reason}). The owner block was emitted without its clips."; }; readonly COLOR_TYPE_UNSUPPORTED: { readonly severity: "warning"; readonly template: "{prefix}{subject}color of type \"{colorType}\" is not supported. Rendered as black."; }; readonly COLOR_SPACE_UNSUPPORTED: { readonly severity: "warning"; readonly template: "{prefix}{elementLabel}color space \"{space}\" ({color}) at {bbox} is not supported. Rendered as black."; }; readonly SPOT_COLOR_NO_ALTERNATE: { readonly severity: "warning"; readonly template: "Spot color \"{name}\" has no resolvable alternate; leaving at engine default."; }; readonly SPOT_COLOR_REGISTER_FAILED: { readonly severity: "warning"; readonly template: "Failed to register spot color \"{name}\": {error}"; }; readonly VECTOR_PATH_FILL_RULE_UNSUPPORTED: { readonly severity: "warning"; 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."; }; readonly BLEND_MODE_UNSUPPORTED: { readonly severity: "warning"; readonly template: "Blend mode \"{mode}\" is not supported. Using \"Normal\" as the default."; }; readonly SHADING_UNRESOLVED: { readonly severity: "error"; 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."; }; readonly SHADING_MESH_UNSUPPORTED: { readonly severity: "warning"; 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."; }; readonly SHADING_UNKNOWN_IR_TAG: { readonly severity: "error"; readonly template: "{prefix}gradient shading reported unknown IR tag \"{tag}\" and was dropped."; }; readonly SHADING_INSUFFICIENT_STOPS: { readonly severity: "warning"; readonly template: "{prefix}gradient shading produced fewer than two color stops and was dropped."; }; readonly SHADING_NO_CLIP_FALLBACK_BBOX: { readonly severity: "info"; 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."; }; readonly SHADING_CLIP_DEGENERATE: { readonly severity: "warning"; readonly template: "{prefix}gradient shading clip path was degenerate and the region was dropped."; }; readonly SHADING_RADIAL_FOCAL_DROPPED: { readonly severity: "info"; 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."; }; readonly SHADING_UNKNOWN_RADIAL_SUBTYPE: { readonly severity: "error"; readonly template: "{prefix}gradient shading reported unknown RadialAxial subtype \"{kind}\" and was dropped."; }; readonly SHADING_NO_PATTERN_REF: { readonly severity: "error"; readonly template: "{prefix}gradient shading was emitted without a pattern reference and was dropped."; }; readonly TILING_PATTERN_AS_IMAGE: { readonly severity: "info"; 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)."; }; readonly TILING_PATTERN_UNSUPPORTED: { readonly severity: "warning"; 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."; }; readonly TILING_PATTERN_UNRESOLVED: { readonly severity: "error"; readonly template: "{prefix}tiling pattern \"{patternId}\" could not be resolved by pdf.js and was dropped."; }; readonly TILING_PATTERN_IMAGE_DECODE_FAILED: { readonly severity: "warning"; readonly template: "{prefix}tiling pattern \"{patternId}\" referenced image \"{imageObjId}\" but the image bytes could not be decoded. The pattern fill was dropped."; }; }; interface Color { space: "rgb" | "cmyk" | "gray"; /** in [0..1]. rgb:[r,g,b] cmyk:[c,m,y,k] gray:[g] */ values: number[]; /** in [0..1]; defaults to 1 */ alpha?: number; } type CesdkFontWeight = "thin" | "extraLight" | "light" | "normal" | "medium" | "semiBold" | "bold" | "extraBold" | "heavy"; interface TextOutline { kind: "text-outline"; /** pt, run bbox top-left */ x: number; y: number; width: number; height: number; /** SVG path data (all glyphs concatenated) */ d: string; /** Original text (for diffing / accessibility) */ text: string; /** * Family base parsed from the PDF PostScript name (subset prefix and * recognized weight/style/width suffix stripped — e.g. * `WTNEYF+Poppins-ExtraBold` → `Poppins`). Falls back to the full * subset-stripped name when no recognized suffix is present, so families * with internal hyphens like `SVN-BlogScript` survive intact. Suitable * as a font-resolver query. */ fontFamily: string; /** pt */ fontSize: number; /** Derived from fontObj.italic + name suffix. */ fontStyle?: "normal" | "italic"; /** * CE.SDK weight string. Together with `fontStyle` and `fontFamily` lets * the font-resolver substitute the correct typeface variant for an * editable text block, or — on resolver miss — be preserved as block * metadata. */ fontWeight?: CesdkFontWeight; fill: Color | null; /** * pt, pen x of the first glyph in device coords. Used by the * resolver-substitution path to place the editable text block at the * generator's setPositionX rather than the ink-bbox left edge (which is * shifted by the first glyph's LSB, typically ~1–2pt for caps). */ textOriginX?: number; /** * Radians in CE.SDK screen (y-down) frame, 0 for horizontal. Optional; * absent on truly horizontal runs. Mirrors the `rotation` field on * TextRun so both emit paths can apply `setRotation` from the same * source. Sign convention: PDF's y-up Tm rotation atan2(b,a) negated to * match CE.SDK's y-down screen frame. */ rotation?: number; /** * pt, ink-bbox width in the un-rotated text frame. Equals `width` for * horizontal runs; differs for ±90°/180° runs where `width`/`height` * describe the rotated AABB. */ unrotWidth?: number; /** * pt, ink-bbox height in the un-rotated text frame. Pair with * `unrotWidth` to size the editable text block at its natural * pre-rotation dimensions; CE.SDK then auto-fits to its own typeface * metrics. */ unrotHeight?: number; /** * [0..1], default 1. Like `VectorPath.opacity` and `ImageBox.opacity`, * lets the emitter apply `setOpacity` to text-outline blocks (the * walker uses this for runs that inherited a reduced fill alpha). */ opacity?: number; /** * pt, baseline y in device (top-down) coords. Pen origin's y, used by * the resolver-substitution path to position the editable text block * at the baseline rather than the ink-bbox top. */ textOriginY?: number; } interface EmbeddedFont { /** * Unique per subset. When a PDF embeds multiple subsets that share a PS * family name (common: one subset per chapter/page), this field is * suffixed with pdf.js's `loadedName` (e.g. * `PublicSans-Light#g_d0_f3`) so each subset keeps its own entry in * `Document.fonts`. Use `family` for display. */ postScriptName: string; /** * Human typeface name from the font's opentype name table (falls back to * the PS family name). */ family: string; /** 400 | 700 | 900 (pdf.js bold/black flags) */ weight?: number; style?: "normal" | "italic"; /** * Width-axis label (OS/2 `usWidthClass` mapped to a normalized string, * or parsed from the PostScript suffix's width token: `cond`, * `extended`, `narrow`, …). Distinguishes condensed-width subsets * from normal-width subsets so the merger does not collapse them. * Absent when neither source carries width information. */ width?: string; /** Raw TTF/OTF bytes */ data: Uint8Array; /** 'font/otf' | 'font/ttf' */ mimeType: string; } interface ColorSpan { from: number; to: number; fill: Color | null; } interface StyleSpan { from: number; to: number; /** PostScript name from the originating run. */ fontRef: string; /** CSS 100..900; matches `EmbeddedFont.weight`. */ fontWeight?: number; /** Matches `EmbeddedFont.style`. */ fontStyle?: "normal" | "italic"; } interface TextRun { kind: "text-run"; /** pt, unrotated bbox top-left */ x: number; /** pt */ y: number; /** pt (with a small advance padding) */ width: number; /** pt (ascender - descender, scaled by fontSize) */ height: number; /** Rendered string (Unicode, not glyph codes) */ text: string; /** postScriptName; resolves via Document.fonts */ fontRef: string; /** * Logical font family (subset prefix + weight/style suffix stripped), * mirroring `EmbeddedFont.family`. Populated by `text-items.ts` from * the resolved EmbeddedFont so `postprocess-text.ts::canGroup` can * decide whether two distinct `fontRef`s (e.g. `Helvetica` + * `Helvetica-Bold`) belong to the same logical typeface and should * merge into one block with `styleSpans`. Absent on legacy inputs * (synthetic IR, older callers) — `canGroup` then falls back to the * stricter `fontRef === fontRef` test and keeps the runs split. */ family?: string; /** * CSS 100..900, mirroring `EmbeddedFont.weight`. Used as the per-run * weight contribution when the merger bridges variants of the same * `family`. Absent on legacy inputs (merger then refuses to merge * across `fontRef` mismatches — see `family`). */ fontWeight?: number; /** Mirrors `EmbeddedFont.style`. Pairs with `fontWeight`. */ fontStyle?: "normal" | "italic"; /** * Width-axis label, mirroring `EmbeddedFont.width`. Distinguishes * `Helvetica-Condensed` from `Helvetica-Regular` so the merger does * not collapse them — CE.SDK's per-range setters (`setTextFontWeight`, * `setTextFontStyle`) have no width parameter and would silently * render condensed glyphs at normal width. * * Values follow OS/2 `usWidthClass` semantics, normalized to a small * string set: `'ultraCondensed' | 'extraCondensed' | 'condensed' | * 'semiCondensed' | 'normal' | 'semiExpanded' | 'expanded' | * 'extraExpanded' | 'ultraExpanded'`. Absent on legacy inputs. */ fontWidth?: string; /** pt */ fontSize: number; /** * Radians, 0 for horizontal text. x/y place the block so rotation around * its center matches the PDF. */ rotation: number; fill: Color | null; /** * pt, pen origin x in PDF view-frame (top-left origin), pre-pivot-comp. * Populated by `text-items.ts`; used by `groupLineRuns` to test * pen-origin continuity between runs that pdf.js split mid-line for * kerning. */ baselineXPt?: number; /** pt, pen origin y, same frame. */ baselineYPt?: number; /** * pt, raw along-baseline advance from pdf.js (`item.width`). Distinct * from `width`, which carries a small rendering padding that is * intentionally invisible to merger logic. */ advanceWidthPt?: number; /** * Per-character (UTF-16) color ranges within `text`. Set by `mergeRuns` * only when constituent runs differ in fill; absent for single-run * blocks and for merged groups with uniform fill (back-compat). Range * indices match `engine.block.setTextColor(id, color, from, to)`'s * contract. */ colorSpans?: ColorSpan[]; /** * Per-character (UTF-16) weight/style ranges within `text`. Set by * `mergeRuns` only when the merger bridged adjacent same-family runs * that use different weight/style variants (e.g. inline bold inside a * paragraph). Absent for single-run blocks and for merged groups with * uniform variant. Range indices match `engine.block.setTextFontWeight * (id, weight, from, to)` / `setTextFontStyle(id, style, from, to)`. */ styleSpans?: StyleSpan[]; /** * Lazy builder for the run's glyph outline as a vector path. Captures * the walker's pending run + glyph + font references; invoked by * `emit/cesdk.ts::emitGlyphsAsVectorPath` only when the font-strategy * cascade returns null and emission needs a fallback. Returns the SVG * `d` plus bbox geometry, or null when path extraction is unavailable * (Type 3 glyph charproc missing, opentype parse failure). * * Populated by `text-items.ts::extractTextRuns` from a per-BT/ET queue * stashed by the walker (`placeholder._lazyGlyphOutlines`). Holds * references — discarded when the IR is GC'd after emit. Builder is * called at most once per run (cascade-null is rare for asset-library * coverage). */ _buildGlyphOutline?: () => GlyphOutlineData | null; } interface GlyphOutlineData { /** SVG path data in local bbox coordinates (top-left origin). */ d: string; /** pt, bbox top-left in page coords. */ x: number; /** pt */ y: number; /** pt */ width: number; /** pt */ height: number; } /** * Per-run input to the cascade and emission layers. Built by * `lib/make-request.ts` from the source IR block (either `TextRun` or * `TextOutline`). * * Vector-outline data has two shapes depending on source kind: * - `TextOutline` sources carry `glyphPaths` eagerly (the walker built * the path because the font wasn't embeddable — Type 3 / restricted / * PUA). * - `TextRun` sources carry `buildGlyphOutline`, a lazy builder set up * by the walker + text-items pairing. Emission only invokes it when * the cascade returns null and a vector fallback is needed — most * documents have asset-library coverage and never call it. */ export interface FontRequest { /** Display family (subset prefix stripped). */ family: string; style: "normal" | "italic"; weight: Font["weight"]; /** Original text content; preserved for metadata + recovery. */ text: string; /** Embedded subset bytes — present when the source was a TextRun. */ embeddedFont?: EmbeddedFont; /** Concatenated glyph paths in local coords — present when the source was a TextOutline. */ glyphPaths?: string; /** Lazy glyph-outline builder (TextRun sources). Built by walker; * invoked at most once by emission when the cascade returns null. */ buildGlyphOutline?: () => GlyphOutlineData | null; /** Original IR block — used by emission for geometry, fills, rotation, etc. */ source: TextRun | TextOutline; } export type CascadeResolution = { kind: "typeface"; typeface: Typeface; font?: Font; /** Identifies which stage produced this resolution. */ provenance: string; /** Forwarded from `FontResolverResult.substitutedFrom`. When set, the * emission layer treats the resolution as substituted and recomputes * layout. */ substitutedFrom?: string; } | { kind: "subset"; embeddedFont: EmbeddedFont; provenance: "embedded-subset"; }; /** * Stage outcome. Distinguishing "pass with reason" from `null` lets debug * logs explain *why* the cascade reached a given stage's neighbour. Cheap * to carry now; expensive to retrofit. */ export type StageOutcome = CascadeResolution | { kind: "pass"; reason: string; }; interface CascadeLogger { emit?: (code: string, params: Record) => void; log?: (message: string, level?: string) => void; } export interface FontStageContext { engine: CreativeEngine; resolver: TypefaceResolver | null; /** * Per-import-call cache. Same `family|style|weight` resolves once per * `PDFParser.fromFile` invocation; reopening the PDF produces a fresh * cache. Created in the parser entry, discarded on completion. */ resolverCache: Map; logger: CascadeLogger | null; } export interface FontStage { /** Stable identifier for logs and tests. */ readonly name: string; resolve(req: FontRequest, ctx: FontStageContext): Promise; } export interface FontCascade { readonly stages: readonly FontStage[]; resolve(req: FontRequest, ctx: FontStageContext): Promise; } /** * Result of a single emission call. The emission layer may produce zero, * one, or more blocks; the `blocks` array is in z-order (back to front). * `substituted` is true when the cascade's answer triggered a * substitution that the dispatcher should account against the * per-import substitution-count log. */ export interface EmissionResult { /** CE.SDK block ids created. Empty array means the run was skipped. */ blocks: number[]; /** True when the resolution involved a font substitution. */ substituted: boolean; /** Display name of the typeface the run resolved to, if any. */ resolvedFamily?: string; } /** * Block-creation primitives that emission delegates to. The dispatcher * fills these in so emission stays decoupled from `engine.block.*` and * from the geometry helpers that already live in `emit/cesdk.ts`. Keeps * the emission policy testable in isolation: each callback can be * stubbed. */ export interface EmissionHelpers { /** * Create an editable text block with the request's geometry and the * caller-supplied `applyFont` callback (called between layout and * properties — order matters for CE.SDK's `replaceText` wrap-marker). * `layoutIr` may be the original block or a typeface-aware substitute * (see `resolveLayoutForSubstitution` below). */ createEditableText(req: FontRequest, layoutIr: TextOutline | TextRun, applyFont: (engine: CreativeEngine, block: number) => void): number; /** * Emit the request's `glyphPaths` as a `vector_path` graphic block at * the source bbox. Returns null when the request carries no * `glyphPaths` (TextRun source). */ emitGlyphsAsVectorPath(req: FontRequest): number | null; /** * Compute the layout-aware IR for a substituted typeface. For TextRun * sources this is a no-op (returns `req.source`); for TextOutline * sources it derives the unrotated bbox CE.SDK needs using the * substitute's font metrics. */ resolveLayoutForSubstitution(req: FontRequest, resolution: CascadeResolution): Promise; } export interface EmissionContext { engine: CreativeEngine; logger: CascadeLogger | null; /** Page index (1-based) for diagnostic context. */ pageIndex?: number; helpers: EmissionHelpers; } export interface FontEmission { readonly name: string; emit(req: FontRequest, resolution: CascadeResolution | null, ctx: EmissionContext): Promise; } export interface FontStrategy { readonly cascade: FontCascade; readonly emission: FontEmission; } export declare const perfectMatchResolverStage: FontStage; export declare const embeddedSubsetStage: FontStage; export declare const anyMatchResolverStage: FontStage; export declare const defaultEmission: FontEmission; /** * Build a cascade from an ordered list of stages. The cascade walks the * list and returns the first non-pass outcome. When every stage passes, * the cascade returns `null` (emission decides what to do). */ export declare function createFontCascade(stages: FontStage[]): FontCascade; interface FontStrategyDef { cascade: FontCascade; emission: FontEmission; } export declare function createFontStrategy(def: FontStrategyDef): FontStrategy; /** * Default for `PDFParser.fromFile({ fontStrategy })`. Embedded subset * bytes are used as an intermediate fallback to preserve the source's * exact rendering when the family isn't in the asset library — vector * outline extraction can produce incorrect bboxes or partial glyph * coverage for some fonts, while the engine renders subset bytes * faithfully. * * - Run's family resolves perfectly in the asset library → * perfect-match typeface (HTTPS URI). * - Embedded subset present (TextRun source) → register the bytes and * emit as editable text with `setFont`. The resulting scene depends * on the bytes living in a `buffer://` URI; this is the offline-safe * path. * - Otherwise → any-match resolver (possibly substituted via the * fallbacks source; a per-import warning summarizes substitutions). * - Neither hits → cascade returns null → emission falls through to a * vector outline (TextOutline-source runs always have glyph paths; * TextRun-source runs use the Phase-2 lazy closure built by the * walker). * * For tools that explicitly want vectorization over subset bytes * (e.g. brand-locked editors), use `assetLibraryStrategy`. */ export declare const editableFirstStrategy: FontStrategy; /** * For print finalization, PDF-viewer-style integrations, and anywhere a * silent Helvetica → Roboto substitution is unacceptable. Skips * `anyMatchResolverStage`; non-embeddable runs without a perfect match * fall through to vector outline. */ export declare const exactFidelityStrategy: FontStrategy; /** * For brand-locked tools: every editable text must come from the asset * library (or the resolver's alias fallbacks). Drops the subset stage so * PDF-embedded subset bytes never leak through; runs whose family isn't * in the library go straight to the any-match resolver. */ export declare const assetLibraryStrategy: FontStrategy; export declare const defaultStrategy: FontStrategy; type PageBounds = "trim" | "media"; type PdfLogger = Logger; export declare class PDFParser { private engine; private pdfBytes; private fontResolver; private fontStrategy; private pageBounds; private logger; private ir?; private constructor(); /** * Create a PDFParser instance from a PDF file. * * @param engine - CE.SDK engine instance * @param file - PDF file as Blob, File, or ArrayBuffer * @param options - Optional configuration * @param options.fontResolver - Custom font resolver. Invoked by the * cascade's resolver-using stages (`perfectMatchResolverStage`, * `anyMatchResolverStage`). Requires `addGfontsAssetLibrary` to be * called on the engine before parse. * @param options.fontStrategy - Strategy controlling how text runs * become blocks. Default: `editableFirstStrategy` — prefers a perfect * asset-library match, falls back to the PDF-embedded subset, then to * resolver substitution (any-match), and finally to vector outline * when nothing else hits. Other shipped presets: * `exactFidelityStrategy` (never substitute), `assetLibraryStrategy` * (drop subset). Build custom strategies with `createFontStrategy({ * cascade, emission })`. See `packages/pdf-importer/CLAUDE.md` → * "Font resolution" for the mental model and offline-safe recipe. * @returns A new PDFParser instance */ static fromFile(engine: CreativeEngine, file: Blob | File | ArrayBuffer, options?: { fontResolver?: TypefaceResolver; fontStrategy?: FontStrategy; /** * Which PDF page box the emitted CE.SDK pages are sized to. Defaults * to `"trim"` (designed page + bleed margin, the end-user view). * `"media"` keeps pages at MediaBox (aka `page.view`) dimensions * with children unshifted — used by the regression pixel-diff harness * so CE.SDK exports match `pdftoppm`'s full-MediaBox reference images. */ pageBounds?: PageBounds; }): Promise; /** * @deprecated Use options object instead: `fromFile(engine, file, { fontResolver })` */ static fromFile(engine: CreativeEngine, file: Blob | File | ArrayBuffer, fontResolver?: TypefaceResolver): Promise; /** * Parse the PDF file and emit a CE.SDK scene with all pages. * * Pipeline: pdf.js → IR (`extractDocument`) → line-run grouping → * CE.SDK scene (`emitInto`). Text extraction always produces full text * blocks: one block per line from pdf.js `getTextContent`, with adjacent * lines that share font/size and horizontal overlap merged into a single * multi-line block. * * Mirrors `engine.scene.loadFromString`: replaces the engine's current * scene with the imported PDF. * * @returns Parse result containing the scene ID and logger */ parse(): Promise<{ scene: number; logger: PdfLogger; }>; /** * Parse the PDF and return the imported pages as detached CE.SDK blocks. * * Mirrors `engine.block.loadFromString`: returned blocks are NOT attached * to a scene. Caller appends and positions them however they want. * * Each PDF page yields one returned `page` block, sized to the PDF's * MediaBox in inches with the page's content as children. CE.SDK pages * are the right wrapper here — `setWidth`/`setHeight` scales children * proportionally (so callers can fit a PDF page into an arbitrary host * frame), and pages clip to their bounds (matching IDML's frame * semantics when content overflows). * * @param options * @param options.pageIndex 0-based page to load. Omit to load all pages * (returns one block per page, in document order). * @returns Detached page block IDs (length 1 for single-page mode, * `pdf.numPages` for all-pages mode), plus the logger so callers can * forward parser warnings into their own diagnostic stream. */ loadAsBlocks(options?: { pageIndex?: number; }): Promise<{ blocks: number[]; logger: PdfLogger; }>; /** * Number of pages in the PDF document. * * Triggers a full IR extraction on first call (the same work `parse` / * `loadAsBlocks` does), then caches it. Subsequent calls — including * `parse` and `loadAsBlocks` themselves — reuse the cached IR. */ getPageCount(): Promise; /** * Get the logger for this parser instance. */ getLogger(): PdfLogger; private ensureIR; } export {};