Move font loading and layout into SkiaRenderer.prepareForExport
The headless render path duplicated font collection, text measurer setup, and layout recomputation separately from the renderer. Move this into SkiaRenderer.prepareForExport() so browser and headless share the same code path for export preparation. Remove the now-redundant loadFonts from CLI headless and the manual setTextMeasurer/collectFontKeys/computeAllLayouts from headless-render.
This commit is contained in:
parent
b9d6afcdbc
commit
7d9eb2931c
|
|
@ -3,7 +3,7 @@ import { basename, extname, resolve } from 'node:path'
|
|||
|
||||
import { renderNodesToSVG, sceneNodeToJSX, selectionToJSX } from '@open-pencil/core'
|
||||
|
||||
import { loadDocument, loadFonts, exportNodes, exportThumbnail } from '../headless'
|
||||
import { loadDocument, exportNodes, exportThumbnail } from '../headless'
|
||||
import { isAppMode, requireFile, rpc } from '../app-client'
|
||||
import { ok, printError } from '../format'
|
||||
import type { ExportFormat, JSXFormat } from '@open-pencil/core'
|
||||
|
|
@ -60,7 +60,6 @@ async function exportViaApp(format: string, args: ExportArgs) {
|
|||
async function exportFromFile(format: string, args: ExportArgs) {
|
||||
const file = requireFile(args.file)
|
||||
const graph = await loadDocument(file)
|
||||
await loadFonts(graph)
|
||||
|
||||
const pages = graph.getPages()
|
||||
const page = args.page ? pages.find((p) => p.name === args.page) : pages[0]
|
||||
|
|
|
|||
|
|
@ -4,8 +4,6 @@ import {
|
|||
type SceneGraph,
|
||||
type ExportFormat,
|
||||
computeAllLayouts,
|
||||
collectFontKeys,
|
||||
loadFont,
|
||||
headlessRenderNodes,
|
||||
headlessRenderThumbnail
|
||||
} from '@open-pencil/core'
|
||||
|
|
@ -19,12 +17,6 @@ export async function loadDocument(filePath: string): Promise<SceneGraph> {
|
|||
return graph
|
||||
}
|
||||
|
||||
export async function loadFonts(graph: SceneGraph, nodeIds?: string[]): Promise<void> {
|
||||
const ids = nodeIds ?? [...graph.getAllNodes()].map((n) => n.id)
|
||||
const fontKeys = collectFontKeys(graph, ids)
|
||||
await Promise.all(fontKeys.map(([family, style]) => loadFont(family, style)))
|
||||
}
|
||||
|
||||
export async function exportNodes(
|
||||
graph: SceneGraph,
|
||||
pageId: string,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
import type { CanvasKit } from 'canvaskit-wasm'
|
||||
|
||||
import { collectFontKeys, loadFont } from './fonts'
|
||||
import { computeAllLayouts, setTextMeasurer } from './layout'
|
||||
import { renderNodesToImage, renderThumbnail, type ExportFormat } from './render-image'
|
||||
import { SkiaRenderer } from './renderer'
|
||||
import type { SceneGraph } from './scene-graph'
|
||||
|
|
@ -28,16 +26,10 @@ async function getRenderer(): Promise<{ ck: CanvasKit; renderer: SkiaRenderer }>
|
|||
renderer.viewportHeight = 1
|
||||
renderer.dpr = 1
|
||||
await renderer.loadFonts()
|
||||
setTextMeasurer((node, maxWidth) => renderer.measureTextNode(node, maxWidth))
|
||||
cachedRenderer = renderer
|
||||
return { ck, renderer }
|
||||
}
|
||||
|
||||
async function loadNodeFonts(graph: SceneGraph, nodeIds: string[]): Promise<void> {
|
||||
const fontKeys = collectFontKeys(graph, nodeIds)
|
||||
await Promise.all(fontKeys.map(([family, style]) => loadFont(family, style)))
|
||||
}
|
||||
|
||||
export async function headlessRenderNodes(
|
||||
graph: SceneGraph,
|
||||
pageId: string,
|
||||
|
|
@ -45,8 +37,7 @@ export async function headlessRenderNodes(
|
|||
options: { scale?: number; format?: ExportFormat; quality?: number } = {}
|
||||
): Promise<Uint8Array | null> {
|
||||
const { ck, renderer } = await getRenderer()
|
||||
await loadNodeFonts(graph, nodeIds)
|
||||
computeAllLayouts(graph, pageId)
|
||||
await renderer.prepareForExport(graph, pageId, nodeIds)
|
||||
return renderNodesToImage(ck, renderer, graph, pageId, nodeIds, {
|
||||
scale: options.scale ?? 1,
|
||||
format: options.format ?? 'PNG',
|
||||
|
|
@ -62,7 +53,6 @@ export async function headlessRenderThumbnail(
|
|||
): Promise<Uint8Array | null> {
|
||||
const { ck, renderer } = await getRenderer()
|
||||
const page = graph.getNode(pageId)
|
||||
if (page) await loadNodeFonts(graph, page.childIds)
|
||||
computeAllLayouts(graph, pageId)
|
||||
if (page) await renderer.prepareForExport(graph, pageId, page.childIds)
|
||||
return renderThumbnail(ck, renderer, graph, pageId, width, height)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -416,6 +416,24 @@ export class SkiaRenderer {
|
|||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Load document fonts and set up text measurement for layout.
|
||||
* Call after `loadFonts()` and before rendering a document headlessly.
|
||||
* Collects all font family+weight pairs used by `nodeIds`, loads them,
|
||||
* wires up the text measurer for Yoga layout, and recomputes layout.
|
||||
*/
|
||||
async prepareForExport(graph: SceneGraph, pageId: string, nodeIds: string[]): Promise<void> {
|
||||
const { collectFontKeys, loadFont } = await import('../fonts')
|
||||
const { setTextMeasurer, computeAllLayouts } = await import('../layout')
|
||||
|
||||
setTextMeasurer((node, maxWidth) => this.measureTextNode(node, maxWidth))
|
||||
|
||||
const fontKeys = collectFontKeys(graph, nodeIds)
|
||||
await Promise.all(fontKeys.map(([family, style]) => loadFont(family, style)))
|
||||
|
||||
computeAllLayouts(graph, pageId)
|
||||
}
|
||||
|
||||
replaceSurface(surface: Surface): void {
|
||||
this.surface.delete()
|
||||
this.surface = surface
|
||||
|
|
|
|||
Loading…
Reference in a new issue