@liustack/pptfast 0.4.0 → 0.6.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.
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/platform/browser.ts","../src/svg/audit/pixel-audit.ts"],"sourcesContent":["import { findRemoteAssetRef, type RasterizedImage } from \"./registry\"\n\n/**\n * Browser default for `rasterizeSvg` (audit-v2 phase B, spec §4.3/§11.8) —\n * native `Image` + `OffscreenCanvas`/`<canvas>` only, zero new dependency.\n * Applied at the pixel-audit call site (`../svg/audit/pixel-audit.ts`) the\n * same way `domParser`'s `?? globalThis.DOMParser` fallback already works\n * (`deck-audit.ts`'s `parseSvg`) — nothing calls `installPlatform()`\n * automatically in a browser, so this is a plain fallback function, not\n * something wired through `installPlatform()` itself. Lives outside\n * `src/platform/node.ts` (which imports `linkedom`/`sharp`) so it can sit\n * inside `src/index.ts`'s own browser-safe dependency closure without\n * pulling in either.\n *\n * Two explicit-failure paths, both load-bearing per the audit-v2 controller\n * ruling on browser remote assets (own tests: `browser.test.ts`):\n *\n * 1. `findRemoteAssetRef` — scanned *before* ever touching `Image`/canvas.\n * An `<img>`/`Image` load of an `http(s):` asset happens in a restricted\n * context: the resource is silently dropped rather than reliably\n * tainting the canvas, so without this guard a remote-image slide would\n * rasterize to a *blank* region and get sampled as if that blank were\n * the real background — exactly the \"checked nothing, reported clean\"\n * failure this wave rules out. (`node.ts`'s Sharp implementation shares\n * this same guard for a different reason — see `findRemoteAssetRef`'s own\n * doc comment.)\n * 2. `getImageData`'s own `SecurityError` — kept as a fallback for\n * whatever the markup scan didn't anticipate (a future asset kind, a\n * same-origin-but-still-tainting edge case): caught and re-thrown as an\n * explicit, readable error rather than left as a raw `DOMException` (or,\n * worse, silently producing zeroed pixel data some engines return\n * instead of throwing).\n */\n\ninterface Minimal2dContext {\n drawImage(image: CanvasImageSource, dx: number, dy: number, dw: number, dh: number): void\n getImageData(sx: number, sy: number, sw: number, sh: number): ImageData\n}\n\ninterface MinimalCanvas {\n getContext(id: \"2d\"): Minimal2dContext | null\n}\n\n/** `DOMException` is *not* an `Error` subclass per the WebIDL spec (real\n * browsers: `new DOMException(\"x\", \"SecurityError\") instanceof Error` is\n * `false`) — duck-type on `.name` rather than `instanceof Error`. */\nfunction isSecurityError(e: unknown): boolean {\n return typeof e === \"object\" && e !== null && (e as { name?: unknown }).name === \"SecurityError\"\n}\n\nfunction loadImage(url: string): Promise<HTMLImageElement> {\n return new Promise((resolve, reject) => {\n const img = new Image()\n img.onload = () => resolve(img)\n img.onerror = () => reject(new Error(\"rasterizeSvg: the browser could not decode the rasterized SVG as an image\"))\n img.src = url\n })\n}\n\nfunction createCanvas(width: number, height: number): MinimalCanvas {\n if (typeof OffscreenCanvas !== \"undefined\") {\n return new OffscreenCanvas(width, height) as unknown as MinimalCanvas\n }\n if (typeof document !== \"undefined\") {\n const canvas = document.createElement(\"canvas\")\n canvas.width = width\n canvas.height = height\n return canvas as unknown as MinimalCanvas\n }\n throw new Error(\n 'rasterizeSvg unavailable — in Node, call installNodePlatform() from \"@liustack/pptfast/node\" first (the pptfast CLI does this automatically); in a browser, OffscreenCanvas or a DOM canvas is required',\n )\n}\n\nexport async function rasterizeSvgInBrowser(svgMarkup: string, width: number, height: number): Promise<RasterizedImage> {\n const remoteRef = findRemoteAssetRef(svgMarkup)\n if (remoteRef) {\n throw new Error(\n `rasterizeSvg: refusing to rasterize an SVG that references a remote image (${remoteRef}) — only data-URI (or other local) assets are supported (a remote asset would silently drop when loaded this way, not rasterize)`,\n )\n }\n if (typeof Image === \"undefined\") {\n throw new Error(\n 'rasterizeSvg unavailable — in Node, call installNodePlatform() from \"@liustack/pptfast/node\" first (the pptfast CLI does this automatically); in a browser, the Image constructor is required',\n )\n }\n\n const blob = new Blob([svgMarkup], { type: \"image/svg+xml\" })\n const url = URL.createObjectURL(blob)\n try {\n const img = await loadImage(url)\n const canvas = createCanvas(width, height)\n const ctx = canvas.getContext(\"2d\")\n if (!ctx) throw new Error(\"rasterizeSvg: could not obtain a 2d canvas context\")\n ctx.drawImage(img, 0, 0, width, height)\n let imageData: ImageData\n try {\n imageData = ctx.getImageData(0, 0, width, height)\n } catch (e) {\n if (isSecurityError(e)) {\n throw new Error(\n \"rasterizeSvg: the canvas was tainted while reading back pixel data (a cross-origin or otherwise untrusted asset) — only data-URI (or other local) assets are supported\",\n )\n }\n throw e\n }\n return { width: imageData.width, height: imageData.height, data: imageData.data }\n } finally {\n URL.revokeObjectURL(url)\n }\n}\n","import type { PptxIR } from \"@/ir\"\nimport { renderSlideSvg } from \"../../api\"\nimport { CANVAS_H_PX, CANVAS_W_PX } from \"../../constants\"\nimport { rasterizeSvgInBrowser } from \"../../platform/browser\"\nimport { getPlatform, type RasterizedImage } from \"../../platform/registry\"\nimport {\n __collectImageBackedTextRuns,\n blendOver,\n contrastRatio,\n type AuditFinding,\n type ImageBackedTextRun,\n} from \"./deck-audit\"\n\n/**\n * Optional pixel-level contrast audit (audit-v2 phase B, spec §4.3) — the\n * one pixel blind spot the deterministic SVG audit can't see: text painted\n * directly over a bare or too-faintly-scrimmed `<image>`, where\n * `deck-audit.ts`'s own SVG-color walk correctly gives up rather than guess\n * (`ImageBackedTextRun`, `__collectImageBackedTextRuns`). Never imported by\n * `deck-audit.ts` at the top level — `auditDeck`'s `pixels: true` branch\n * reaches this module through a lazy `import(\"./pixel-audit\")` instead\n * (that function's own doc comment explains why: this file statically\n * depends on `deck-audit.ts` for its shared primitives, so a *static*\n * import the other way would form a module cycle; nothing here needs to be\n * loaded at all for the far more common `pixels` left unset case).\n *\n * Flow per spec §4.3, steps 2-6:\n * 1. `__collectImageBackedTextRuns` — reuse the exact same background-\n * resolution walk the deterministic audit already ran, just reading its\n * \"could not resolve\" runs instead of discarding them. A page with none\n * skips rasterization entirely (no rasterizer call, no risk of that\n * page's own remote-asset guard ever firing) — real cost only where\n * there is real work to do.\n * 2. `stripTextNodes` — the \"去文字克隆\" clone.\n * 3. `rasterizeSvg(stripped, 1280, 720)` — platform primitive (Sharp in\n * Node, native canvas in a browser — see `resolveRasterizer`).\n * 4/5. `worstCaseSample` — grid-sample each run's estimated box against the\n * rasterized pixels, tracking the least-favorable (lowest-ratio) point.\n * 6. Only a sample below `PIXEL_HARD_FINDING_MAX_RATIO` becomes a finding —\n * spec §4.3's own anti-false-positive gate, see that constant's doc\n * comment.\n */\n\nconst PIXEL_CANVAS_W = CANVAS_W_PX\nconst PIXEL_CANVAS_H = CANVAS_H_PX\n\n/**\n * Below this, a pixel-sampled contrast finding is emitted regardless of the\n * real WCAG target (`ImageBackedTextRun.required`) — spec §4.3's own \"为了\n * 控制误报,首版只有低于 1.5:1 才进入 hard finding\" gate. Pixel sampling\n * carries antialiasing/rasterizer noise the SVG-only walk never has to deal\n * with (spec §11.10's determinism footnote: no cross-platform byte\n * guarantee for this layer) — `node-rasterize.test.ts`'s own transparency\n * probe found up to ~1/255-per-channel sequential-blend rounding drift,\n * nowhere near enough to move a real ratio across this floor. Deliberately\n * far below either real WCAG floor (3/4.5) so only a genuinely broken\n * pairing fires, not a borderline-but-fine one.\n */\nconst PIXEL_HARD_FINDING_MAX_RATIO = 1.5\n\n/**\n * Strip every `<text>...</text>` (and self-closing `<text/>`) element from\n * SVG markup — spec §4.3 step 2's \"去文字克隆\" (clone with text removed). A\n * plain string replace, not a DOM parse/remove/reserialize round-trip:\n * removing an element has zero effect on sibling/ancestor geometry in SVG\n * (no reflow, unlike HTML), so a round-trip would only add risk — a\n * serializer (linkedom in Node) producing markup that doesn't byte-match\n * what a real browser's `XMLSerializer` would, for zero benefit. Sound\n * under two preconditions this renderer's own architecture already\n * guarantees: `renderToStaticMarkup` (React) HTML/XML-escapes every text\n * *node*, so a literal `</text>` substring appearing in `markup` can only\n * ever be a real closing tag, never escaped slide content; and `<text>` is\n * never nested inside another `<text>` anywhere in `src/svg` (verified\n * across every emitter while building this task).\n */\nconst TEXT_ELEMENT_RE = /<text\\b[^>]*\\/>|<text\\b[^>]*>[\\s\\S]*?<\\/text>/g\n\nexport function stripTextNodes(markup: string): string {\n return markup.replace(TEXT_ELEMENT_RE, \"\")\n}\n\nfunction rgbToHex(r: number, g: number, b: number): string {\n const toHex = (v: number) => v.toString(16).padStart(2, \"0\")\n return `#${toHex(r)}${toHex(g)}${toHex(b)}`.toUpperCase()\n}\n\n/**\n * Ascent/descent as a fraction of `fontSize`, defining the vertical band\n * `worstCaseSample` grids over — no real font metrics are available at\n * audit time (this renderer never embeds/queries a font file), so both are\n * the same kind of declared-size-relative heuristic `deck-audit.ts`'s own\n * `TEXT_DESCENT_RATIO` (0.25, used for v-overflow/derived-box-height) is —\n * `SAMPLE_DESCENT_RATIO` mirrors it exactly for consistency between the two\n * auditors' notion of \"how far below the baseline a glyph's ink extends\".\n * `SAMPLE_ASCENT_RATIO` (0.75) is this task's own addition — no existing\n * constant to mirror since nothing before this needed a text run's *top*\n * edge — a standard approximation for common UI sans-serif cap-height/\n * ascender proportion.\n */\nconst SAMPLE_ASCENT_RATIO = 0.75\nconst SAMPLE_DESCENT_RATIO = 0.25\n\n/**\n * Sample grid resolution (columns × rows) across a run's estimated\n * `[left,right] × [top,bottom]` box. Small on purpose — pixel sampling runs\n * per image-backed run, per audited page, and the goal is \"don't miss a\n * genuinely broken pairing by bad luck\", not a dense scan: 15 points is\n * already enough to hit both a bright and dark region of any photo a real\n * heading/caption run would plausibly sit across.\n */\nconst SAMPLE_COLS: number = 5\nconst SAMPLE_ROWS: number = 3\n\ninterface WorstCaseSample {\n ratio: number\n background: string\n}\n\n/**\n * Grid-sample `run`'s estimated box against `image`, tracking the least-\n * favorable (lowest) contrast ratio found — spec §4.3 step 6's \"WCAG 最不利\n * 带\" (worst-case band). A sample whose alpha is below 255 is skipped as\n * indeterminate (this renderer's own `Background.tsx` always paints a\n * full-bleed layer first, so a genuinely transparent pixel should not occur\n * in practice — this is a defensive fallback for that hypothetical, not a\n * normal-path concern). Returns `null` when no sample point yielded usable\n * pixel data at all (every point skipped, or the run's box fell entirely\n * outside the rasterized canvas) — the caller treats that as \"nothing\n * proven either way\", not a finding.\n */\nfunction worstCaseSample(run: ImageBackedTextRun, image: RasterizedImage): WorstCaseSample | null {\n const top = run.baseline - run.fontSize * SAMPLE_ASCENT_RATIO\n const bottom = run.baseline + run.fontSize * SAMPLE_DESCENT_RATIO\n let worst: WorstCaseSample | null = null\n\n for (let row = 0; row < SAMPLE_ROWS; row++) {\n const fy = SAMPLE_ROWS === 1 ? 0.5 : row / (SAMPLE_ROWS - 1)\n const y = Math.round(top + (bottom - top) * fy)\n if (y < 0 || y >= image.height) continue\n for (let col = 0; col < SAMPLE_COLS; col++) {\n const fx = SAMPLE_COLS === 1 ? 0.5 : col / (SAMPLE_COLS - 1)\n const x = Math.round(run.left + (run.right - run.left) * fx)\n if (x < 0 || x >= image.width) continue\n\n const i = (y * image.width + x) * 4\n const alpha = image.data[i + 3]!\n if (alpha < 255) continue\n\n const bgHex = rgbToHex(image.data[i]!, image.data[i + 1]!, image.data[i + 2]!)\n const effective = blendOver(run.fill, bgHex, run.alpha)\n const ratio = contrastRatio(effective, bgHex)\n if (!worst || ratio < worst.ratio) worst = { ratio, background: bgHex }\n }\n }\n return worst\n}\n\nexport interface PixelContrastIssue {\n text: string\n fill: string\n /** The specific sampled RGB pixel (hex) the worst-case point landed on —\n * a literal rasterized sample, never a resolved SVG paint. */\n background: string\n ratio: number\n required: number\n fontSize: number\n}\n\nfunction pixelContrastMessage(issue: PixelContrastIssue): string {\n return (\n `text \"${issue.text}\" has a pixel-sampled contrast ratio of ${issue.ratio.toFixed(2)}:1 against its image background ` +\n `(sampled ${issue.background}, target ${issue.required}:1) — this text sits directly on an image with no resolvable ` +\n `solid backing color; reposition it, add an opaque-enough scrim behind it, or recolor the text`\n )\n}\n\ntype Rasterizer = (svgMarkup: string, width: number, height: number) => Promise<RasterizedImage>\n\n/**\n * `getPlatform().rasterizeSvg` (Sharp once `installNodePlatform()` ran) or\n * the browser default — the exact same `?? fallback` shape `deck-audit.ts`'s\n * `parseSvg` already uses for `domParser`. Never throws itself: an\n * environment with neither capability surfaces through\n * `rasterizeSvgInBrowser`'s own curated \"rasterizeSvg unavailable\" error the\n * first time the returned function is actually called (its `Image`/canvas\n * capability guards — see `browser.ts`), which is the explicit-failure\n * contract spec §11.7's \"契约层\" asks for either way.\n */\nfunction resolveRasterizer(): Rasterizer {\n return getPlatform().rasterizeSvg ?? rasterizeSvgInBrowser\n}\n\nasync function pixelFindingsForPage(\n markup: string,\n page: number,\n slideId: string | undefined,\n rasterize: Rasterizer,\n): Promise<AuditFinding[]> {\n const runs = __collectImageBackedTextRuns(markup)\n if (runs.length === 0) return []\n\n const stripped = stripTextNodes(markup)\n const image = await rasterize(stripped, PIXEL_CANVAS_W, PIXEL_CANVAS_H)\n\n const findings: AuditFinding[] = []\n for (const run of runs) {\n const sampled = worstCaseSample(run, image)\n if (!sampled) continue\n if (sampled.ratio < PIXEL_HARD_FINDING_MAX_RATIO) {\n const issue: PixelContrastIssue = {\n text: run.text,\n fill: run.fill,\n background: sampled.background,\n ratio: sampled.ratio,\n required: run.required,\n fontSize: run.fontSize,\n }\n findings.push({\n page,\n ...(slideId !== undefined ? { slideId } : {}),\n code: \"low-contrast\",\n message: pixelContrastMessage(issue),\n // `source: \"pixels\"` distinguishes this from an SVG-color-resolved\n // low-contrast finding's own `detail` shape (`ContrastIssue`,\n // `deck-audit.ts`) — same `code`, since both are the same category\n // of defect (text fails contrast against its real background), just\n // measured through a different, more reliable source for that\n // background's color.\n detail: { ...issue, source: \"pixels\" },\n })\n }\n }\n return findings\n}\n\n/**\n * Test-only re-export (`__`-prefixed, same \"SDK-internal, not part of any\n * public barrel\" convention `deck-audit.ts`'s own `__collectBgRegions`/\n * `__pathBoundingBox` establish): lets `pixel-audit.test.ts` exercise the\n * sampling-grid + `PIXEL_HARD_FINDING_MAX_RATIO` threshold logic directly,\n * with a hand-crafted `rasterize` function returning exact, controlled\n * pixel data — real component geometry (`ImagePages.tsx`'s `DarkScrim`, in\n * particular) turned out unable to organically produce a sub-1.5 ratio for\n * *any* photo brightness at the org-line's single-scrim-layer position\n * (confirmed empirically while building this task's own test suite: even a\n * pure-white source image only reaches ~1.83), which is the calibration\n * working as designed (spec §4.3's own \"control false positives\" gate) but\n * makes the threshold-crossing branch unreachable through real IR/archetype\n * fixtures alone.\n */\nexport const __pixelFindingsForPage = pixelFindingsForPage\n\n/**\n * The pixel-audit pass over an already-valid deck — `auditDeck(ir, {pixels:\n * true})`'s own async branch (`deck-audit.ts`). Independently walks\n * `ir.slides` (skipping placeholders the same way `runDeterministicAudit`\n * does) rather than reusing that function's own loop, so this module has no\n * static dependency back on it beyond the few named imports at the top of\n * this file — `renderSlideSvg` is pure and synchronous, so re-rendering\n * each non-placeholder slide a second time costs a little CPU, never\n * correctness (spec's own \"no second renderer\" non-goal is about a\n * *different* rendering path, not calling the one true renderer twice).\n *\n * Sequential, not `Promise.all` — deliberately bounds rasterization\n * concurrency to 1 (each Sharp call is real CPU-bound work) and makes the\n * page-order-stable output an obvious property of the code rather than an\n * incidental one `Promise.all`'s array-order guarantee happens to provide.\n *\n * A rasterization failure on any one page (missing platform capability, a\n * remote asset reference, a tainted canvas) propagates out of this function\n * entirely, aborting the whole pixel pass rather than silently skipping\n * just that page — spec §11.7's \"契约层\": a requested-but-failed pixel audit\n * is an explicit failure, never a partial \"clean\".\n */\nexport async function runPixelContrastAudit(ir: PptxIR): Promise<AuditFinding[]> {\n const rasterize = resolveRasterizer()\n const findings: AuditFinding[] = []\n for (let i = 0; i < ir.slides.length; i++) {\n const slide = ir.slides[i]!\n if (slide.placeholder) continue\n const page = i + 1\n const slideId = slide.id\n const markup = renderSlideSvg(ir, i)\n findings.push(...(await pixelFindingsForPage(markup, page, slideId, rasterize)))\n }\n return findings\n}\n"],"mappings":"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","names":[]}