@overtone-art/canvas-editor-core 0.2.8 → 0.3.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/dist/{chunk-ORZZ6MGQ.mjs → chunk-MCBRZQ4M.mjs} +34 -1
- package/dist/chunk-MCBRZQ4M.mjs.map +1 -0
- package/dist/index.d.mts +172 -4
- package/dist/index.d.ts +172 -4
- package/dist/index.global.js +67 -67
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +710 -37
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +644 -22
- package/dist/index.mjs.map +1 -1
- package/dist/node.d.mts +1 -1
- package/dist/node.d.ts +1 -1
- package/dist/node.js.map +1 -1
- package/dist/node.mjs +1 -1
- package/dist/{types-D60CfxL9.d.mts → types-Dh1unrzT.d.mts} +28 -1
- package/dist/{types-D60CfxL9.d.ts → types-Dh1unrzT.d.ts} +28 -1
- package/package.json +6 -4
- package/dist/chunk-ORZZ6MGQ.mjs.map +0 -1
package/dist/node.d.mts
CHANGED
package/dist/node.d.ts
CHANGED
package/dist/node.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/displacement.ts","../src/export.ts","../src/print.ts","../src/node.ts"],"sourcesContent":["import type { MockupDisplacement, MockupDisplacementChannel } from './types';\n\nconst CHANNEL_INDEX: Record<MockupDisplacementChannel, number> = {\n red: 0,\n green: 1,\n blue: 2,\n alpha: 3,\n};\n\nfunction finiteScale(value: number | undefined, fallback: number, label: string): number {\n const resolved = value ?? fallback;\n if (!Number.isFinite(resolved)) throw new Error(`${label} must be finite`);\n return resolved;\n}\n\nfunction sample(\n source: Uint8ClampedArray,\n width: number,\n height: number,\n x: number,\n y: number,\n channel: number,\n): number {\n const clampedX = Math.max(0, Math.min(width - 1, x));\n const clampedY = Math.max(0, Math.min(height - 1, y));\n const x0 = Math.floor(clampedX);\n const y0 = Math.floor(clampedY);\n const x1 = Math.min(width - 1, x0 + 1);\n const y1 = Math.min(height - 1, y0 + 1);\n const tx = clampedX - x0;\n const ty = clampedY - y0;\n const top =\n source[(y0 * width + x0) * 4 + channel] * (1 - tx) +\n source[(y0 * width + x1) * 4 + channel] * tx;\n const bottom =\n source[(y1 * width + x0) * 4 + channel] * (1 - tx) +\n source[(y1 * width + x1) * 4 + channel] * tx;\n return top * (1 - ty) + bottom * ty;\n}\n\n/**\n * Warp RGBA pixels with an equally sized channel map. A channel value of 128\n * is neutral; 0 and 255 move by the configured negative/positive maximum.\n */\nexport function displaceRgba(\n source: Uint8ClampedArray,\n map: Uint8ClampedArray,\n width: number,\n height: number,\n options: Omit<MockupDisplacement, 'image'>,\n): Uint8ClampedArray {\n if (!Number.isInteger(width) || !Number.isInteger(height) || width <= 0 || height <= 0) {\n throw new Error('Displacement dimensions must be positive integers');\n }\n const expectedLength = width * height * 4;\n if (source.length !== expectedLength || map.length !== expectedLength) {\n throw new Error('Displacement source and map must match the requested dimensions');\n }\n\n const scaleX = finiteScale(options.scaleX, 10, 'Displacement scaleX');\n const scaleY = finiteScale(options.scaleY, 10, 'Displacement scaleY');\n const channelX = CHANNEL_INDEX[options.channelX ?? 'red'];\n const channelY = CHANNEL_INDEX[options.channelY ?? 'green'];\n const output = new Uint8ClampedArray(expectedLength);\n\n for (let y = 0; y < height; y += 1) {\n for (let x = 0; x < width; x += 1) {\n const offset = (y * width + x) * 4;\n const sourceX = x + ((map[offset + channelX] - 128) / 127) * scaleX;\n const sourceY = y + ((map[offset + channelY] - 128) / 127) * scaleY;\n for (let channel = 0; channel < 4; channel += 1) {\n output[offset + channel] = Math.round(\n sample(source, width, height, sourceX, sourceY, channel),\n );\n }\n }\n }\n return output;\n}\n","import { StaticCanvas } from 'fabric';\nimport type { Canvas, FabricObject, ImageFormat } from 'fabric';\nimport type { MockupConfig, MockupPrintArea } from './types';\nimport { displaceRgba } from './displacement';\n\nexport interface PngExportOptions {\n multiplier?: number;\n format?: ImageFormat;\n quality?: number;\n}\n\nexport interface CoverPlacement {\n left: number;\n top: number;\n width: number;\n height: number;\n}\n\nexport function computePrintAreaClip(\n area: MockupPrintArea,\n scaleX: number,\n scaleY: number,\n targetWidth: number,\n targetHeight: number,\n): MockupPrintArea {\n const left = Math.max(0, Math.min(targetWidth, area.left * scaleX));\n const top = Math.max(0, Math.min(targetHeight, area.top * scaleY));\n const right = Math.max(left, Math.min(targetWidth, (area.left + area.width) * scaleX));\n const bottom = Math.max(top, Math.min(targetHeight, (area.top + area.height) * scaleY));\n return { left, top, width: right - left, height: bottom - top };\n}\n\n/** Object-fit: cover geometry, exported for deterministic preview/composite tests. */\nexport function computeCoverPlacement(\n sourceWidth: number,\n sourceHeight: number,\n targetWidth: number,\n targetHeight: number,\n): CoverPlacement {\n if (sourceWidth <= 0 || sourceHeight <= 0 || targetWidth <= 0 || targetHeight <= 0) {\n throw new Error('Cover dimensions must be positive');\n }\n const scale = Math.max(targetWidth / sourceWidth, targetHeight / sourceHeight);\n const width = sourceWidth * scale;\n const height = sourceHeight * scale;\n return {\n left: (targetWidth - width) / 2,\n top: (targetHeight - height) / 2,\n width,\n height,\n };\n}\n\nfunction canvasElementToBlob(\n output: HTMLCanvasElement,\n format: ImageFormat,\n quality: number,\n): Promise<Blob> {\n const mime = format === 'jpeg' ? 'image/jpeg' : `image/${format}`;\n return new Promise<Blob>((resolve, reject) => {\n output.toBlob(\n (blob) => (blob ? resolve(blob) : reject(new Error(`Failed to export ${format}`))),\n mime,\n quality,\n );\n });\n}\n\nexport async function exportPNG(canvas: Canvas, options: PngExportOptions = {}): Promise<Blob> {\n const { multiplier = 1, format = 'png' as ImageFormat, quality = 1 } = options;\n const output = canvas.toCanvasElement(multiplier);\n return canvasElementToBlob(output, format, quality);\n}\n\n/** Render cloned objects without mutating the live editor canvas. */\nexport async function exportIsolatedPNG(\n source: Canvas,\n objects: FabricObject[],\n options: PngExportOptions & {\n width?: number;\n height?: number;\n backgroundColor?: string;\n backgroundImage?: FabricObject | null;\n cloneObjects?: boolean;\n } = {},\n): Promise<Blob> {\n const element = source.lowerCanvasEl.ownerDocument.createElement('canvas');\n const canvas = new StaticCanvas(element, {\n width: options.width ?? source.getWidth(),\n height: options.height ?? source.getHeight(),\n backgroundColor: options.backgroundColor || undefined,\n });\n try {\n const clones =\n options.cloneObjects === false\n ? objects\n : await Promise.all(objects.map((object) => object.clone()));\n if (clones.length) canvas.add(...clones);\n if (options.backgroundImage) canvas.backgroundImage = await options.backgroundImage.clone();\n canvas.requestRenderAll();\n // Awaited, not returned: `finally` would otherwise dispose the canvas while\n // the export is still reading from it.\n return await exportPNG(canvas as unknown as Canvas, options);\n } finally {\n canvas.dispose();\n }\n}\n\n/** Rasterize the browser mockup preview together with the transparent design. */\nexport async function exportMockup(\n canvas: Canvas,\n mockup: MockupConfig,\n options: PngExportOptions = {},\n): Promise<Blob> {\n const { multiplier = 1, format = 'png' as ImageFormat, quality = 1 } = options;\n const design = canvas.toCanvasElement(multiplier);\n const output = design.ownerDocument.createElement('canvas');\n output.width = design.width;\n output.height = design.height;\n const context = output.getContext('2d');\n if (!context) throw new Error('2D canvas context is unavailable');\n\n const loadImage = (url: string) =>\n new Promise<HTMLImageElement>((resolve, reject) => {\n const element = new Image();\n element.crossOrigin = 'anonymous';\n element.onload = () => resolve(element);\n element.onerror = () => reject(new Error(`Failed to load mockup image: ${url}`));\n element.src = url;\n });\n const drawCover = (\n image: HTMLImageElement,\n targetContext: CanvasRenderingContext2D = context,\n ) => {\n const placement = computeCoverPlacement(\n image.naturalWidth || image.width,\n image.naturalHeight || image.height,\n output.width,\n output.height,\n );\n targetContext.drawImage(\n image,\n placement.left,\n placement.top,\n placement.width,\n placement.height,\n );\n };\n\n // Full-size scratch buffers, released explicitly in the finally below: a\n // detached canvas element can hold its backing store well past its last\n // reference, and a 4K mockup allocates three of them per export.\n const scratch: HTMLCanvasElement[] = [design];\n try {\n drawCover(await loadImage(mockup.image));\n let compositedDesign: CanvasImageSource = design;\n if (mockup.displacement) {\n const sourceContext = design.getContext('2d');\n if (!sourceContext) throw new Error('2D design context is unavailable');\n const mapCanvas = design.ownerDocument.createElement('canvas');\n scratch.push(mapCanvas);\n mapCanvas.width = design.width;\n mapCanvas.height = design.height;\n const mapContext = mapCanvas.getContext('2d');\n if (!mapContext) throw new Error('2D displacement-map context is unavailable');\n drawCover(await loadImage(mockup.displacement.image), mapContext);\n\n const warped = design.ownerDocument.createElement('canvas');\n scratch.push(warped);\n warped.width = design.width;\n warped.height = design.height;\n const warpedContext = warped.getContext('2d');\n if (!warpedContext) throw new Error('2D displaced-design context is unavailable');\n let sourcePixels: Uint8ClampedArray;\n let mapPixels: Uint8ClampedArray;\n try {\n sourcePixels = sourceContext.getImageData(0, 0, design.width, design.height).data;\n mapPixels = mapContext.getImageData(0, 0, design.width, design.height).data;\n } catch (error) {\n throw new Error('Failed to apply mockup displacement map; verify image CORS access', {\n cause: error,\n });\n }\n const pixels = displaceRgba(sourcePixels, mapPixels, design.width, design.height, {\n ...mockup.displacement,\n scaleX: (mockup.displacement.scaleX ?? 10) * multiplier,\n scaleY: (mockup.displacement.scaleY ?? 10) * multiplier,\n });\n const imageData = warpedContext.createImageData(design.width, design.height);\n imageData.data.set(pixels);\n warpedContext.putImageData(imageData, 0, 0);\n compositedDesign = warped;\n }\n context.save();\n if (mockup.printArea && mockup.clipToPrintArea !== false) {\n const clip = computePrintAreaClip(\n mockup.printArea,\n output.width / canvas.getWidth(),\n output.height / canvas.getHeight(),\n output.width,\n output.height,\n );\n context.beginPath();\n context.rect(clip.left, clip.top, clip.width, clip.height);\n context.clip();\n }\n context.globalAlpha = Math.max(0, Math.min(1, mockup.designOpacity ?? 1));\n context.globalCompositeOperation =\n !mockup.designBlendMode || mockup.designBlendMode === 'normal'\n ? 'source-over'\n : mockup.designBlendMode;\n context.drawImage(compositedDesign, 0, 0);\n context.restore();\n\n if (mockup.overlay) {\n context.save();\n context.globalAlpha = Math.max(0, Math.min(1, mockup.overlay.opacity ?? 1));\n context.globalCompositeOperation =\n mockup.overlay.blendMode === 'normal'\n ? 'source-over'\n : (mockup.overlay.blendMode ?? 'multiply');\n drawCover(await loadImage(mockup.overlay.image));\n context.restore();\n }\n return await canvasElementToBlob(output, format, quality);\n } finally {\n for (const element of scratch) {\n element.width = 0;\n element.height = 0;\n }\n }\n}\n\nexport function exportSVG(canvas: Canvas): string {\n return canvas.toSVG();\n}\n\nexport function exportDataURL(canvas: Canvas, format: ImageFormat = 'png', multiplier = 1): string {\n return canvas.toDataURL({ format, multiplier });\n}\n","import type { EditorState } from './types';\nimport type { NodeRenderOptions } from './node';\n\nexport interface PrintPdfOptions {\n /** Rasterization density. Defaults to the document DPI, or 300. */\n dpi?: number;\n /** Bleed on every edge, in inches. Defaults to 0.125in. */\n bleed?: number;\n /** Space outside bleed reserved for printer marks, in inches. Defaults to 0.25in. */\n marksMargin?: number;\n trimMarks?: boolean;\n registrationMarks?: boolean;\n /** Optional safe-area inset in inches for preflight warnings. */\n safeArea?: number;\n /** Sharp built-in `cmyk` profile or an absolute path to a custom ICC profile. */\n iccProfile?: string;\n /** Ceiling on the rasterized bleed image, in pixels. Defaults to 250 megapixels. */\n maxPixels?: number;\n outputConditionIdentifier?: string;\n title?: string;\n allowImageUrl?: NodeRenderOptions['allowImageUrl'];\n /** Preserve SVG shapes/text over a CMYK bleed raster. Defaults to `vector`. */\n rendering?: 'vector' | 'raster';\n /** PDFKit font registrations keyed by the exact SVG font-family name. */\n fontFiles?: Record<string, string | Uint8Array>;\n /** Convert text backed by `fontFiles` into glyph paths. Defaults to true. */\n outlineFonts?: boolean;\n}\n\nexport interface PrintPdfResult {\n format: 'pdf';\n mimeType: 'application/pdf';\n data: Uint8Array;\n standard: 'PDF/X-4';\n colourSpace: 'CMYK';\n rendering: 'vector' | 'raster';\n outlinedFonts: string[];\n unoutlinedFonts: string[];\n dpi: number;\n trimWidthPoints: number;\n trimHeightPoints: number;\n bleedPoints: number;\n warnings: string[];\n}\n\nfunction svgAttributes(source: string): Record<string, string> {\n return Object.fromEntries(\n [...source.matchAll(/([\\w:-]+)=(?:\"([^\"]*)\"|'([^']*)')/g)].map((match) => [\n match[1],\n match[2] ?? match[3] ?? '',\n ]),\n );\n}\n\nfunction decodeXmlText(source: string): string {\n return source\n .replace(/<[^>]+>/g, '')\n .replace(/&#x([\\da-f]+);/gi, (_, value: string) =>\n String.fromCodePoint(Number.parseInt(value, 16)),\n )\n .replace(/&#(\\d+);/g, (_, value: string) => String.fromCodePoint(Number(value)))\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/"/g, '\"')\n .replace(/'/g, \"'\")\n .replace(/&/g, '&');\n}\n\nfunction escapeXmlAttribute(value: string): string {\n return value.replace(/[<>&\"']/g, (character) => `&#${character.charCodeAt(0)};`);\n}\n\nfunction fontSource(\n files: Record<string, string | Uint8Array>,\n family: string,\n bold: boolean,\n italic: boolean,\n): string | Uint8Array | undefined {\n const suffix = bold && italic ? '-BoldItalic' : bold ? '-Bold' : italic ? '-Italic' : '';\n // `family` comes from the untrusted SVG, so plain indexing would resolve\n // `__proto__`/`constructor` to inherited members and hand a non-font to fontkit.\n const own = (key: string) =>\n Object.hasOwn(files, key) ? (files[key] as string | Uint8Array) : undefined;\n return own(`${family}${suffix}`) ?? own(family);\n}\n\nasync function outlineSvgText(\n svg: string,\n files: Record<string, string | Uint8Array>,\n outlined: Set<string>,\n): Promise<string> {\n const fontkit = await import('fontkit');\n let output = '';\n let cursor = 0;\n for (const textMatch of svg.matchAll(/<text\\b([^>]*)>([\\s\\S]*?)<\\/text>/gi)) {\n const index = textMatch.index ?? 0;\n output += svg.slice(cursor, index);\n cursor = index + textMatch[0].length;\n const textAttributes = svgAttributes(textMatch[1]);\n const spans = [...textMatch[2].matchAll(/<tspan\\b([^>]*)>([\\s\\S]*?)<\\/tspan>/gi)];\n const lines = spans.length\n ? spans.map((span) => ({ attributes: svgAttributes(span[1]), text: decodeXmlText(span[2]) }))\n : [{ attributes: textAttributes, text: decodeXmlText(textMatch[2]) }];\n const resolved = lines.map((line) => {\n const attributes = { ...textAttributes, ...line.attributes };\n const family = attributes['font-family'] ?? 'sans-serif';\n const bold = /bold|[6-9]00/i.test(attributes['font-weight'] ?? '');\n const italic = /italic|oblique/i.test(attributes['font-style'] ?? '');\n return { ...line, attributes, family, source: fontSource(files, family, bold, italic) };\n });\n if (resolved.some((line) => !line.source)) {\n output += textMatch[0];\n continue;\n }\n const paths: string[] = [];\n for (const line of resolved) {\n const source = line.source!;\n const opened =\n typeof source === 'string'\n ? fontkit.openSync(source)\n : fontkit.create(Buffer.from(source.buffer, source.byteOffset, source.byteLength));\n if (!('layout' in opened)) {\n throw new Error(`Font collection requires a named face: ${line.family}`);\n }\n const size = Number.parseFloat(line.attributes['font-size'] ?? '16');\n const scale = size / opened.unitsPerEm;\n const style = line.attributes.style ?? '';\n const run = opened.layout(line.text);\n let penX = Number.parseFloat(line.attributes.x ?? '0');\n const baseline = Number.parseFloat(line.attributes.y ?? '0');\n run.glyphs.forEach((glyph, glyphIndex) => {\n const position = run.positions[glyphIndex];\n const x = penX + position.xOffset * scale;\n const y = baseline - position.yOffset * scale;\n paths.push(\n `<path d=\"${glyph.path.toSVG()}\" transform=\"translate(${x} ${y}) scale(${scale} ${-scale})\" style=\"${escapeXmlAttribute(style)}\"/>`,\n );\n penX += position.xAdvance * scale;\n });\n outlined.add(line.family);\n }\n output += `<g data-outlined-font=\"${escapeXmlAttribute([...new Set(resolved.map((line) => line.family))].join(','))}\">${paths.join('')}</g>`;\n }\n return output + svg.slice(cursor);\n}\n\nfunction rgbToCmyk([redByte, greenByte, blueByte]: [number, number, number]): [\n number,\n number,\n number,\n number,\n] {\n const red = redByte / 255;\n const green = greenByte / 255;\n const blue = blueByte / 255;\n const black = 1 - Math.max(red, green, blue);\n if (black >= 1) return [0, 0, 0, 100];\n return [\n ((1 - red - black) / (1 - black)) * 100,\n ((1 - green - black) / (1 - black)) * 100,\n ((1 - blue - black) / (1 - black)) * 100,\n black * 100,\n ];\n}\n\nasync function imageSourceBytes(\n source: string,\n allow?: (url: string) => boolean,\n): Promise<Uint8Array> {\n if (source.startsWith('data:')) {\n const response = await fetch(source);\n if (!response.ok) throw new Error('Failed to decode an embedded SVG image');\n return new Uint8Array(await response.arrayBuffer());\n }\n const permitted = allow\n ? allow(source)\n : (() => {\n try {\n return ['http:', 'https:'].includes(new URL(source).protocol);\n } catch {\n return false;\n }\n })();\n if (!permitted) throw new Error(`Blocked disallowed vector image URL: ${source}`);\n const response = await fetch(source);\n if (!response.ok) throw new Error(`Failed to load vector image: ${source}`);\n return new Uint8Array(await response.arrayBuffer());\n}\n\nasync function convertSvgImagesToCmyk(\n svg: string,\n sharp: (typeof import('sharp'))['default'],\n profile: string,\n allow?: (url: string) => boolean,\n): Promise<string> {\n const sources = new Set<string>();\n for (const image of svg.matchAll(/<image\\b[^>]*(?:xlink:href|href)=\"([^\"]+)\"[^>]*>/gi)) {\n if (image[1]) sources.add(image[1]);\n }\n let converted = svg;\n for (const source of sources) {\n const bytes = await imageSourceBytes(source, allow);\n const jpeg = await sharp(bytes)\n .flatten({ background: '#ffffff' })\n .toColourspace('cmyk')\n .withIccProfile(profile)\n .jpeg({ quality: 100, chromaSubsampling: '4:4:4' })\n .toBuffer();\n const dataUrl = `data:image/jpeg;base64,${jpeg.toString('base64')}`;\n converted = converted.split(source).join(dataUrl);\n }\n return converted;\n}\n\nasync function renderVectorOverlay(\n state: EditorState,\n options: PrintPdfOptions,\n width: number,\n height: number,\n sharp: (typeof import('sharp'))['default'],\n warnings: string[],\n outlinedFonts: Set<string>,\n unoutlinedFonts: Set<string>,\n): Promise<Uint8Array> {\n const [{ default: PDFKit }, { default: SVGtoPDF }, { renderEditorState }] = await Promise.all([\n import('pdfkit'),\n import('svg-to-pdfkit'),\n import('./node'),\n ]);\n // The bleed image is already flattened onto white. Render the trim overlay\n // against the same opaque print substrate so semi-transparent artwork does\n // not blend a second time with the raster copy beneath it.\n const rendered = await renderEditorState(\n { ...state, background: '#ffffff' },\n {\n format: 'svg',\n allowImageUrl: options.allowImageUrl,\n },\n );\n if (typeof rendered.data !== 'string') throw new Error('Vector rendering returned raster data');\n const fontFiles = options.fontFiles ?? {};\n const outlinedSvg =\n options.outlineFonts === false\n ? rendered.data\n : await outlineSvgText(rendered.data, fontFiles, outlinedFonts);\n const svg = await convertSvgImagesToCmyk(\n outlinedSvg,\n sharp,\n options.iccProfile ?? 'cmyk',\n options.allowImageUrl,\n );\n const remainingText = [...svg.matchAll(/<text\\b([^>]*)>/gi)].map((match) =>\n svgAttributes(match[1]),\n );\n for (const attributes of remainingText) {\n const family = attributes['font-family'] ?? 'sans-serif';\n unoutlinedFonts.add(family);\n const bold = /bold|[6-9]00/i.test(attributes['font-weight'] ?? '');\n const italic = /italic|oblique/i.test(attributes['font-style'] ?? '');\n if (!fontSource(fontFiles, family, bold, italic)) {\n warnings.push(\n `Font \"${family}\" used a PDF standard fallback; supply fontFiles for exact embedding`,\n );\n }\n }\n\n const document = new PDFKit({ autoFirstPage: false, compress: false, pdfVersion: '1.7' });\n for (const [name, path] of Object.entries(fontFiles)) {\n document.registerFont(name, typeof path === 'string' ? path : Buffer.from(path));\n }\n document.addPage({ size: [width, height], margin: 0 });\n SVGtoPDF(document, svg, 0, 0, {\n width,\n height,\n preserveAspectRatio: 'none',\n colorCallback: (color) => {\n const [rgb, opacity] = color;\n return [rgbToCmyk(rgb), opacity] as unknown as typeof color;\n },\n warningCallback: (warning) => warnings.push(`Vector render: ${warning}`),\n });\n\n return new Promise<Uint8Array>((resolve, reject) => {\n const chunks: Uint8Array[] = [];\n document.on('data', (chunk: Uint8Array) => chunks.push(chunk));\n document.on('error', reject);\n document.on('end', () => resolve(new Uint8Array(Buffer.concat(chunks))));\n document.end();\n });\n}\n\n/** Beyond this no printer is served, and larger values only buy an OOM. */\nconst MAX_DPI = 2400;\n/** ~24×36in at 600dpi. Bounds the raster a hostile state can ask a server for. */\nconst DEFAULT_MAX_PIXELS = 250_000_000;\n\nfunction positive(value: number, label: string): number {\n if (!Number.isFinite(value) || value <= 0) throw new Error(`${label} must be positive`);\n return value;\n}\n\n/**\n * States are browser-authored and untrusted on a server. `documentDpi` divides\n * the render multiplier, so an unvalidated fractional value (0.001) inflates the\n * rasterization by six orders of magnitude before any size check runs.\n */\nfunction boundedDpi(value: number, label: string): number {\n const dpi = positive(value, label);\n if (dpi > MAX_DPI) throw new Error(`${label} must not exceed ${MAX_DPI}`);\n if (dpi < 1) throw new Error(`${label} must be at least 1`);\n return dpi;\n}\n\nfunction nonNegative(value: number, label: string): number {\n if (!Number.isFinite(value) || value < 0) throw new Error(`${label} cannot be negative`);\n return value;\n}\n\nfunction preflightSafeArea(state: EditorState, safePixels: number): string[] {\n if (safePixels <= 0) return [];\n const right = state.canvas.width - safePixels;\n const bottom = state.canvas.height - safePixels;\n const warnings: string[] = [];\n for (const layer of state.layers) {\n if (!layer.visible) continue;\n const object = layer.fabricObject;\n const left = Number(object.left ?? 0);\n const top = Number(object.top ?? 0);\n const width = Number(object.width ?? 0) * Math.abs(Number(object.scaleX ?? 1));\n const height = Number(object.height ?? 0) * Math.abs(Number(object.scaleY ?? 1));\n if (left < safePixels || top < safePixels || left + width > right || top + height > bottom) {\n warnings.push(`Layer \"${layer.name}\" extends outside the configured safe area`);\n }\n }\n return warnings;\n}\n\n/**\n * Render an EditorState into a print-production PDF/X-4 file.\n *\n * The design is rasterized at the requested density, converted through Sharp's\n * CMYK ICC pipeline, edge-extended into bleed, and embedded with output intent,\n * trim/bleed boxes, XMP identification, and optional printer marks.\n */\nexport async function renderPrintPdf(\n state: EditorState,\n options: PrintPdfOptions = {},\n): Promise<PrintPdfResult> {\n const dpi = boundedDpi(options.dpi ?? state.canvas.dpi ?? 300, 'Print DPI');\n const documentDpi = boundedDpi(state.canvas.dpi ?? 72, 'Document DPI');\n const maxPixels = positive(options.maxPixels ?? DEFAULT_MAX_PIXELS, 'Max pixels');\n const bleedInches = nonNegative(options.bleed ?? 0.125, 'Bleed');\n const marksMarginInches = nonNegative(options.marksMargin ?? 0.25, 'Marks margin');\n const safeAreaInches = nonNegative(options.safeArea ?? 0, 'Safe area');\n const rendering = options.rendering ?? 'vector';\n const bleedPixels = Math.round(bleedInches * dpi);\n const trimWidthPoints = (state.canvas.width / documentDpi) * 72;\n const trimHeightPoints = (state.canvas.height / documentDpi) * 72;\n const bleedPoints = bleedInches * 72;\n const marksMarginPoints = marksMarginInches * 72;\n\n const scale = dpi / documentDpi;\n const outputPixels =\n Math.round(state.canvas.width * scale + bleedPixels * 2) *\n Math.round(state.canvas.height * scale + bleedPixels * 2);\n if (!Number.isFinite(outputPixels) || outputPixels > maxPixels) {\n throw new Error(\n `Print raster of ${outputPixels} pixels exceeds the ${maxPixels} pixel budget; lower the DPI or raise maxPixels`,\n );\n }\n\n const [{ default: sharp }, pdfLib] = await Promise.all([import('sharp'), import('pdf-lib')]);\n // Keep the optional print entry free of a static cycle with `node.ts`, which\n // re-exports this function as part of the Node-only public surface.\n const { renderEditorState } = await import('./node');\n const rendered = await renderEditorState(state, {\n format: 'png',\n multiplier: scale,\n allowImageUrl: options.allowImageUrl,\n });\n if (typeof rendered.data === 'string') throw new Error('Print rasterization returned SVG data');\n\n let pipeline = sharp(rendered.data).flatten({ background: '#ffffff' });\n if (bleedPixels > 0) {\n pipeline = pipeline.extend({\n top: bleedPixels,\n right: bleedPixels,\n bottom: bleedPixels,\n left: bleedPixels,\n extendWith: 'copy',\n });\n }\n const { data: cmykJpeg, info } = await pipeline\n .toColourspace('cmyk')\n .withIccProfile(options.iccProfile ?? 'cmyk')\n .withDensity(dpi)\n .jpeg({ quality: 100, chromaSubsampling: '4:4:4' })\n .toBuffer({ resolveWithObject: true });\n const metadata = await sharp(cmykJpeg).metadata();\n if (info.channels !== 4 || metadata.space !== 'cmyk' || !metadata.icc) {\n throw new Error('CMYK conversion did not produce a four-channel image with an ICC profile');\n }\n\n const { PDFDocument, PDFDict, PDFName, PDFString, cmyk } = pdfLib;\n const document = await PDFDocument.create();\n const title = options.title ?? 'Overtone Canvas Editor print export';\n document.setTitle(title);\n document.setCreator('@overtone-art/canvas-editor-core');\n document.setProducer('@overtone-art/canvas-editor-core');\n const pageWidth = trimWidthPoints + bleedPoints * 2 + marksMarginPoints * 2;\n const pageHeight = trimHeightPoints + bleedPoints * 2 + marksMarginPoints * 2;\n const page = document.addPage([pageWidth, pageHeight]);\n const image = await document.embedJpg(cmykJpeg);\n page.drawImage(image, {\n x: marksMarginPoints,\n y: marksMarginPoints,\n width: trimWidthPoints + bleedPoints * 2,\n height: trimHeightPoints + bleedPoints * 2,\n });\n\n const trimLeft = marksMarginPoints + bleedPoints;\n const trimBottom = marksMarginPoints + bleedPoints;\n const trimRight = trimLeft + trimWidthPoints;\n const trimTop = trimBottom + trimHeightPoints;\n const warnings = preflightSafeArea(state, safeAreaInches * documentDpi);\n const outlinedFonts = new Set<string>();\n const unoutlinedFonts = new Set<string>();\n if (rendering === 'vector') {\n const vectorPdf = await renderVectorOverlay(\n state,\n options,\n trimWidthPoints,\n trimHeightPoints,\n sharp,\n warnings,\n outlinedFonts,\n unoutlinedFonts,\n );\n const [vectorPage] = await document.embedPdf(vectorPdf);\n page.drawPage(vectorPage, {\n x: trimLeft,\n y: trimBottom,\n width: trimWidthPoints,\n height: trimHeightPoints,\n });\n }\n const bleedLeft = marksMarginPoints;\n const bleedBottom = marksMarginPoints;\n const bleedRight = pageWidth - marksMarginPoints;\n const bleedTop = pageHeight - marksMarginPoints;\n const context = document.context;\n page.node.set(PDFName.of('TrimBox'), context.obj([trimLeft, trimBottom, trimRight, trimTop]));\n page.node.set(\n PDFName.of('BleedBox'),\n context.obj([bleedLeft, bleedBottom, bleedRight, bleedTop]),\n );\n page.node.set(PDFName.of('ArtBox'), context.obj([trimLeft, trimBottom, trimRight, trimTop]));\n\n const markColour = cmyk(0, 0, 0, 1);\n if (options.trimMarks !== false) {\n const offset = Math.max(3, bleedPoints / 2);\n const length = Math.max(9, marksMarginPoints - 3);\n for (const x of [trimLeft, trimRight]) {\n page.drawLine({\n start: { x, y: trimBottom - offset },\n end: { x, y: trimBottom - offset - length },\n thickness: 0.5,\n color: markColour,\n });\n page.drawLine({\n start: { x, y: trimTop + offset },\n end: { x, y: trimTop + offset + length },\n thickness: 0.5,\n color: markColour,\n });\n }\n for (const y of [trimBottom, trimTop]) {\n page.drawLine({\n start: { x: trimLeft - offset, y },\n end: { x: trimLeft - offset - length, y },\n thickness: 0.5,\n color: markColour,\n });\n page.drawLine({\n start: { x: trimRight + offset, y },\n end: { x: trimRight + offset + length, y },\n thickness: 0.5,\n color: markColour,\n });\n }\n }\n if (options.registrationMarks !== false) {\n for (const [x, y] of [\n [pageWidth / 2, marksMarginPoints / 2],\n [pageWidth / 2, pageHeight - marksMarginPoints / 2],\n [marksMarginPoints / 2, pageHeight / 2],\n [pageWidth - marksMarginPoints / 2, pageHeight / 2],\n ] as Array<[number, number]>) {\n page.drawCircle({ x, y, size: 4, borderWidth: 0.5, borderColor: markColour });\n page.drawLine({\n start: { x: x - 6, y },\n end: { x: x + 6, y },\n thickness: 0.5,\n color: markColour,\n });\n page.drawLine({\n start: { x, y: y - 6 },\n end: { x, y: y + 6 },\n thickness: 0.5,\n color: markColour,\n });\n }\n }\n\n const profileStream = context.flateStream(metadata.icc, {\n N: 4,\n Alternate: PDFName.of('DeviceCMYK'),\n });\n const profileRef = context.register(profileStream);\n const outputIntent = context.obj({\n Type: PDFName.of('OutputIntent'),\n S: PDFName.of('GTS_PDFX'),\n OutputConditionIdentifier: PDFString.of(options.outputConditionIdentifier ?? 'CMYK'),\n RegistryName: PDFString.of('https://www.color.org'),\n Info: PDFString.of(options.outputConditionIdentifier ?? 'CMYK print condition'),\n DestOutputProfile: profileRef,\n });\n document.catalog.set(PDFName.of('OutputIntents'), context.obj([context.register(outputIntent)]));\n\n const now = new Date().toISOString();\n const xmp = `<?xpacket begin=\"\" id=\"W5M0MpCehiHzreSzNTczkc9d\"?>\n<x:xmpmeta xmlns:x=\"adobe:ns:meta/\"><rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">\n<rdf:Description rdf:about=\"\" xmlns:pdfxid=\"http://www.npes.org/pdfx/ns/id/\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:xmp=\"http://ns.adobe.com/xap/1.0/\" pdfxid:GTS_PDFXVersion=\"PDF/X-4\" xmp:CreateDate=\"${now}\"><dc:title><rdf:Alt><rdf:li xml:lang=\"x-default\">${title.replace(/[<>&]/g, '')}</rdf:li></rdf:Alt></dc:title></rdf:Description>\n</rdf:RDF></x:xmpmeta><?xpacket end=\"w\"?>`;\n const metadataStream = context.flateStream(new TextEncoder().encode(xmp), {\n Type: PDFName.of('Metadata'),\n Subtype: PDFName.of('XML'),\n });\n document.catalog.set(PDFName.of('Metadata'), context.register(metadataStream));\n const infoRef = context.trailerInfo.Info;\n if (infoRef) {\n const infoDict = context.lookup(infoRef, PDFDict);\n infoDict.set(PDFName.of('GTS_PDFXVersion'), PDFString.of('PDF/X-4'));\n infoDict.set(PDFName.of('Trapped'), PDFName.of('False'));\n }\n\n return {\n format: 'pdf',\n mimeType: 'application/pdf',\n data: await document.save({ useObjectStreams: false }),\n standard: 'PDF/X-4',\n colourSpace: 'CMYK',\n rendering,\n outlinedFonts: [...outlinedFonts].sort(),\n unoutlinedFonts: [...unoutlinedFonts].sort(),\n dpi,\n trimWidthPoints,\n trimHeightPoints,\n bleedPoints,\n warnings,\n };\n}\n","import { FabricImage, Rect, StaticCanvas, util } from 'fabric/node';\nimport type { FabricObject, ImageFormat } from 'fabric/node';\nimport { computeCoverPlacement, computePrintAreaClip } from './export';\nimport { displaceRgba } from './displacement';\nimport type { EditorState, MockupBlendMode, MockupConfig, MockupDisplacement } from './types';\n\nexport { renderPrintPdf } from './print';\nexport type { PrintPdfOptions, PrintPdfResult } from './print';\n\nexport interface NodeRenderOptions {\n format?: 'png' | 'jpeg' | 'webp' | 'svg';\n multiplier?: number;\n quality?: number;\n /**\n * Gate every image URL referenced by the state before it is loaded. States\n * are authored in the browser and therefore untrusted on a server; the\n * default policy allows only `http:`, `https:` and `data:`. Supply a\n * narrower predicate (e.g. an origin allowlist) to also stop requests to\n * internal hosts.\n */\n allowImageUrl?: (url: string) => boolean;\n}\n\nexport interface NodeRenderResult {\n format: 'png' | 'jpeg' | 'webp' | 'svg';\n mimeType: string;\n data: Uint8Array | string;\n width: number;\n height: number;\n}\n\n// `fabric/node` resolves bare paths and `file:` URLs against the local disk, so\n// an unrestricted state is a local-file-read and SSRF primitive on a server.\nconst ALLOWED_PROTOCOLS = new Set(['http:', 'https:', 'data:']);\n\n/** Keys whose string values are fetched as images during a render. */\nconst URL_KEYS = new Set(['src', 'image']);\n\nfunction defaultAllowImageUrl(url: string): boolean {\n const scheme = /^([a-z][a-z\\d+.-]*):/i.exec(url.trim());\n return scheme !== null && ALLOWED_PROTOCOLS.has(`${scheme[1].toLowerCase()}:`);\n}\n\nfunction assertImageUrlsAllowed(value: unknown, allow: (url: string) => boolean): void {\n if (Array.isArray(value)) {\n for (const item of value) assertImageUrlsAllowed(item, allow);\n return;\n }\n if (!value || typeof value !== 'object') return;\n for (const [key, entry] of Object.entries(value)) {\n if (typeof entry === 'string') {\n if (URL_KEYS.has(key) && !allow(entry)) {\n throw new Error(`Blocked disallowed image URL: ${entry.slice(0, 120)}`);\n }\n } else {\n assertImageUrlsAllowed(entry, allow);\n }\n }\n}\n\nfunction validateState(state: EditorState): void {\n if (\n !state?.canvas ||\n !Array.isArray(state.layers) ||\n !Number.isFinite(state.canvas.width) ||\n !Number.isFinite(state.canvas.height) ||\n state.canvas.width <= 0 ||\n state.canvas.height <= 0\n ) {\n throw new Error('Invalid editor state');\n }\n const major = Number.parseInt(state.version?.split('.')[0] ?? '1', 10);\n if (!Number.isFinite(major) || major > 2) {\n throw new Error(`Unsupported editor state version: ${state.version}`);\n }\n}\n\nfunction dataUrlBytes(dataUrl: string): Uint8Array {\n const encoded = dataUrl.slice(dataUrl.indexOf(',') + 1);\n const binary = atob(encoded);\n const bytes = new Uint8Array(binary.length);\n for (let index = 0; index < binary.length; index += 1) bytes[index] = binary.charCodeAt(index);\n return bytes;\n}\n\nfunction validateOptions(options: NodeRenderOptions): Required<NodeRenderOptions> {\n const format = options.format ?? 'png';\n const multiplier = options.multiplier ?? 1;\n const quality = options.quality ?? 1;\n const allowImageUrl = options.allowImageUrl ?? defaultAllowImageUrl;\n if (!Number.isFinite(multiplier) || multiplier <= 0) {\n throw new Error('Render multiplier must be positive');\n }\n if (!Number.isFinite(quality) || quality < 0 || quality > 1) {\n throw new Error('Render quality must be between 0 and 1');\n }\n return { format, multiplier, quality, allowImageUrl };\n}\n\nasync function createStateCanvas(state: EditorState, transparent = false): Promise<StaticCanvas> {\n const canvas = new StaticCanvas(undefined, {\n width: state.canvas.width,\n height: state.canvas.height,\n backgroundColor: transparent ? '' : (state.background ?? ''),\n preserveObjectStacking: true,\n });\n try {\n if (!transparent && state.backgroundImage) {\n canvas.backgroundImage = (\n await util.enlivenObjects([state.backgroundImage])\n )[0] as FabricObject;\n }\n const objects = (await util.enlivenObjects(\n state.layers.map((layer) => layer.fabricObject),\n )) as FabricObject[];\n objects.forEach((object, index) => {\n const layer = state.layers[index];\n object.set({ visible: layer.visible, opacity: layer.opacity });\n canvas.add(object);\n });\n canvas.renderAll();\n return canvas;\n } catch (error) {\n canvas.dispose();\n throw error;\n }\n}\n\nfunction encodeCanvas(\n canvas: StaticCanvas,\n options: Required<NodeRenderOptions>,\n): NodeRenderResult {\n const { format, multiplier, quality } = options;\n const width = Math.round(canvas.getWidth() * multiplier);\n const height = Math.round(canvas.getHeight() * multiplier);\n if (format === 'svg') {\n return { format, mimeType: 'image/svg+xml', data: canvas.toSVG(), width, height };\n }\n const dataUrl = canvas.toDataURL({ format: format as ImageFormat, multiplier, quality });\n return {\n format,\n mimeType: format === 'jpeg' ? 'image/jpeg' : `image/${format}`,\n data: dataUrlBytes(dataUrl),\n width,\n height,\n };\n}\n\nfunction compositeOperation(mode?: MockupBlendMode): GlobalCompositeOperation {\n return !mode || mode === 'normal' ? 'source-over' : mode;\n}\n\nfunction clampOpacity(value = 1): number {\n return Math.max(0, Math.min(1, value));\n}\n\nasync function coverImage(url: string, width: number, height: number): Promise<FabricImage> {\n let image: FabricImage;\n try {\n image = await FabricImage.fromURL(url);\n } catch (error) {\n throw new Error(`Failed to load mockup image: ${url}`, { cause: error });\n }\n const sourceWidth = image.width;\n const sourceHeight = image.height;\n const placement = computeCoverPlacement(sourceWidth, sourceHeight, width, height);\n image.set({\n originX: 'left',\n originY: 'top',\n left: placement.left,\n top: placement.top,\n scaleX: placement.width / sourceWidth,\n scaleY: placement.height / sourceHeight,\n selectable: false,\n evented: false,\n });\n return image;\n}\n\nasync function displacedDesignUrl(\n designCanvas: StaticCanvas,\n displacement: MockupDisplacement,\n width: number,\n height: number,\n): Promise<string> {\n const mapCanvas = new StaticCanvas(undefined, { width, height });\n const warpedCanvas = new StaticCanvas(undefined, { width, height });\n try {\n mapCanvas.add(await coverImage(displacement.image, width, height));\n mapCanvas.renderAll();\n const pixels = displaceRgba(\n designCanvas.getContext().getImageData(0, 0, width, height).data,\n mapCanvas.getContext().getImageData(0, 0, width, height).data,\n width,\n height,\n displacement,\n );\n const imageData = warpedCanvas.getContext().createImageData(width, height);\n imageData.data.set(pixels);\n warpedCanvas.getContext().putImageData(imageData, 0, 0);\n return warpedCanvas.toDataURL({ format: 'png', multiplier: 1 });\n } catch (error) {\n throw new Error('Failed to apply mockup displacement map', { cause: error });\n } finally {\n mapCanvas.dispose();\n warpedCanvas.dispose();\n }\n}\n\n/** Render browser-authored EditorState without a DOM or live editor instance. */\nexport async function renderEditorState(\n state: EditorState,\n options: NodeRenderOptions = {},\n): Promise<NodeRenderResult> {\n validateState(state);\n const resolved = validateOptions(options);\n assertImageUrlsAllowed(state, resolved.allowImageUrl);\n const canvas = await createStateCanvas(state);\n try {\n return encodeCanvas(canvas, resolved);\n } finally {\n canvas.dispose();\n }\n}\n\n/** Render a saved product mockup with the transparent design composited above it. */\nexport async function renderMockupState(\n state: EditorState,\n options: NodeRenderOptions = {},\n): Promise<NodeRenderResult> {\n validateState(state);\n const resolved = validateOptions(options);\n assertImageUrlsAllowed(state, resolved.allowImageUrl);\n if (resolved.format === 'svg') {\n throw new Error('Mockup rendering supports PNG, JPEG, and WebP output');\n }\n const mockup: MockupConfig | null | undefined = state.mockup;\n if (!mockup?.image) throw new Error('No mockup is configured');\n\n const designCanvas = await createStateCanvas(state, true);\n const output = new StaticCanvas(undefined, {\n width: state.canvas.width,\n height: state.canvas.height,\n preserveObjectStacking: true,\n });\n try {\n output.add(await coverImage(mockup.image, state.canvas.width, state.canvas.height));\n\n const designUrl = mockup.displacement\n ? await displacedDesignUrl(\n designCanvas,\n mockup.displacement,\n state.canvas.width,\n state.canvas.height,\n )\n : designCanvas.toDataURL({ format: 'png', multiplier: 1 });\n const design = await FabricImage.fromURL(designUrl);\n design.set({\n originX: 'left',\n originY: 'top',\n left: 0,\n top: 0,\n opacity: clampOpacity(mockup.designOpacity),\n globalCompositeOperation: compositeOperation(mockup.designBlendMode),\n selectable: false,\n evented: false,\n });\n if (mockup.printArea && mockup.clipToPrintArea !== false) {\n const clip = computePrintAreaClip(\n mockup.printArea,\n 1,\n 1,\n state.canvas.width,\n state.canvas.height,\n );\n design.clipPath = new Rect({\n originX: 'left',\n originY: 'top',\n left: clip.left,\n top: clip.top,\n width: clip.width,\n height: clip.height,\n absolutePositioned: true,\n });\n }\n output.add(design);\n\n if (mockup.overlay) {\n const overlay = await coverImage(\n mockup.overlay.image,\n state.canvas.width,\n state.canvas.height,\n );\n overlay.set({\n opacity: clampOpacity(mockup.overlay.opacity),\n globalCompositeOperation: compositeOperation(mockup.overlay.blendMode ?? 'multiply'),\n });\n output.add(overlay);\n }\n output.renderAll();\n return encodeCanvas(output, resolved);\n } finally {\n designCanvas.dispose();\n output.dispose();\n }\n}\n\nasync function renderBatch(\n states: EditorState[],\n options: NodeRenderOptions & { concurrency?: number },\n renderer: (state: EditorState, options: NodeRenderOptions) => Promise<NodeRenderResult>,\n): Promise<NodeRenderResult[]> {\n const concurrency = Math.max(1, Math.floor(options.concurrency ?? 2));\n const results = new Array<NodeRenderResult>(states.length);\n let nextIndex = 0;\n await Promise.all(\n Array.from({ length: Math.min(concurrency, states.length) }, async () => {\n while (nextIndex < states.length) {\n const index = nextIndex++;\n results[index] = await renderer(states[index], options);\n }\n }),\n );\n return results;\n}\n\n/** Render multiple states with bounded concurrency for fulfillment jobs. */\nexport async function renderEditorStateBatch(\n states: EditorState[],\n options: NodeRenderOptions & { concurrency?: number } = {},\n): Promise<NodeRenderResult[]> {\n return renderBatch(states, options, renderEditorState);\n}\n\n/** Render multiple mockup states with bounded concurrency for fulfillment jobs. */\nexport async function renderMockupStateBatch(\n states: EditorState[],\n options: NodeRenderOptions & { concurrency?: number } = {},\n): Promise<NodeRenderResult[]> {\n return renderBatch(states, options, renderMockupState);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AASA,SAAS,YAAY,OAA2B,UAAkB,OAAuB;AACvF,QAAM,WAAW,SAAS;AAC1B,MAAI,CAAC,OAAO,SAAS,QAAQ,EAAG,OAAM,IAAI,MAAM,GAAG,KAAK,iBAAiB;AACzE,SAAO;AACT;AAEA,SAAS,OACP,QACA,OACA,QACA,GACA,GACA,SACQ;AACR,QAAM,WAAW,KAAK,IAAI,GAAG,KAAK,IAAI,QAAQ,GAAG,CAAC,CAAC;AACnD,QAAM,WAAW,KAAK,IAAI,GAAG,KAAK,IAAI,SAAS,GAAG,CAAC,CAAC;AACpD,QAAM,KAAK,KAAK,MAAM,QAAQ;AAC9B,QAAM,KAAK,KAAK,MAAM,QAAQ;AAC9B,QAAM,KAAK,KAAK,IAAI,QAAQ,GAAG,KAAK,CAAC;AACrC,QAAM,KAAK,KAAK,IAAI,SAAS,GAAG,KAAK,CAAC;AACtC,QAAM,KAAK,WAAW;AACtB,QAAM,KAAK,WAAW;AACtB,QAAM,MACJ,QAAQ,KAAK,QAAQ,MAAM,IAAI,OAAO,KAAK,IAAI,MAC/C,QAAQ,KAAK,QAAQ,MAAM,IAAI,OAAO,IAAI;AAC5C,QAAM,SACJ,QAAQ,KAAK,QAAQ,MAAM,IAAI,OAAO,KAAK,IAAI,MAC/C,QAAQ,KAAK,QAAQ,MAAM,IAAI,OAAO,IAAI;AAC5C,SAAO,OAAO,IAAI,MAAM,SAAS;AACnC;AAMO,SAAS,aACd,QACA,KACA,OACA,QACA,SACmB;AACnB,MAAI,CAAC,OAAO,UAAU,KAAK,KAAK,CAAC,OAAO,UAAU,MAAM,KAAK,SAAS,KAAK,UAAU,GAAG;AACtF,UAAM,IAAI,MAAM,mDAAmD;AAAA,EACrE;AACA,QAAM,iBAAiB,QAAQ,SAAS;AACxC,MAAI,OAAO,WAAW,kBAAkB,IAAI,WAAW,gBAAgB;AACrE,UAAM,IAAI,MAAM,iEAAiE;AAAA,EACnF;AAEA,QAAM,SAAS,YAAY,QAAQ,QAAQ,IAAI,qBAAqB;AACpE,QAAM,SAAS,YAAY,QAAQ,QAAQ,IAAI,qBAAqB;AACpE,QAAM,WAAW,cAAc,QAAQ,YAAY,KAAK;AACxD,QAAM,WAAW,cAAc,QAAQ,YAAY,OAAO;AAC1D,QAAM,SAAS,IAAI,kBAAkB,cAAc;AAEnD,WAAS,IAAI,GAAG,IAAI,QAAQ,KAAK,GAAG;AAClC,aAAS,IAAI,GAAG,IAAI,OAAO,KAAK,GAAG;AACjC,YAAM,UAAU,IAAI,QAAQ,KAAK;AACjC,YAAM,UAAU,KAAM,IAAI,SAAS,QAAQ,IAAI,OAAO,MAAO;AAC7D,YAAM,UAAU,KAAM,IAAI,SAAS,QAAQ,IAAI,OAAO,MAAO;AAC7D,eAAS,UAAU,GAAG,UAAU,GAAG,WAAW,GAAG;AAC/C,eAAO,SAAS,OAAO,IAAI,KAAK;AAAA,UAC9B,OAAO,QAAQ,OAAO,QAAQ,SAAS,SAAS,OAAO;AAAA,QACzD;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AA9EA,IAEM;AAFN;AAAA;AAAA;AAEA,IAAM,gBAA2D;AAAA,MAC/D,KAAK;AAAA,MACL,OAAO;AAAA,MACP,MAAM;AAAA,MACN,OAAO;AAAA,IACT;AAAA;AAAA;;;ACWO,SAAS,qBACd,MACA,QACA,QACA,aACA,cACiB;AACjB,QAAM,OAAO,KAAK,IAAI,GAAG,KAAK,IAAI,aAAa,KAAK,OAAO,MAAM,CAAC;AAClE,QAAM,MAAM,KAAK,IAAI,GAAG,KAAK,IAAI,cAAc,KAAK,MAAM,MAAM,CAAC;AACjE,QAAM,QAAQ,KAAK,IAAI,MAAM,KAAK,IAAI,cAAc,KAAK,OAAO,KAAK,SAAS,MAAM,CAAC;AACrF,QAAM,SAAS,KAAK,IAAI,KAAK,KAAK,IAAI,eAAe,KAAK,MAAM,KAAK,UAAU,MAAM,CAAC;AACtF,SAAO,EAAE,MAAM,KAAK,OAAO,QAAQ,MAAM,QAAQ,SAAS,IAAI;AAChE;AAGO,SAAS,sBACd,aACA,cACA,aACA,cACgB;AAChB,MAAI,eAAe,KAAK,gBAAgB,KAAK,eAAe,KAAK,gBAAgB,GAAG;AAClF,UAAM,IAAI,MAAM,mCAAmC;AAAA,EACrD;AACA,QAAM,QAAQ,KAAK,IAAI,cAAc,aAAa,eAAe,YAAY;AAC7E,QAAM,QAAQ,cAAc;AAC5B,QAAM,SAAS,eAAe;AAC9B,SAAO;AAAA,IACL,OAAO,cAAc,SAAS;AAAA,IAC9B,MAAM,eAAe,UAAU;AAAA,IAC/B;AAAA,IACA;AAAA,EACF;AACF;AAnDA;AAAA;AAAA;AAAA;AAAA,oBAA6B;AAG7B;AAAA;AAAA;;;AC0CA,SAAS,cAAc,QAAwC;AAC7D,SAAO,OAAO;AAAA,IACZ,CAAC,GAAG,OAAO,SAAS,oCAAoC,CAAC,EAAE,IAAI,CAAC,UAAU;AAAA,MACxE,MAAM,CAAC;AAAA,MACP,MAAM,CAAC,KAAK,MAAM,CAAC,KAAK;AAAA,IAC1B,CAAC;AAAA,EACH;AACF;AAEA,SAAS,cAAc,QAAwB;AAC7C,SAAO,OACJ,QAAQ,YAAY,EAAE,EACtB;AAAA,IAAQ;AAAA,IAAoB,CAAC,GAAG,UAC/B,OAAO,cAAc,OAAO,SAAS,OAAO,EAAE,CAAC;AAAA,EACjD,EACC,QAAQ,aAAa,CAAC,GAAG,UAAkB,OAAO,cAAc,OAAO,KAAK,CAAC,CAAC,EAC9E,QAAQ,SAAS,GAAG,EACpB,QAAQ,SAAS,GAAG,EACpB,QAAQ,WAAW,GAAG,EACtB,QAAQ,WAAW,GAAG,EACtB,QAAQ,UAAU,GAAG;AAC1B;AAEA,SAAS,mBAAmB,OAAuB;AACjD,SAAO,MAAM,QAAQ,YAAY,CAAC,cAAc,KAAK,UAAU,WAAW,CAAC,CAAC,GAAG;AACjF;AAEA,SAAS,WACP,OACA,QACA,MACA,QACiC;AACjC,QAAM,SAAS,QAAQ,SAAS,gBAAgB,OAAO,UAAU,SAAS,YAAY;AAGtF,QAAM,MAAM,CAAC,QACX,OAAO,OAAO,OAAO,GAAG,IAAK,MAAM,GAAG,IAA4B;AACpE,SAAO,IAAI,GAAG,MAAM,GAAG,MAAM,EAAE,KAAK,IAAI,MAAM;AAChD;AAEA,eAAe,eACb,KACA,OACA,UACiB;AACjB,QAAM,UAAU,MAAM,OAAO,SAAS;AACtC,MAAI,SAAS;AACb,MAAI,SAAS;AACb,aAAW,aAAa,IAAI,SAAS,qCAAqC,GAAG;AAC3E,UAAM,QAAQ,UAAU,SAAS;AACjC,cAAU,IAAI,MAAM,QAAQ,KAAK;AACjC,aAAS,QAAQ,UAAU,CAAC,EAAE;AAC9B,UAAM,iBAAiB,cAAc,UAAU,CAAC,CAAC;AACjD,UAAM,QAAQ,CAAC,GAAG,UAAU,CAAC,EAAE,SAAS,uCAAuC,CAAC;AAChF,UAAM,QAAQ,MAAM,SAChB,MAAM,IAAI,CAAC,UAAU,EAAE,YAAY,cAAc,KAAK,CAAC,CAAC,GAAG,MAAM,cAAc,KAAK,CAAC,CAAC,EAAE,EAAE,IAC1F,CAAC,EAAE,YAAY,gBAAgB,MAAM,cAAc,UAAU,CAAC,CAAC,EAAE,CAAC;AACtE,UAAM,WAAW,MAAM,IAAI,CAAC,SAAS;AACnC,YAAM,aAAa,EAAE,GAAG,gBAAgB,GAAG,KAAK,WAAW;AAC3D,YAAM,SAAS,WAAW,aAAa,KAAK;AAC5C,YAAM,OAAO,gBAAgB,KAAK,WAAW,aAAa,KAAK,EAAE;AACjE,YAAM,SAAS,kBAAkB,KAAK,WAAW,YAAY,KAAK,EAAE;AACpE,aAAO,EAAE,GAAG,MAAM,YAAY,QAAQ,QAAQ,WAAW,OAAO,QAAQ,MAAM,MAAM,EAAE;AAAA,IACxF,CAAC;AACD,QAAI,SAAS,KAAK,CAAC,SAAS,CAAC,KAAK,MAAM,GAAG;AACzC,gBAAU,UAAU,CAAC;AACrB;AAAA,IACF;AACA,UAAM,QAAkB,CAAC;AACzB,eAAW,QAAQ,UAAU;AAC3B,YAAM,SAAS,KAAK;AACpB,YAAM,SACJ,OAAO,WAAW,WACd,QAAQ,SAAS,MAAM,IACvB,QAAQ,OAAO,OAAO,KAAK,OAAO,QAAQ,OAAO,YAAY,OAAO,UAAU,CAAC;AACrF,UAAI,EAAE,YAAY,SAAS;AACzB,cAAM,IAAI,MAAM,0CAA0C,KAAK,MAAM,EAAE;AAAA,MACzE;AACA,YAAM,OAAO,OAAO,WAAW,KAAK,WAAW,WAAW,KAAK,IAAI;AACnE,YAAM,QAAQ,OAAO,OAAO;AAC5B,YAAM,QAAQ,KAAK,WAAW,SAAS;AACvC,YAAM,MAAM,OAAO,OAAO,KAAK,IAAI;AACnC,UAAI,OAAO,OAAO,WAAW,KAAK,WAAW,KAAK,GAAG;AACrD,YAAM,WAAW,OAAO,WAAW,KAAK,WAAW,KAAK,GAAG;AAC3D,UAAI,OAAO,QAAQ,CAAC,OAAO,eAAe;AACxC,cAAM,WAAW,IAAI,UAAU,UAAU;AACzC,cAAM,IAAI,OAAO,SAAS,UAAU;AACpC,cAAM,IAAI,WAAW,SAAS,UAAU;AACxC,cAAM;AAAA,UACJ,YAAY,MAAM,KAAK,MAAM,CAAC,0BAA0B,CAAC,IAAI,CAAC,WAAW,KAAK,IAAI,CAAC,KAAK,aAAa,mBAAmB,KAAK,CAAC;AAAA,QAChI;AACA,gBAAQ,SAAS,WAAW;AAAA,MAC9B,CAAC;AACD,eAAS,IAAI,KAAK,MAAM;AAAA,IAC1B;AACA,cAAU,0BAA0B,mBAAmB,CAAC,GAAG,IAAI,IAAI,SAAS,IAAI,CAAC,SAAS,KAAK,MAAM,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,KAAK,MAAM,KAAK,EAAE,CAAC;AAAA,EACxI;AACA,SAAO,SAAS,IAAI,MAAM,MAAM;AAClC;AAEA,SAAS,UAAU,CAAC,SAAS,WAAW,QAAQ,GAK9C;AACA,QAAM,MAAM,UAAU;AACtB,QAAM,QAAQ,YAAY;AAC1B,QAAM,OAAO,WAAW;AACxB,QAAM,QAAQ,IAAI,KAAK,IAAI,KAAK,OAAO,IAAI;AAC3C,MAAI,SAAS,EAAG,QAAO,CAAC,GAAG,GAAG,GAAG,GAAG;AACpC,SAAO;AAAA,KACH,IAAI,MAAM,UAAU,IAAI,SAAU;AAAA,KAClC,IAAI,QAAQ,UAAU,IAAI,SAAU;AAAA,KACpC,IAAI,OAAO,UAAU,IAAI,SAAU;AAAA,IACrC,QAAQ;AAAA,EACV;AACF;AAEA,eAAe,iBACb,QACA,OACqB;AACrB,MAAI,OAAO,WAAW,OAAO,GAAG;AAC9B,UAAMA,YAAW,MAAM,MAAM,MAAM;AACnC,QAAI,CAACA,UAAS,GAAI,OAAM,IAAI,MAAM,wCAAwC;AAC1E,WAAO,IAAI,WAAW,MAAMA,UAAS,YAAY,CAAC;AAAA,EACpD;AACA,QAAM,YAAY,QACd,MAAM,MAAM,KACX,MAAM;AACL,QAAI;AACF,aAAO,CAAC,SAAS,QAAQ,EAAE,SAAS,IAAI,IAAI,MAAM,EAAE,QAAQ;AAAA,IAC9D,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF,GAAG;AACP,MAAI,CAAC,UAAW,OAAM,IAAI,MAAM,wCAAwC,MAAM,EAAE;AAChF,QAAM,WAAW,MAAM,MAAM,MAAM;AACnC,MAAI,CAAC,SAAS,GAAI,OAAM,IAAI,MAAM,gCAAgC,MAAM,EAAE;AAC1E,SAAO,IAAI,WAAW,MAAM,SAAS,YAAY,CAAC;AACpD;AAEA,eAAe,uBACb,KACA,OACA,SACA,OACiB;AACjB,QAAM,UAAU,oBAAI,IAAY;AAChC,aAAW,SAAS,IAAI,SAAS,oDAAoD,GAAG;AACtF,QAAI,MAAM,CAAC,EAAG,SAAQ,IAAI,MAAM,CAAC,CAAC;AAAA,EACpC;AACA,MAAI,YAAY;AAChB,aAAW,UAAU,SAAS;AAC5B,UAAM,QAAQ,MAAM,iBAAiB,QAAQ,KAAK;AAClD,UAAM,OAAO,MAAM,MAAM,KAAK,EAC3B,QAAQ,EAAE,YAAY,UAAU,CAAC,EACjC,cAAc,MAAM,EACpB,eAAe,OAAO,EACtB,KAAK,EAAE,SAAS,KAAK,mBAAmB,QAAQ,CAAC,EACjD,SAAS;AACZ,UAAM,UAAU,0BAA0B,KAAK,SAAS,QAAQ,CAAC;AACjE,gBAAY,UAAU,MAAM,MAAM,EAAE,KAAK,OAAO;AAAA,EAClD;AACA,SAAO;AACT;AAEA,eAAe,oBACb,OACA,SACA,OACA,QACA,OACA,UACA,eACA,iBACqB;AACrB,QAAM,CAAC,EAAE,SAAS,OAAO,GAAG,EAAE,SAAS,SAAS,GAAG,EAAE,mBAAAC,mBAAkB,CAAC,IAAI,MAAM,QAAQ,IAAI;AAAA,IAC5F,OAAO,QAAQ;AAAA,IACf,OAAO,eAAe;AAAA,IACtB;AAAA,EACF,CAAC;AAID,QAAM,WAAW,MAAMA;AAAA,IACrB,EAAE,GAAG,OAAO,YAAY,UAAU;AAAA,IAClC;AAAA,MACE,QAAQ;AAAA,MACR,eAAe,QAAQ;AAAA,IACzB;AAAA,EACF;AACA,MAAI,OAAO,SAAS,SAAS,SAAU,OAAM,IAAI,MAAM,uCAAuC;AAC9F,QAAM,YAAY,QAAQ,aAAa,CAAC;AACxC,QAAM,cACJ,QAAQ,iBAAiB,QACrB,SAAS,OACT,MAAM,eAAe,SAAS,MAAM,WAAW,aAAa;AAClE,QAAM,MAAM,MAAM;AAAA,IAChB;AAAA,IACA;AAAA,IACA,QAAQ,cAAc;AAAA,IACtB,QAAQ;AAAA,EACV;AACA,QAAM,gBAAgB,CAAC,GAAG,IAAI,SAAS,mBAAmB,CAAC,EAAE;AAAA,IAAI,CAAC,UAChE,cAAc,MAAM,CAAC,CAAC;AAAA,EACxB;AACA,aAAW,cAAc,eAAe;AACtC,UAAM,SAAS,WAAW,aAAa,KAAK;AAC5C,oBAAgB,IAAI,MAAM;AAC1B,UAAM,OAAO,gBAAgB,KAAK,WAAW,aAAa,KAAK,EAAE;AACjE,UAAM,SAAS,kBAAkB,KAAK,WAAW,YAAY,KAAK,EAAE;AACpE,QAAI,CAAC,WAAW,WAAW,QAAQ,MAAM,MAAM,GAAG;AAChD,eAAS;AAAA,QACP,SAAS,MAAM;AAAA,MACjB;AAAA,IACF;AAAA,EACF;AAEA,QAAM,WAAW,IAAI,OAAO,EAAE,eAAe,OAAO,UAAU,OAAO,YAAY,MAAM,CAAC;AACxF,aAAW,CAAC,MAAM,IAAI,KAAK,OAAO,QAAQ,SAAS,GAAG;AACpD,aAAS,aAAa,MAAM,OAAO,SAAS,WAAW,OAAO,OAAO,KAAK,IAAI,CAAC;AAAA,EACjF;AACA,WAAS,QAAQ,EAAE,MAAM,CAAC,OAAO,MAAM,GAAG,QAAQ,EAAE,CAAC;AACrD,WAAS,UAAU,KAAK,GAAG,GAAG;AAAA,IAC5B;AAAA,IACA;AAAA,IACA,qBAAqB;AAAA,IACrB,eAAe,CAAC,UAAU;AACxB,YAAM,CAAC,KAAK,OAAO,IAAI;AACvB,aAAO,CAAC,UAAU,GAAG,GAAG,OAAO;AAAA,IACjC;AAAA,IACA,iBAAiB,CAAC,YAAY,SAAS,KAAK,kBAAkB,OAAO,EAAE;AAAA,EACzE,CAAC;AAED,SAAO,IAAI,QAAoB,CAAC,SAAS,WAAW;AAClD,UAAM,SAAuB,CAAC;AAC9B,aAAS,GAAG,QAAQ,CAAC,UAAsB,OAAO,KAAK,KAAK,CAAC;AAC7D,aAAS,GAAG,SAAS,MAAM;AAC3B,aAAS,GAAG,OAAO,MAAM,QAAQ,IAAI,WAAW,OAAO,OAAO,MAAM,CAAC,CAAC,CAAC;AACvE,aAAS,IAAI;AAAA,EACf,CAAC;AACH;AAOA,SAAS,SAAS,OAAe,OAAuB;AACtD,MAAI,CAAC,OAAO,SAAS,KAAK,KAAK,SAAS,EAAG,OAAM,IAAI,MAAM,GAAG,KAAK,mBAAmB;AACtF,SAAO;AACT;AAOA,SAAS,WAAW,OAAe,OAAuB;AACxD,QAAM,MAAM,SAAS,OAAO,KAAK;AACjC,MAAI,MAAM,QAAS,OAAM,IAAI,MAAM,GAAG,KAAK,oBAAoB,OAAO,EAAE;AACxE,MAAI,MAAM,EAAG,OAAM,IAAI,MAAM,GAAG,KAAK,qBAAqB;AAC1D,SAAO;AACT;AAEA,SAAS,YAAY,OAAe,OAAuB;AACzD,MAAI,CAAC,OAAO,SAAS,KAAK,KAAK,QAAQ,EAAG,OAAM,IAAI,MAAM,GAAG,KAAK,qBAAqB;AACvF,SAAO;AACT;AAEA,SAAS,kBAAkB,OAAoB,YAA8B;AAC3E,MAAI,cAAc,EAAG,QAAO,CAAC;AAC7B,QAAM,QAAQ,MAAM,OAAO,QAAQ;AACnC,QAAM,SAAS,MAAM,OAAO,SAAS;AACrC,QAAM,WAAqB,CAAC;AAC5B,aAAW,SAAS,MAAM,QAAQ;AAChC,QAAI,CAAC,MAAM,QAAS;AACpB,UAAM,SAAS,MAAM;AACrB,UAAM,OAAO,OAAO,OAAO,QAAQ,CAAC;AACpC,UAAM,MAAM,OAAO,OAAO,OAAO,CAAC;AAClC,UAAM,QAAQ,OAAO,OAAO,SAAS,CAAC,IAAI,KAAK,IAAI,OAAO,OAAO,UAAU,CAAC,CAAC;AAC7E,UAAM,SAAS,OAAO,OAAO,UAAU,CAAC,IAAI,KAAK,IAAI,OAAO,OAAO,UAAU,CAAC,CAAC;AAC/E,QAAI,OAAO,cAAc,MAAM,cAAc,OAAO,QAAQ,SAAS,MAAM,SAAS,QAAQ;AAC1F,eAAS,KAAK,UAAU,MAAM,IAAI,4CAA4C;AAAA,IAChF;AAAA,EACF;AACA,SAAO;AACT;AASA,eAAsB,eACpB,OACA,UAA2B,CAAC,GACH;AACzB,QAAM,MAAM,WAAW,QAAQ,OAAO,MAAM,OAAO,OAAO,KAAK,WAAW;AAC1E,QAAM,cAAc,WAAW,MAAM,OAAO,OAAO,IAAI,cAAc;AACrE,QAAM,YAAY,SAAS,QAAQ,aAAa,oBAAoB,YAAY;AAChF,QAAM,cAAc,YAAY,QAAQ,SAAS,OAAO,OAAO;AAC/D,QAAM,oBAAoB,YAAY,QAAQ,eAAe,MAAM,cAAc;AACjF,QAAM,iBAAiB,YAAY,QAAQ,YAAY,GAAG,WAAW;AACrE,QAAM,YAAY,QAAQ,aAAa;AACvC,QAAM,cAAc,KAAK,MAAM,cAAc,GAAG;AAChD,QAAM,kBAAmB,MAAM,OAAO,QAAQ,cAAe;AAC7D,QAAM,mBAAoB,MAAM,OAAO,SAAS,cAAe;AAC/D,QAAM,cAAc,cAAc;AAClC,QAAM,oBAAoB,oBAAoB;AAE9C,QAAM,QAAQ,MAAM;AACpB,QAAM,eACJ,KAAK,MAAM,MAAM,OAAO,QAAQ,QAAQ,cAAc,CAAC,IACvD,KAAK,MAAM,MAAM,OAAO,SAAS,QAAQ,cAAc,CAAC;AAC1D,MAAI,CAAC,OAAO,SAAS,YAAY,KAAK,eAAe,WAAW;AAC9D,UAAM,IAAI;AAAA,MACR,mBAAmB,YAAY,uBAAuB,SAAS;AAAA,IACjE;AAAA,EACF;AAEA,QAAM,CAAC,EAAE,SAAS,MAAM,GAAG,MAAM,IAAI,MAAM,QAAQ,IAAI,CAAC,OAAO,OAAO,GAAG,OAAO,SAAS,CAAC,CAAC;AAG3F,QAAM,EAAE,mBAAAA,mBAAkB,IAAI,MAAM;AACpC,QAAM,WAAW,MAAMA,mBAAkB,OAAO;AAAA,IAC9C,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,eAAe,QAAQ;AAAA,EACzB,CAAC;AACD,MAAI,OAAO,SAAS,SAAS,SAAU,OAAM,IAAI,MAAM,uCAAuC;AAE9F,MAAI,WAAW,MAAM,SAAS,IAAI,EAAE,QAAQ,EAAE,YAAY,UAAU,CAAC;AACrE,MAAI,cAAc,GAAG;AACnB,eAAW,SAAS,OAAO;AAAA,MACzB,KAAK;AAAA,MACL,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,YAAY;AAAA,IACd,CAAC;AAAA,EACH;AACA,QAAM,EAAE,MAAM,UAAU,KAAK,IAAI,MAAM,SACpC,cAAc,MAAM,EACpB,eAAe,QAAQ,cAAc,MAAM,EAC3C,YAAY,GAAG,EACf,KAAK,EAAE,SAAS,KAAK,mBAAmB,QAAQ,CAAC,EACjD,SAAS,EAAE,mBAAmB,KAAK,CAAC;AACvC,QAAM,WAAW,MAAM,MAAM,QAAQ,EAAE,SAAS;AAChD,MAAI,KAAK,aAAa,KAAK,SAAS,UAAU,UAAU,CAAC,SAAS,KAAK;AACrE,UAAM,IAAI,MAAM,0EAA0E;AAAA,EAC5F;AAEA,QAAM,EAAE,aAAa,SAAS,SAAS,WAAW,KAAK,IAAI;AAC3D,QAAM,WAAW,MAAM,YAAY,OAAO;AAC1C,QAAM,QAAQ,QAAQ,SAAS;AAC/B,WAAS,SAAS,KAAK;AACvB,WAAS,WAAW,kCAAkC;AACtD,WAAS,YAAY,kCAAkC;AACvD,QAAM,YAAY,kBAAkB,cAAc,IAAI,oBAAoB;AAC1E,QAAM,aAAa,mBAAmB,cAAc,IAAI,oBAAoB;AAC5E,QAAM,OAAO,SAAS,QAAQ,CAAC,WAAW,UAAU,CAAC;AACrD,QAAM,QAAQ,MAAM,SAAS,SAAS,QAAQ;AAC9C,OAAK,UAAU,OAAO;AAAA,IACpB,GAAG;AAAA,IACH,GAAG;AAAA,IACH,OAAO,kBAAkB,cAAc;AAAA,IACvC,QAAQ,mBAAmB,cAAc;AAAA,EAC3C,CAAC;AAED,QAAM,WAAW,oBAAoB;AACrC,QAAM,aAAa,oBAAoB;AACvC,QAAM,YAAY,WAAW;AAC7B,QAAM,UAAU,aAAa;AAC7B,QAAM,WAAW,kBAAkB,OAAO,iBAAiB,WAAW;AACtE,QAAM,gBAAgB,oBAAI,IAAY;AACtC,QAAM,kBAAkB,oBAAI,IAAY;AACxC,MAAI,cAAc,UAAU;AAC1B,UAAM,YAAY,MAAM;AAAA,MACtB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,UAAM,CAAC,UAAU,IAAI,MAAM,SAAS,SAAS,SAAS;AACtD,SAAK,SAAS,YAAY;AAAA,MACxB,GAAG;AAAA,MACH,GAAG;AAAA,MACH,OAAO;AAAA,MACP,QAAQ;AAAA,IACV,CAAC;AAAA,EACH;AACA,QAAM,YAAY;AAClB,QAAM,cAAc;AACpB,QAAM,aAAa,YAAY;AAC/B,QAAM,WAAW,aAAa;AAC9B,QAAM,UAAU,SAAS;AACzB,OAAK,KAAK,IAAI,QAAQ,GAAG,SAAS,GAAG,QAAQ,IAAI,CAAC,UAAU,YAAY,WAAW,OAAO,CAAC,CAAC;AAC5F,OAAK,KAAK;AAAA,IACR,QAAQ,GAAG,UAAU;AAAA,IACrB,QAAQ,IAAI,CAAC,WAAW,aAAa,YAAY,QAAQ,CAAC;AAAA,EAC5D;AACA,OAAK,KAAK,IAAI,QAAQ,GAAG,QAAQ,GAAG,QAAQ,IAAI,CAAC,UAAU,YAAY,WAAW,OAAO,CAAC,CAAC;AAE3F,QAAM,aAAa,KAAK,GAAG,GAAG,GAAG,CAAC;AAClC,MAAI,QAAQ,cAAc,OAAO;AAC/B,UAAM,SAAS,KAAK,IAAI,GAAG,cAAc,CAAC;AAC1C,UAAM,SAAS,KAAK,IAAI,GAAG,oBAAoB,CAAC;AAChD,eAAW,KAAK,CAAC,UAAU,SAAS,GAAG;AACrC,WAAK,SAAS;AAAA,QACZ,OAAO,EAAE,GAAG,GAAG,aAAa,OAAO;AAAA,QACnC,KAAK,EAAE,GAAG,GAAG,aAAa,SAAS,OAAO;AAAA,QAC1C,WAAW;AAAA,QACX,OAAO;AAAA,MACT,CAAC;AACD,WAAK,SAAS;AAAA,QACZ,OAAO,EAAE,GAAG,GAAG,UAAU,OAAO;AAAA,QAChC,KAAK,EAAE,GAAG,GAAG,UAAU,SAAS,OAAO;AAAA,QACvC,WAAW;AAAA,QACX,OAAO;AAAA,MACT,CAAC;AAAA,IACH;AACA,eAAW,KAAK,CAAC,YAAY,OAAO,GAAG;AACrC,WAAK,SAAS;AAAA,QACZ,OAAO,EAAE,GAAG,WAAW,QAAQ,EAAE;AAAA,QACjC,KAAK,EAAE,GAAG,WAAW,SAAS,QAAQ,EAAE;AAAA,QACxC,WAAW;AAAA,QACX,OAAO;AAAA,MACT,CAAC;AACD,WAAK,SAAS;AAAA,QACZ,OAAO,EAAE,GAAG,YAAY,QAAQ,EAAE;AAAA,QAClC,KAAK,EAAE,GAAG,YAAY,SAAS,QAAQ,EAAE;AAAA,QACzC,WAAW;AAAA,QACX,OAAO;AAAA,MACT,CAAC;AAAA,IACH;AAAA,EACF;AACA,MAAI,QAAQ,sBAAsB,OAAO;AACvC,eAAW,CAAC,GAAG,CAAC,KAAK;AAAA,MACnB,CAAC,YAAY,GAAG,oBAAoB,CAAC;AAAA,MACrC,CAAC,YAAY,GAAG,aAAa,oBAAoB,CAAC;AAAA,MAClD,CAAC,oBAAoB,GAAG,aAAa,CAAC;AAAA,MACtC,CAAC,YAAY,oBAAoB,GAAG,aAAa,CAAC;AAAA,IACpD,GAA8B;AAC5B,WAAK,WAAW,EAAE,GAAG,GAAG,MAAM,GAAG,aAAa,KAAK,aAAa,WAAW,CAAC;AAC5E,WAAK,SAAS;AAAA,QACZ,OAAO,EAAE,GAAG,IAAI,GAAG,EAAE;AAAA,QACrB,KAAK,EAAE,GAAG,IAAI,GAAG,EAAE;AAAA,QACnB,WAAW;AAAA,QACX,OAAO;AAAA,MACT,CAAC;AACD,WAAK,SAAS;AAAA,QACZ,OAAO,EAAE,GAAG,GAAG,IAAI,EAAE;AAAA,QACrB,KAAK,EAAE,GAAG,GAAG,IAAI,EAAE;AAAA,QACnB,WAAW;AAAA,QACX,OAAO;AAAA,MACT,CAAC;AAAA,IACH;AAAA,EACF;AAEA,QAAM,gBAAgB,QAAQ,YAAY,SAAS,KAAK;AAAA,IACtD,GAAG;AAAA,IACH,WAAW,QAAQ,GAAG,YAAY;AAAA,EACpC,CAAC;AACD,QAAM,aAAa,QAAQ,SAAS,aAAa;AACjD,QAAM,eAAe,QAAQ,IAAI;AAAA,IAC/B,MAAM,QAAQ,GAAG,cAAc;AAAA,IAC/B,GAAG,QAAQ,GAAG,UAAU;AAAA,IACxB,2BAA2B,UAAU,GAAG,QAAQ,6BAA6B,MAAM;AAAA,IACnF,cAAc,UAAU,GAAG,uBAAuB;AAAA,IAClD,MAAM,UAAU,GAAG,QAAQ,6BAA6B,sBAAsB;AAAA,IAC9E,mBAAmB;AAAA,EACrB,CAAC;AACD,WAAS,QAAQ,IAAI,QAAQ,GAAG,eAAe,GAAG,QAAQ,IAAI,CAAC,QAAQ,SAAS,YAAY,CAAC,CAAC,CAAC;AAE/F,QAAM,OAAM,oBAAI,KAAK,GAAE,YAAY;AACnC,QAAM,MAAM;AAAA;AAAA,qNAEuM,GAAG,qDAAqD,MAAM,QAAQ,UAAU,EAAE,CAAC;AAAA;AAEtS,QAAM,iBAAiB,QAAQ,YAAY,IAAI,YAAY,EAAE,OAAO,GAAG,GAAG;AAAA,IACxE,MAAM,QAAQ,GAAG,UAAU;AAAA,IAC3B,SAAS,QAAQ,GAAG,KAAK;AAAA,EAC3B,CAAC;AACD,WAAS,QAAQ,IAAI,QAAQ,GAAG,UAAU,GAAG,QAAQ,SAAS,cAAc,CAAC;AAC7E,QAAM,UAAU,QAAQ,YAAY;AACpC,MAAI,SAAS;AACX,UAAM,WAAW,QAAQ,OAAO,SAAS,OAAO;AAChD,aAAS,IAAI,QAAQ,GAAG,iBAAiB,GAAG,UAAU,GAAG,SAAS,CAAC;AACnE,aAAS,IAAI,QAAQ,GAAG,SAAS,GAAG,QAAQ,GAAG,OAAO,CAAC;AAAA,EACzD;AAEA,SAAO;AAAA,IACL,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,MAAM,MAAM,SAAS,KAAK,EAAE,kBAAkB,MAAM,CAAC;AAAA,IACrD,UAAU;AAAA,IACV,aAAa;AAAA,IACb;AAAA,IACA,eAAe,CAAC,GAAG,aAAa,EAAE,KAAK;AAAA,IACvC,iBAAiB,CAAC,GAAG,eAAe,EAAE,KAAK;AAAA,IAC3C;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAjjBA,IAoSM,SAEA;AAtSN;AAAA;AAAA;AAoSA,IAAM,UAAU;AAEhB,IAAM,qBAAqB;AAAA;AAAA;;;ACtS3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAsCA,SAAS,qBAAqB,KAAsB;AAClD,QAAM,SAAS,wBAAwB,KAAK,IAAI,KAAK,CAAC;AACtD,SAAO,WAAW,QAAQ,kBAAkB,IAAI,GAAG,OAAO,CAAC,EAAE,YAAY,CAAC,GAAG;AAC/E;AAEA,SAAS,uBAAuB,OAAgB,OAAuC;AACrF,MAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,eAAW,QAAQ,MAAO,wBAAuB,MAAM,KAAK;AAC5D;AAAA,EACF;AACA,MAAI,CAAC,SAAS,OAAO,UAAU,SAAU;AACzC,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAK,GAAG;AAChD,QAAI,OAAO,UAAU,UAAU;AAC7B,UAAI,SAAS,IAAI,GAAG,KAAK,CAAC,MAAM,KAAK,GAAG;AACtC,cAAM,IAAI,MAAM,iCAAiC,MAAM,MAAM,GAAG,GAAG,CAAC,EAAE;AAAA,MACxE;AAAA,IACF,OAAO;AACL,6BAAuB,OAAO,KAAK;AAAA,IACrC;AAAA,EACF;AACF;AAEA,SAAS,cAAc,OAA0B;AAC/C,MACE,CAAC,OAAO,UACR,CAAC,MAAM,QAAQ,MAAM,MAAM,KAC3B,CAAC,OAAO,SAAS,MAAM,OAAO,KAAK,KACnC,CAAC,OAAO,SAAS,MAAM,OAAO,MAAM,KACpC,MAAM,OAAO,SAAS,KACtB,MAAM,OAAO,UAAU,GACvB;AACA,UAAM,IAAI,MAAM,sBAAsB;AAAA,EACxC;AACA,QAAM,QAAQ,OAAO,SAAS,MAAM,SAAS,MAAM,GAAG,EAAE,CAAC,KAAK,KAAK,EAAE;AACrE,MAAI,CAAC,OAAO,SAAS,KAAK,KAAK,QAAQ,GAAG;AACxC,UAAM,IAAI,MAAM,qCAAqC,MAAM,OAAO,EAAE;AAAA,EACtE;AACF;AAEA,SAAS,aAAa,SAA6B;AACjD,QAAM,UAAU,QAAQ,MAAM,QAAQ,QAAQ,GAAG,IAAI,CAAC;AACtD,QAAM,SAAS,KAAK,OAAO;AAC3B,QAAM,QAAQ,IAAI,WAAW,OAAO,MAAM;AAC1C,WAAS,QAAQ,GAAG,QAAQ,OAAO,QAAQ,SAAS,EAAG,OAAM,KAAK,IAAI,OAAO,WAAW,KAAK;AAC7F,SAAO;AACT;AAEA,SAAS,gBAAgB,SAAyD;AAChF,QAAM,SAAS,QAAQ,UAAU;AACjC,QAAM,aAAa,QAAQ,cAAc;AACzC,QAAM,UAAU,QAAQ,WAAW;AACnC,QAAM,gBAAgB,QAAQ,iBAAiB;AAC/C,MAAI,CAAC,OAAO,SAAS,UAAU,KAAK,cAAc,GAAG;AACnD,UAAM,IAAI,MAAM,oCAAoC;AAAA,EACtD;AACA,MAAI,CAAC,OAAO,SAAS,OAAO,KAAK,UAAU,KAAK,UAAU,GAAG;AAC3D,UAAM,IAAI,MAAM,wCAAwC;AAAA,EAC1D;AACA,SAAO,EAAE,QAAQ,YAAY,SAAS,cAAc;AACtD;AAEA,eAAe,kBAAkB,OAAoB,cAAc,OAA8B;AAC/F,QAAM,SAAS,IAAI,yBAAa,QAAW;AAAA,IACzC,OAAO,MAAM,OAAO;AAAA,IACpB,QAAQ,MAAM,OAAO;AAAA,IACrB,iBAAiB,cAAc,KAAM,MAAM,cAAc;AAAA,IACzD,wBAAwB;AAAA,EAC1B,CAAC;AACD,MAAI;AACF,QAAI,CAAC,eAAe,MAAM,iBAAiB;AACzC,aAAO,mBACL,MAAM,iBAAK,eAAe,CAAC,MAAM,eAAe,CAAC,GACjD,CAAC;AAAA,IACL;AACA,UAAM,UAAW,MAAM,iBAAK;AAAA,MAC1B,MAAM,OAAO,IAAI,CAAC,UAAU,MAAM,YAAY;AAAA,IAChD;AACA,YAAQ,QAAQ,CAAC,QAAQ,UAAU;AACjC,YAAM,QAAQ,MAAM,OAAO,KAAK;AAChC,aAAO,IAAI,EAAE,SAAS,MAAM,SAAS,SAAS,MAAM,QAAQ,CAAC;AAC7D,aAAO,IAAI,MAAM;AAAA,IACnB,CAAC;AACD,WAAO,UAAU;AACjB,WAAO;AAAA,EACT,SAAS,OAAO;AACd,WAAO,QAAQ;AACf,UAAM;AAAA,EACR;AACF;AAEA,SAAS,aACP,QACA,SACkB;AAClB,QAAM,EAAE,QAAQ,YAAY,QAAQ,IAAI;AACxC,QAAM,QAAQ,KAAK,MAAM,OAAO,SAAS,IAAI,UAAU;AACvD,QAAM,SAAS,KAAK,MAAM,OAAO,UAAU,IAAI,UAAU;AACzD,MAAI,WAAW,OAAO;AACpB,WAAO,EAAE,QAAQ,UAAU,iBAAiB,MAAM,OAAO,MAAM,GAAG,OAAO,OAAO;AAAA,EAClF;AACA,QAAM,UAAU,OAAO,UAAU,EAAE,QAA+B,YAAY,QAAQ,CAAC;AACvF,SAAO;AAAA,IACL;AAAA,IACA,UAAU,WAAW,SAAS,eAAe,SAAS,MAAM;AAAA,IAC5D,MAAM,aAAa,OAAO;AAAA,IAC1B;AAAA,IACA;AAAA,EACF;AACF;AAEA,SAAS,mBAAmB,MAAkD;AAC5E,SAAO,CAAC,QAAQ,SAAS,WAAW,gBAAgB;AACtD;AAEA,SAAS,aAAa,QAAQ,GAAW;AACvC,SAAO,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,KAAK,CAAC;AACvC;AAEA,eAAe,WAAW,KAAa,OAAe,QAAsC;AAC1F,MAAI;AACJ,MAAI;AACF,YAAQ,MAAM,wBAAY,QAAQ,GAAG;AAAA,EACvC,SAAS,OAAO;AACd,UAAM,IAAI,MAAM,gCAAgC,GAAG,IAAI,EAAE,OAAO,MAAM,CAAC;AAAA,EACzE;AACA,QAAM,cAAc,MAAM;AAC1B,QAAM,eAAe,MAAM;AAC3B,QAAM,YAAY,sBAAsB,aAAa,cAAc,OAAO,MAAM;AAChF,QAAM,IAAI;AAAA,IACR,SAAS;AAAA,IACT,SAAS;AAAA,IACT,MAAM,UAAU;AAAA,IAChB,KAAK,UAAU;AAAA,IACf,QAAQ,UAAU,QAAQ;AAAA,IAC1B,QAAQ,UAAU,SAAS;AAAA,IAC3B,YAAY;AAAA,IACZ,SAAS;AAAA,EACX,CAAC;AACD,SAAO;AACT;AAEA,eAAe,mBACb,cACA,cACA,OACA,QACiB;AACjB,QAAM,YAAY,IAAI,yBAAa,QAAW,EAAE,OAAO,OAAO,CAAC;AAC/D,QAAM,eAAe,IAAI,yBAAa,QAAW,EAAE,OAAO,OAAO,CAAC;AAClE,MAAI;AACF,cAAU,IAAI,MAAM,WAAW,aAAa,OAAO,OAAO,MAAM,CAAC;AACjE,cAAU,UAAU;AACpB,UAAM,SAAS;AAAA,MACb,aAAa,WAAW,EAAE,aAAa,GAAG,GAAG,OAAO,MAAM,EAAE;AAAA,MAC5D,UAAU,WAAW,EAAE,aAAa,GAAG,GAAG,OAAO,MAAM,EAAE;AAAA,MACzD;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,UAAM,YAAY,aAAa,WAAW,EAAE,gBAAgB,OAAO,MAAM;AACzE,cAAU,KAAK,IAAI,MAAM;AACzB,iBAAa,WAAW,EAAE,aAAa,WAAW,GAAG,CAAC;AACtD,WAAO,aAAa,UAAU,EAAE,QAAQ,OAAO,YAAY,EAAE,CAAC;AAAA,EAChE,SAAS,OAAO;AACd,UAAM,IAAI,MAAM,2CAA2C,EAAE,OAAO,MAAM,CAAC;AAAA,EAC7E,UAAE;AACA,cAAU,QAAQ;AAClB,iBAAa,QAAQ;AAAA,EACvB;AACF;AAGA,eAAsB,kBACpB,OACA,UAA6B,CAAC,GACH;AAC3B,gBAAc,KAAK;AACnB,QAAM,WAAW,gBAAgB,OAAO;AACxC,yBAAuB,OAAO,SAAS,aAAa;AACpD,QAAM,SAAS,MAAM,kBAAkB,KAAK;AAC5C,MAAI;AACF,WAAO,aAAa,QAAQ,QAAQ;AAAA,EACtC,UAAE;AACA,WAAO,QAAQ;AAAA,EACjB;AACF;AAGA,eAAsB,kBACpB,OACA,UAA6B,CAAC,GACH;AAC3B,gBAAc,KAAK;AACnB,QAAM,WAAW,gBAAgB,OAAO;AACxC,yBAAuB,OAAO,SAAS,aAAa;AACpD,MAAI,SAAS,WAAW,OAAO;AAC7B,UAAM,IAAI,MAAM,sDAAsD;AAAA,EACxE;AACA,QAAM,SAA0C,MAAM;AACtD,MAAI,CAAC,QAAQ,MAAO,OAAM,IAAI,MAAM,yBAAyB;AAE7D,QAAM,eAAe,MAAM,kBAAkB,OAAO,IAAI;AACxD,QAAM,SAAS,IAAI,yBAAa,QAAW;AAAA,IACzC,OAAO,MAAM,OAAO;AAAA,IACpB,QAAQ,MAAM,OAAO;AAAA,IACrB,wBAAwB;AAAA,EAC1B,CAAC;AACD,MAAI;AACF,WAAO,IAAI,MAAM,WAAW,OAAO,OAAO,MAAM,OAAO,OAAO,MAAM,OAAO,MAAM,CAAC;AAElF,UAAM,YAAY,OAAO,eACrB,MAAM;AAAA,MACJ;AAAA,MACA,OAAO;AAAA,MACP,MAAM,OAAO;AAAA,MACb,MAAM,OAAO;AAAA,IACf,IACA,aAAa,UAAU,EAAE,QAAQ,OAAO,YAAY,EAAE,CAAC;AAC3D,UAAM,SAAS,MAAM,wBAAY,QAAQ,SAAS;AAClD,WAAO,IAAI;AAAA,MACT,SAAS;AAAA,MACT,SAAS;AAAA,MACT,MAAM;AAAA,MACN,KAAK;AAAA,MACL,SAAS,aAAa,OAAO,aAAa;AAAA,MAC1C,0BAA0B,mBAAmB,OAAO,eAAe;AAAA,MACnE,YAAY;AAAA,MACZ,SAAS;AAAA,IACX,CAAC;AACD,QAAI,OAAO,aAAa,OAAO,oBAAoB,OAAO;AACxD,YAAM,OAAO;AAAA,QACX,OAAO;AAAA,QACP;AAAA,QACA;AAAA,QACA,MAAM,OAAO;AAAA,QACb,MAAM,OAAO;AAAA,MACf;AACA,aAAO,WAAW,IAAI,iBAAK;AAAA,QACzB,SAAS;AAAA,QACT,SAAS;AAAA,QACT,MAAM,KAAK;AAAA,QACX,KAAK,KAAK;AAAA,QACV,OAAO,KAAK;AAAA,QACZ,QAAQ,KAAK;AAAA,QACb,oBAAoB;AAAA,MACtB,CAAC;AAAA,IACH;AACA,WAAO,IAAI,MAAM;AAEjB,QAAI,OAAO,SAAS;AAClB,YAAM,UAAU,MAAM;AAAA,QACpB,OAAO,QAAQ;AAAA,QACf,MAAM,OAAO;AAAA,QACb,MAAM,OAAO;AAAA,MACf;AACA,cAAQ,IAAI;AAAA,QACV,SAAS,aAAa,OAAO,QAAQ,OAAO;AAAA,QAC5C,0BAA0B,mBAAmB,OAAO,QAAQ,aAAa,UAAU;AAAA,MACrF,CAAC;AACD,aAAO,IAAI,OAAO;AAAA,IACpB;AACA,WAAO,UAAU;AACjB,WAAO,aAAa,QAAQ,QAAQ;AAAA,EACtC,UAAE;AACA,iBAAa,QAAQ;AACrB,WAAO,QAAQ;AAAA,EACjB;AACF;AAEA,eAAe,YACb,QACA,SACA,UAC6B;AAC7B,QAAM,cAAc,KAAK,IAAI,GAAG,KAAK,MAAM,QAAQ,eAAe,CAAC,CAAC;AACpE,QAAM,UAAU,IAAI,MAAwB,OAAO,MAAM;AACzD,MAAI,YAAY;AAChB,QAAM,QAAQ;AAAA,IACZ,MAAM,KAAK,EAAE,QAAQ,KAAK,IAAI,aAAa,OAAO,MAAM,EAAE,GAAG,YAAY;AACvE,aAAO,YAAY,OAAO,QAAQ;AAChC,cAAM,QAAQ;AACd,gBAAQ,KAAK,IAAI,MAAM,SAAS,OAAO,KAAK,GAAG,OAAO;AAAA,MACxD;AAAA,IACF,CAAC;AAAA,EACH;AACA,SAAO;AACT;AAGA,eAAsB,uBACpB,QACA,UAAwD,CAAC,GAC5B;AAC7B,SAAO,YAAY,QAAQ,SAAS,iBAAiB;AACvD;AAGA,eAAsB,uBACpB,QACA,UAAwD,CAAC,GAC5B;AAC7B,SAAO,YAAY,QAAQ,SAAS,iBAAiB;AACvD;AApVA,iBAiCM,mBAGA;AApCN;AAAA;AAAA,kBAAsD;AAEtD;AACA;AAGA;AA2BA,IAAM,oBAAoB,oBAAI,IAAI,CAAC,SAAS,UAAU,OAAO,CAAC;AAG9D,IAAM,WAAW,oBAAI,IAAI,CAAC,OAAO,OAAO,CAAC;AAAA;AAAA;","names":["response","renderEditorState"]}
|
|
1
|
+
{"version":3,"sources":["../src/displacement.ts","../src/export.ts","../src/print.ts","../src/node.ts"],"sourcesContent":["import type { MockupDisplacement, MockupDisplacementChannel } from './types';\n\nconst CHANNEL_INDEX: Record<MockupDisplacementChannel, number> = {\n red: 0,\n green: 1,\n blue: 2,\n alpha: 3,\n};\n\nfunction finiteScale(value: number | undefined, fallback: number, label: string): number {\n const resolved = value ?? fallback;\n if (!Number.isFinite(resolved)) throw new Error(`${label} must be finite`);\n return resolved;\n}\n\nfunction sample(\n source: Uint8ClampedArray,\n width: number,\n height: number,\n x: number,\n y: number,\n channel: number,\n): number {\n const clampedX = Math.max(0, Math.min(width - 1, x));\n const clampedY = Math.max(0, Math.min(height - 1, y));\n const x0 = Math.floor(clampedX);\n const y0 = Math.floor(clampedY);\n const x1 = Math.min(width - 1, x0 + 1);\n const y1 = Math.min(height - 1, y0 + 1);\n const tx = clampedX - x0;\n const ty = clampedY - y0;\n const top =\n source[(y0 * width + x0) * 4 + channel] * (1 - tx) +\n source[(y0 * width + x1) * 4 + channel] * tx;\n const bottom =\n source[(y1 * width + x0) * 4 + channel] * (1 - tx) +\n source[(y1 * width + x1) * 4 + channel] * tx;\n return top * (1 - ty) + bottom * ty;\n}\n\n/**\n * Warp RGBA pixels with an equally sized channel map. A channel value of 128\n * is neutral; 0 and 255 move by the configured negative/positive maximum.\n */\nexport function displaceRgba(\n source: Uint8ClampedArray,\n map: Uint8ClampedArray,\n width: number,\n height: number,\n options: Omit<MockupDisplacement, 'image'>,\n): Uint8ClampedArray {\n if (!Number.isInteger(width) || !Number.isInteger(height) || width <= 0 || height <= 0) {\n throw new Error('Displacement dimensions must be positive integers');\n }\n const expectedLength = width * height * 4;\n if (source.length !== expectedLength || map.length !== expectedLength) {\n throw new Error('Displacement source and map must match the requested dimensions');\n }\n\n const scaleX = finiteScale(options.scaleX, 10, 'Displacement scaleX');\n const scaleY = finiteScale(options.scaleY, 10, 'Displacement scaleY');\n const channelX = CHANNEL_INDEX[options.channelX ?? 'red'];\n const channelY = CHANNEL_INDEX[options.channelY ?? 'green'];\n const output = new Uint8ClampedArray(expectedLength);\n\n for (let y = 0; y < height; y += 1) {\n for (let x = 0; x < width; x += 1) {\n const offset = (y * width + x) * 4;\n const sourceX = x + ((map[offset + channelX] - 128) / 127) * scaleX;\n const sourceY = y + ((map[offset + channelY] - 128) / 127) * scaleY;\n for (let channel = 0; channel < 4; channel += 1) {\n output[offset + channel] = Math.round(\n sample(source, width, height, sourceX, sourceY, channel),\n );\n }\n }\n }\n return output;\n}\n","import { StaticCanvas } from 'fabric';\nimport type { Canvas, FabricObject, ImageFormat } from 'fabric';\nimport type { MockupConfig, MockupPrintArea } from './types';\nimport { displaceRgba } from './displacement';\n\nexport interface PngExportOptions {\n multiplier?: number;\n format?: ImageFormat;\n quality?: number;\n}\n\nexport interface CoverPlacement {\n left: number;\n top: number;\n width: number;\n height: number;\n}\n\nexport function computePrintAreaClip(\n area: MockupPrintArea,\n scaleX: number,\n scaleY: number,\n targetWidth: number,\n targetHeight: number,\n): MockupPrintArea {\n const left = Math.max(0, Math.min(targetWidth, area.left * scaleX));\n const top = Math.max(0, Math.min(targetHeight, area.top * scaleY));\n const right = Math.max(left, Math.min(targetWidth, (area.left + area.width) * scaleX));\n const bottom = Math.max(top, Math.min(targetHeight, (area.top + area.height) * scaleY));\n return { left, top, width: right - left, height: bottom - top };\n}\n\n/** Object-fit: cover geometry, exported for deterministic preview/composite tests. */\nexport function computeCoverPlacement(\n sourceWidth: number,\n sourceHeight: number,\n targetWidth: number,\n targetHeight: number,\n): CoverPlacement {\n if (sourceWidth <= 0 || sourceHeight <= 0 || targetWidth <= 0 || targetHeight <= 0) {\n throw new Error('Cover dimensions must be positive');\n }\n const scale = Math.max(targetWidth / sourceWidth, targetHeight / sourceHeight);\n const width = sourceWidth * scale;\n const height = sourceHeight * scale;\n return {\n left: (targetWidth - width) / 2,\n top: (targetHeight - height) / 2,\n width,\n height,\n };\n}\n\nfunction canvasElementToBlob(\n output: HTMLCanvasElement,\n format: ImageFormat,\n quality: number,\n): Promise<Blob> {\n const mime = format === 'jpeg' ? 'image/jpeg' : `image/${format}`;\n return new Promise<Blob>((resolve, reject) => {\n output.toBlob(\n (blob) => (blob ? resolve(blob) : reject(new Error(`Failed to export ${format}`))),\n mime,\n quality,\n );\n });\n}\n\nexport async function exportPNG(canvas: Canvas, options: PngExportOptions = {}): Promise<Blob> {\n const { multiplier = 1, format = 'png' as ImageFormat, quality = 1 } = options;\n const output = canvas.toCanvasElement(multiplier);\n return canvasElementToBlob(output, format, quality);\n}\n\n/** Render cloned objects without mutating the live editor canvas. */\nexport async function exportIsolatedPNG(\n source: Canvas,\n objects: FabricObject[],\n options: PngExportOptions & {\n width?: number;\n height?: number;\n backgroundColor?: string;\n backgroundImage?: FabricObject | null;\n cloneObjects?: boolean;\n } = {},\n): Promise<Blob> {\n const element = source.lowerCanvasEl.ownerDocument.createElement('canvas');\n const canvas = new StaticCanvas(element, {\n width: options.width ?? source.getWidth(),\n height: options.height ?? source.getHeight(),\n backgroundColor: options.backgroundColor || undefined,\n });\n try {\n const clones =\n options.cloneObjects === false\n ? objects\n : await Promise.all(objects.map((object) => object.clone()));\n if (clones.length) canvas.add(...clones);\n if (options.backgroundImage) canvas.backgroundImage = await options.backgroundImage.clone();\n canvas.requestRenderAll();\n // Awaited, not returned: `finally` would otherwise dispose the canvas while\n // the export is still reading from it.\n return await exportPNG(canvas as unknown as Canvas, options);\n } finally {\n canvas.dispose();\n }\n}\n\n/**\n * Render just the print-area rectangle, on transparency.\n *\n * This is the file a print provider receives: the design alone, cropped to the\n * printable rectangle, with no garment behind it and no canvas background baked\n * in — so it is rendered from cloned objects rather than off the live canvas.\n */\nexport async function exportPrintArea(\n source: Canvas,\n area: MockupPrintArea,\n options: PngExportOptions = {},\n): Promise<Blob> {\n const { multiplier = 1, format = 'png' as ImageFormat, quality = 1 } = options;\n const width = source.getWidth();\n const height = source.getHeight();\n const clip = computePrintAreaClip(\n area,\n multiplier,\n multiplier,\n width * multiplier,\n height * multiplier,\n );\n if (clip.width <= 0 || clip.height <= 0) {\n throw new Error('Print area does not overlap the canvas');\n }\n\n const element = source.lowerCanvasEl.ownerDocument.createElement('canvas');\n const canvas = new StaticCanvas(element, { width, height });\n try {\n const clones = await Promise.all(source.getObjects().map((object) => object.clone()));\n if (clones.length) canvas.add(...clones);\n canvas.requestRenderAll();\n const rendered = canvas.toCanvasElement(multiplier);\n const output = rendered.ownerDocument.createElement('canvas');\n output.width = Math.max(1, Math.round(clip.width));\n output.height = Math.max(1, Math.round(clip.height));\n const context = output.getContext('2d');\n if (!context) throw new Error('2D canvas context is unavailable');\n context.drawImage(rendered, -clip.left, -clip.top);\n // Awaited, not returned: `finally` would dispose the canvas mid-read.\n return await canvasElementToBlob(output, format, quality);\n } finally {\n canvas.dispose();\n }\n}\n\n/** Rasterize the browser mockup preview together with the transparent design. */\nexport async function exportMockup(\n canvas: Canvas,\n mockup: MockupConfig,\n options: PngExportOptions = {},\n): Promise<Blob> {\n const { multiplier = 1, format = 'png' as ImageFormat, quality = 1 } = options;\n const design = canvas.toCanvasElement(multiplier);\n const output = design.ownerDocument.createElement('canvas');\n output.width = design.width;\n output.height = design.height;\n const context = output.getContext('2d');\n if (!context) throw new Error('2D canvas context is unavailable');\n\n const loadImage = (url: string) =>\n new Promise<HTMLImageElement>((resolve, reject) => {\n const element = new Image();\n element.crossOrigin = 'anonymous';\n element.onload = () => resolve(element);\n element.onerror = () => reject(new Error(`Failed to load mockup image: ${url}`));\n element.src = url;\n });\n const drawCover = (\n image: HTMLImageElement,\n targetContext: CanvasRenderingContext2D = context,\n ) => {\n const placement = computeCoverPlacement(\n image.naturalWidth || image.width,\n image.naturalHeight || image.height,\n output.width,\n output.height,\n );\n targetContext.drawImage(\n image,\n placement.left,\n placement.top,\n placement.width,\n placement.height,\n );\n };\n\n // Full-size scratch buffers, released explicitly in the finally below: a\n // detached canvas element can hold its backing store well past its last\n // reference, and a 4K mockup allocates three of them per export.\n const scratch: HTMLCanvasElement[] = [design];\n try {\n drawCover(await loadImage(mockup.image));\n let compositedDesign: CanvasImageSource = design;\n if (mockup.displacement) {\n const sourceContext = design.getContext('2d');\n if (!sourceContext) throw new Error('2D design context is unavailable');\n const mapCanvas = design.ownerDocument.createElement('canvas');\n scratch.push(mapCanvas);\n mapCanvas.width = design.width;\n mapCanvas.height = design.height;\n const mapContext = mapCanvas.getContext('2d');\n if (!mapContext) throw new Error('2D displacement-map context is unavailable');\n drawCover(await loadImage(mockup.displacement.image), mapContext);\n\n const warped = design.ownerDocument.createElement('canvas');\n scratch.push(warped);\n warped.width = design.width;\n warped.height = design.height;\n const warpedContext = warped.getContext('2d');\n if (!warpedContext) throw new Error('2D displaced-design context is unavailable');\n let sourcePixels: Uint8ClampedArray;\n let mapPixels: Uint8ClampedArray;\n try {\n sourcePixels = sourceContext.getImageData(0, 0, design.width, design.height).data;\n mapPixels = mapContext.getImageData(0, 0, design.width, design.height).data;\n } catch (error) {\n throw new Error('Failed to apply mockup displacement map; verify image CORS access', {\n cause: error,\n });\n }\n const pixels = displaceRgba(sourcePixels, mapPixels, design.width, design.height, {\n ...mockup.displacement,\n scaleX: (mockup.displacement.scaleX ?? 10) * multiplier,\n scaleY: (mockup.displacement.scaleY ?? 10) * multiplier,\n });\n const imageData = warpedContext.createImageData(design.width, design.height);\n imageData.data.set(pixels);\n warpedContext.putImageData(imageData, 0, 0);\n compositedDesign = warped;\n }\n context.save();\n if (mockup.printArea && mockup.clipToPrintArea !== false) {\n const clip = computePrintAreaClip(\n mockup.printArea,\n output.width / canvas.getWidth(),\n output.height / canvas.getHeight(),\n output.width,\n output.height,\n );\n context.beginPath();\n context.rect(clip.left, clip.top, clip.width, clip.height);\n context.clip();\n }\n context.globalAlpha = Math.max(0, Math.min(1, mockup.designOpacity ?? 1));\n context.globalCompositeOperation =\n !mockup.designBlendMode || mockup.designBlendMode === 'normal'\n ? 'source-over'\n : mockup.designBlendMode;\n context.drawImage(compositedDesign, 0, 0);\n context.restore();\n\n if (mockup.overlay) {\n context.save();\n context.globalAlpha = Math.max(0, Math.min(1, mockup.overlay.opacity ?? 1));\n context.globalCompositeOperation =\n mockup.overlay.blendMode === 'normal'\n ? 'source-over'\n : (mockup.overlay.blendMode ?? 'multiply');\n drawCover(await loadImage(mockup.overlay.image));\n context.restore();\n }\n return await canvasElementToBlob(output, format, quality);\n } finally {\n for (const element of scratch) {\n element.width = 0;\n element.height = 0;\n }\n }\n}\n\nexport function exportSVG(canvas: Canvas): string {\n return canvas.toSVG();\n}\n\nexport function exportDataURL(canvas: Canvas, format: ImageFormat = 'png', multiplier = 1): string {\n return canvas.toDataURL({ format, multiplier });\n}\n","import type { EditorState } from './types';\nimport type { NodeRenderOptions } from './node';\n\nexport interface PrintPdfOptions {\n /** Rasterization density. Defaults to the document DPI, or 300. */\n dpi?: number;\n /** Bleed on every edge, in inches. Defaults to 0.125in. */\n bleed?: number;\n /** Space outside bleed reserved for printer marks, in inches. Defaults to 0.25in. */\n marksMargin?: number;\n trimMarks?: boolean;\n registrationMarks?: boolean;\n /** Optional safe-area inset in inches for preflight warnings. */\n safeArea?: number;\n /** Sharp built-in `cmyk` profile or an absolute path to a custom ICC profile. */\n iccProfile?: string;\n /** Ceiling on the rasterized bleed image, in pixels. Defaults to 250 megapixels. */\n maxPixels?: number;\n outputConditionIdentifier?: string;\n title?: string;\n allowImageUrl?: NodeRenderOptions['allowImageUrl'];\n /** Preserve SVG shapes/text over a CMYK bleed raster. Defaults to `vector`. */\n rendering?: 'vector' | 'raster';\n /** PDFKit font registrations keyed by the exact SVG font-family name. */\n fontFiles?: Record<string, string | Uint8Array>;\n /** Convert text backed by `fontFiles` into glyph paths. Defaults to true. */\n outlineFonts?: boolean;\n}\n\nexport interface PrintPdfResult {\n format: 'pdf';\n mimeType: 'application/pdf';\n data: Uint8Array;\n standard: 'PDF/X-4';\n colourSpace: 'CMYK';\n rendering: 'vector' | 'raster';\n outlinedFonts: string[];\n unoutlinedFonts: string[];\n dpi: number;\n trimWidthPoints: number;\n trimHeightPoints: number;\n bleedPoints: number;\n warnings: string[];\n}\n\nfunction svgAttributes(source: string): Record<string, string> {\n return Object.fromEntries(\n [...source.matchAll(/([\\w:-]+)=(?:\"([^\"]*)\"|'([^']*)')/g)].map((match) => [\n match[1],\n match[2] ?? match[3] ?? '',\n ]),\n );\n}\n\nfunction decodeXmlText(source: string): string {\n return source\n .replace(/<[^>]+>/g, '')\n .replace(/&#x([\\da-f]+);/gi, (_, value: string) =>\n String.fromCodePoint(Number.parseInt(value, 16)),\n )\n .replace(/&#(\\d+);/g, (_, value: string) => String.fromCodePoint(Number(value)))\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/"/g, '\"')\n .replace(/'/g, \"'\")\n .replace(/&/g, '&');\n}\n\nfunction escapeXmlAttribute(value: string): string {\n return value.replace(/[<>&\"']/g, (character) => `&#${character.charCodeAt(0)};`);\n}\n\nfunction fontSource(\n files: Record<string, string | Uint8Array>,\n family: string,\n bold: boolean,\n italic: boolean,\n): string | Uint8Array | undefined {\n const suffix = bold && italic ? '-BoldItalic' : bold ? '-Bold' : italic ? '-Italic' : '';\n // `family` comes from the untrusted SVG, so plain indexing would resolve\n // `__proto__`/`constructor` to inherited members and hand a non-font to fontkit.\n const own = (key: string) =>\n Object.hasOwn(files, key) ? (files[key] as string | Uint8Array) : undefined;\n return own(`${family}${suffix}`) ?? own(family);\n}\n\nasync function outlineSvgText(\n svg: string,\n files: Record<string, string | Uint8Array>,\n outlined: Set<string>,\n): Promise<string> {\n const fontkit = await import('fontkit');\n let output = '';\n let cursor = 0;\n for (const textMatch of svg.matchAll(/<text\\b([^>]*)>([\\s\\S]*?)<\\/text>/gi)) {\n const index = textMatch.index ?? 0;\n output += svg.slice(cursor, index);\n cursor = index + textMatch[0].length;\n const textAttributes = svgAttributes(textMatch[1]);\n const spans = [...textMatch[2].matchAll(/<tspan\\b([^>]*)>([\\s\\S]*?)<\\/tspan>/gi)];\n const lines = spans.length\n ? spans.map((span) => ({ attributes: svgAttributes(span[1]), text: decodeXmlText(span[2]) }))\n : [{ attributes: textAttributes, text: decodeXmlText(textMatch[2]) }];\n const resolved = lines.map((line) => {\n const attributes = { ...textAttributes, ...line.attributes };\n const family = attributes['font-family'] ?? 'sans-serif';\n const bold = /bold|[6-9]00/i.test(attributes['font-weight'] ?? '');\n const italic = /italic|oblique/i.test(attributes['font-style'] ?? '');\n return { ...line, attributes, family, source: fontSource(files, family, bold, italic) };\n });\n if (resolved.some((line) => !line.source)) {\n output += textMatch[0];\n continue;\n }\n const paths: string[] = [];\n for (const line of resolved) {\n const source = line.source!;\n const opened =\n typeof source === 'string'\n ? fontkit.openSync(source)\n : fontkit.create(Buffer.from(source.buffer, source.byteOffset, source.byteLength));\n if (!('layout' in opened)) {\n throw new Error(`Font collection requires a named face: ${line.family}`);\n }\n const size = Number.parseFloat(line.attributes['font-size'] ?? '16');\n const scale = size / opened.unitsPerEm;\n const style = line.attributes.style ?? '';\n const run = opened.layout(line.text);\n let penX = Number.parseFloat(line.attributes.x ?? '0');\n const baseline = Number.parseFloat(line.attributes.y ?? '0');\n run.glyphs.forEach((glyph, glyphIndex) => {\n const position = run.positions[glyphIndex];\n const x = penX + position.xOffset * scale;\n const y = baseline - position.yOffset * scale;\n paths.push(\n `<path d=\"${glyph.path.toSVG()}\" transform=\"translate(${x} ${y}) scale(${scale} ${-scale})\" style=\"${escapeXmlAttribute(style)}\"/>`,\n );\n penX += position.xAdvance * scale;\n });\n outlined.add(line.family);\n }\n output += `<g data-outlined-font=\"${escapeXmlAttribute([...new Set(resolved.map((line) => line.family))].join(','))}\">${paths.join('')}</g>`;\n }\n return output + svg.slice(cursor);\n}\n\nfunction rgbToCmyk([redByte, greenByte, blueByte]: [number, number, number]): [\n number,\n number,\n number,\n number,\n] {\n const red = redByte / 255;\n const green = greenByte / 255;\n const blue = blueByte / 255;\n const black = 1 - Math.max(red, green, blue);\n if (black >= 1) return [0, 0, 0, 100];\n return [\n ((1 - red - black) / (1 - black)) * 100,\n ((1 - green - black) / (1 - black)) * 100,\n ((1 - blue - black) / (1 - black)) * 100,\n black * 100,\n ];\n}\n\nasync function imageSourceBytes(\n source: string,\n allow?: (url: string) => boolean,\n): Promise<Uint8Array> {\n if (source.startsWith('data:')) {\n const response = await fetch(source);\n if (!response.ok) throw new Error('Failed to decode an embedded SVG image');\n return new Uint8Array(await response.arrayBuffer());\n }\n const permitted = allow\n ? allow(source)\n : (() => {\n try {\n return ['http:', 'https:'].includes(new URL(source).protocol);\n } catch {\n return false;\n }\n })();\n if (!permitted) throw new Error(`Blocked disallowed vector image URL: ${source}`);\n const response = await fetch(source);\n if (!response.ok) throw new Error(`Failed to load vector image: ${source}`);\n return new Uint8Array(await response.arrayBuffer());\n}\n\nasync function convertSvgImagesToCmyk(\n svg: string,\n sharp: (typeof import('sharp'))['default'],\n profile: string,\n allow?: (url: string) => boolean,\n): Promise<string> {\n const sources = new Set<string>();\n for (const image of svg.matchAll(/<image\\b[^>]*(?:xlink:href|href)=\"([^\"]+)\"[^>]*>/gi)) {\n if (image[1]) sources.add(image[1]);\n }\n let converted = svg;\n for (const source of sources) {\n const bytes = await imageSourceBytes(source, allow);\n const jpeg = await sharp(bytes)\n .flatten({ background: '#ffffff' })\n .toColourspace('cmyk')\n .withIccProfile(profile)\n .jpeg({ quality: 100, chromaSubsampling: '4:4:4' })\n .toBuffer();\n const dataUrl = `data:image/jpeg;base64,${jpeg.toString('base64')}`;\n converted = converted.split(source).join(dataUrl);\n }\n return converted;\n}\n\nasync function renderVectorOverlay(\n state: EditorState,\n options: PrintPdfOptions,\n width: number,\n height: number,\n sharp: (typeof import('sharp'))['default'],\n warnings: string[],\n outlinedFonts: Set<string>,\n unoutlinedFonts: Set<string>,\n): Promise<Uint8Array> {\n const [{ default: PDFKit }, { default: SVGtoPDF }, { renderEditorState }] = await Promise.all([\n import('pdfkit'),\n import('svg-to-pdfkit'),\n import('./node'),\n ]);\n // The bleed image is already flattened onto white. Render the trim overlay\n // against the same opaque print substrate so semi-transparent artwork does\n // not blend a second time with the raster copy beneath it.\n const rendered = await renderEditorState(\n { ...state, background: '#ffffff' },\n {\n format: 'svg',\n allowImageUrl: options.allowImageUrl,\n },\n );\n if (typeof rendered.data !== 'string') throw new Error('Vector rendering returned raster data');\n const fontFiles = options.fontFiles ?? {};\n const outlinedSvg =\n options.outlineFonts === false\n ? rendered.data\n : await outlineSvgText(rendered.data, fontFiles, outlinedFonts);\n const svg = await convertSvgImagesToCmyk(\n outlinedSvg,\n sharp,\n options.iccProfile ?? 'cmyk',\n options.allowImageUrl,\n );\n const remainingText = [...svg.matchAll(/<text\\b([^>]*)>/gi)].map((match) =>\n svgAttributes(match[1]),\n );\n for (const attributes of remainingText) {\n const family = attributes['font-family'] ?? 'sans-serif';\n unoutlinedFonts.add(family);\n const bold = /bold|[6-9]00/i.test(attributes['font-weight'] ?? '');\n const italic = /italic|oblique/i.test(attributes['font-style'] ?? '');\n if (!fontSource(fontFiles, family, bold, italic)) {\n warnings.push(\n `Font \"${family}\" used a PDF standard fallback; supply fontFiles for exact embedding`,\n );\n }\n }\n\n const document = new PDFKit({ autoFirstPage: false, compress: false, pdfVersion: '1.7' });\n for (const [name, path] of Object.entries(fontFiles)) {\n document.registerFont(name, typeof path === 'string' ? path : Buffer.from(path));\n }\n document.addPage({ size: [width, height], margin: 0 });\n SVGtoPDF(document, svg, 0, 0, {\n width,\n height,\n preserveAspectRatio: 'none',\n colorCallback: (color) => {\n const [rgb, opacity] = color;\n return [rgbToCmyk(rgb), opacity] as unknown as typeof color;\n },\n warningCallback: (warning) => warnings.push(`Vector render: ${warning}`),\n });\n\n return new Promise<Uint8Array>((resolve, reject) => {\n const chunks: Uint8Array[] = [];\n document.on('data', (chunk: Uint8Array) => chunks.push(chunk));\n document.on('error', reject);\n document.on('end', () => resolve(new Uint8Array(Buffer.concat(chunks))));\n document.end();\n });\n}\n\n/** Beyond this no printer is served, and larger values only buy an OOM. */\nconst MAX_DPI = 2400;\n/** ~24×36in at 600dpi. Bounds the raster a hostile state can ask a server for. */\nconst DEFAULT_MAX_PIXELS = 250_000_000;\n\nfunction positive(value: number, label: string): number {\n if (!Number.isFinite(value) || value <= 0) throw new Error(`${label} must be positive`);\n return value;\n}\n\n/**\n * States are browser-authored and untrusted on a server. `documentDpi` divides\n * the render multiplier, so an unvalidated fractional value (0.001) inflates the\n * rasterization by six orders of magnitude before any size check runs.\n */\nfunction boundedDpi(value: number, label: string): number {\n const dpi = positive(value, label);\n if (dpi > MAX_DPI) throw new Error(`${label} must not exceed ${MAX_DPI}`);\n if (dpi < 1) throw new Error(`${label} must be at least 1`);\n return dpi;\n}\n\nfunction nonNegative(value: number, label: string): number {\n if (!Number.isFinite(value) || value < 0) throw new Error(`${label} cannot be negative`);\n return value;\n}\n\nfunction preflightSafeArea(state: EditorState, safePixels: number): string[] {\n if (safePixels <= 0) return [];\n const right = state.canvas.width - safePixels;\n const bottom = state.canvas.height - safePixels;\n const warnings: string[] = [];\n for (const layer of state.layers) {\n if (!layer.visible) continue;\n const object = layer.fabricObject;\n const left = Number(object.left ?? 0);\n const top = Number(object.top ?? 0);\n const width = Number(object.width ?? 0) * Math.abs(Number(object.scaleX ?? 1));\n const height = Number(object.height ?? 0) * Math.abs(Number(object.scaleY ?? 1));\n if (left < safePixels || top < safePixels || left + width > right || top + height > bottom) {\n warnings.push(`Layer \"${layer.name}\" extends outside the configured safe area`);\n }\n }\n return warnings;\n}\n\n/**\n * Render an EditorState into a print-production PDF/X-4 file.\n *\n * The design is rasterized at the requested density, converted through Sharp's\n * CMYK ICC pipeline, edge-extended into bleed, and embedded with output intent,\n * trim/bleed boxes, XMP identification, and optional printer marks.\n */\nexport async function renderPrintPdf(\n state: EditorState,\n options: PrintPdfOptions = {},\n): Promise<PrintPdfResult> {\n const dpi = boundedDpi(options.dpi ?? state.canvas.dpi ?? 300, 'Print DPI');\n const documentDpi = boundedDpi(state.canvas.dpi ?? 72, 'Document DPI');\n const maxPixels = positive(options.maxPixels ?? DEFAULT_MAX_PIXELS, 'Max pixels');\n const bleedInches = nonNegative(options.bleed ?? 0.125, 'Bleed');\n const marksMarginInches = nonNegative(options.marksMargin ?? 0.25, 'Marks margin');\n const safeAreaInches = nonNegative(options.safeArea ?? 0, 'Safe area');\n const rendering = options.rendering ?? 'vector';\n const bleedPixels = Math.round(bleedInches * dpi);\n const trimWidthPoints = (state.canvas.width / documentDpi) * 72;\n const trimHeightPoints = (state.canvas.height / documentDpi) * 72;\n const bleedPoints = bleedInches * 72;\n const marksMarginPoints = marksMarginInches * 72;\n\n const scale = dpi / documentDpi;\n const outputPixels =\n Math.round(state.canvas.width * scale + bleedPixels * 2) *\n Math.round(state.canvas.height * scale + bleedPixels * 2);\n if (!Number.isFinite(outputPixels) || outputPixels > maxPixels) {\n throw new Error(\n `Print raster of ${outputPixels} pixels exceeds the ${maxPixels} pixel budget; lower the DPI or raise maxPixels`,\n );\n }\n\n const [{ default: sharp }, pdfLib] = await Promise.all([import('sharp'), import('pdf-lib')]);\n // Keep the optional print entry free of a static cycle with `node.ts`, which\n // re-exports this function as part of the Node-only public surface.\n const { renderEditorState } = await import('./node');\n const rendered = await renderEditorState(state, {\n format: 'png',\n multiplier: scale,\n allowImageUrl: options.allowImageUrl,\n });\n if (typeof rendered.data === 'string') throw new Error('Print rasterization returned SVG data');\n\n let pipeline = sharp(rendered.data).flatten({ background: '#ffffff' });\n if (bleedPixels > 0) {\n pipeline = pipeline.extend({\n top: bleedPixels,\n right: bleedPixels,\n bottom: bleedPixels,\n left: bleedPixels,\n extendWith: 'copy',\n });\n }\n const { data: cmykJpeg, info } = await pipeline\n .toColourspace('cmyk')\n .withIccProfile(options.iccProfile ?? 'cmyk')\n .withDensity(dpi)\n .jpeg({ quality: 100, chromaSubsampling: '4:4:4' })\n .toBuffer({ resolveWithObject: true });\n const metadata = await sharp(cmykJpeg).metadata();\n if (info.channels !== 4 || metadata.space !== 'cmyk' || !metadata.icc) {\n throw new Error('CMYK conversion did not produce a four-channel image with an ICC profile');\n }\n\n const { PDFDocument, PDFDict, PDFName, PDFString, cmyk } = pdfLib;\n const document = await PDFDocument.create();\n const title = options.title ?? 'Overtone Canvas Editor print export';\n document.setTitle(title);\n document.setCreator('@overtone-art/canvas-editor-core');\n document.setProducer('@overtone-art/canvas-editor-core');\n const pageWidth = trimWidthPoints + bleedPoints * 2 + marksMarginPoints * 2;\n const pageHeight = trimHeightPoints + bleedPoints * 2 + marksMarginPoints * 2;\n const page = document.addPage([pageWidth, pageHeight]);\n const image = await document.embedJpg(cmykJpeg);\n page.drawImage(image, {\n x: marksMarginPoints,\n y: marksMarginPoints,\n width: trimWidthPoints + bleedPoints * 2,\n height: trimHeightPoints + bleedPoints * 2,\n });\n\n const trimLeft = marksMarginPoints + bleedPoints;\n const trimBottom = marksMarginPoints + bleedPoints;\n const trimRight = trimLeft + trimWidthPoints;\n const trimTop = trimBottom + trimHeightPoints;\n const warnings = preflightSafeArea(state, safeAreaInches * documentDpi);\n const outlinedFonts = new Set<string>();\n const unoutlinedFonts = new Set<string>();\n if (rendering === 'vector') {\n const vectorPdf = await renderVectorOverlay(\n state,\n options,\n trimWidthPoints,\n trimHeightPoints,\n sharp,\n warnings,\n outlinedFonts,\n unoutlinedFonts,\n );\n const [vectorPage] = await document.embedPdf(vectorPdf);\n page.drawPage(vectorPage, {\n x: trimLeft,\n y: trimBottom,\n width: trimWidthPoints,\n height: trimHeightPoints,\n });\n }\n const bleedLeft = marksMarginPoints;\n const bleedBottom = marksMarginPoints;\n const bleedRight = pageWidth - marksMarginPoints;\n const bleedTop = pageHeight - marksMarginPoints;\n const context = document.context;\n page.node.set(PDFName.of('TrimBox'), context.obj([trimLeft, trimBottom, trimRight, trimTop]));\n page.node.set(\n PDFName.of('BleedBox'),\n context.obj([bleedLeft, bleedBottom, bleedRight, bleedTop]),\n );\n page.node.set(PDFName.of('ArtBox'), context.obj([trimLeft, trimBottom, trimRight, trimTop]));\n\n const markColour = cmyk(0, 0, 0, 1);\n if (options.trimMarks !== false) {\n const offset = Math.max(3, bleedPoints / 2);\n const length = Math.max(9, marksMarginPoints - 3);\n for (const x of [trimLeft, trimRight]) {\n page.drawLine({\n start: { x, y: trimBottom - offset },\n end: { x, y: trimBottom - offset - length },\n thickness: 0.5,\n color: markColour,\n });\n page.drawLine({\n start: { x, y: trimTop + offset },\n end: { x, y: trimTop + offset + length },\n thickness: 0.5,\n color: markColour,\n });\n }\n for (const y of [trimBottom, trimTop]) {\n page.drawLine({\n start: { x: trimLeft - offset, y },\n end: { x: trimLeft - offset - length, y },\n thickness: 0.5,\n color: markColour,\n });\n page.drawLine({\n start: { x: trimRight + offset, y },\n end: { x: trimRight + offset + length, y },\n thickness: 0.5,\n color: markColour,\n });\n }\n }\n if (options.registrationMarks !== false) {\n for (const [x, y] of [\n [pageWidth / 2, marksMarginPoints / 2],\n [pageWidth / 2, pageHeight - marksMarginPoints / 2],\n [marksMarginPoints / 2, pageHeight / 2],\n [pageWidth - marksMarginPoints / 2, pageHeight / 2],\n ] as Array<[number, number]>) {\n page.drawCircle({ x, y, size: 4, borderWidth: 0.5, borderColor: markColour });\n page.drawLine({\n start: { x: x - 6, y },\n end: { x: x + 6, y },\n thickness: 0.5,\n color: markColour,\n });\n page.drawLine({\n start: { x, y: y - 6 },\n end: { x, y: y + 6 },\n thickness: 0.5,\n color: markColour,\n });\n }\n }\n\n const profileStream = context.flateStream(metadata.icc, {\n N: 4,\n Alternate: PDFName.of('DeviceCMYK'),\n });\n const profileRef = context.register(profileStream);\n const outputIntent = context.obj({\n Type: PDFName.of('OutputIntent'),\n S: PDFName.of('GTS_PDFX'),\n OutputConditionIdentifier: PDFString.of(options.outputConditionIdentifier ?? 'CMYK'),\n RegistryName: PDFString.of('https://www.color.org'),\n Info: PDFString.of(options.outputConditionIdentifier ?? 'CMYK print condition'),\n DestOutputProfile: profileRef,\n });\n document.catalog.set(PDFName.of('OutputIntents'), context.obj([context.register(outputIntent)]));\n\n const now = new Date().toISOString();\n const xmp = `<?xpacket begin=\"\" id=\"W5M0MpCehiHzreSzNTczkc9d\"?>\n<x:xmpmeta xmlns:x=\"adobe:ns:meta/\"><rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">\n<rdf:Description rdf:about=\"\" xmlns:pdfxid=\"http://www.npes.org/pdfx/ns/id/\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:xmp=\"http://ns.adobe.com/xap/1.0/\" pdfxid:GTS_PDFXVersion=\"PDF/X-4\" xmp:CreateDate=\"${now}\"><dc:title><rdf:Alt><rdf:li xml:lang=\"x-default\">${title.replace(/[<>&]/g, '')}</rdf:li></rdf:Alt></dc:title></rdf:Description>\n</rdf:RDF></x:xmpmeta><?xpacket end=\"w\"?>`;\n const metadataStream = context.flateStream(new TextEncoder().encode(xmp), {\n Type: PDFName.of('Metadata'),\n Subtype: PDFName.of('XML'),\n });\n document.catalog.set(PDFName.of('Metadata'), context.register(metadataStream));\n const infoRef = context.trailerInfo.Info;\n if (infoRef) {\n const infoDict = context.lookup(infoRef, PDFDict);\n infoDict.set(PDFName.of('GTS_PDFXVersion'), PDFString.of('PDF/X-4'));\n infoDict.set(PDFName.of('Trapped'), PDFName.of('False'));\n }\n\n return {\n format: 'pdf',\n mimeType: 'application/pdf',\n data: await document.save({ useObjectStreams: false }),\n standard: 'PDF/X-4',\n colourSpace: 'CMYK',\n rendering,\n outlinedFonts: [...outlinedFonts].sort(),\n unoutlinedFonts: [...unoutlinedFonts].sort(),\n dpi,\n trimWidthPoints,\n trimHeightPoints,\n bleedPoints,\n warnings,\n };\n}\n","import { FabricImage, Rect, StaticCanvas, util } from 'fabric/node';\nimport type { FabricObject, ImageFormat } from 'fabric/node';\nimport { computeCoverPlacement, computePrintAreaClip } from './export';\nimport { displaceRgba } from './displacement';\nimport type { EditorState, MockupBlendMode, MockupConfig, MockupDisplacement } from './types';\n\nexport { renderPrintPdf } from './print';\nexport type { PrintPdfOptions, PrintPdfResult } from './print';\n\nexport interface NodeRenderOptions {\n format?: 'png' | 'jpeg' | 'webp' | 'svg';\n multiplier?: number;\n quality?: number;\n /**\n * Gate every image URL referenced by the state before it is loaded. States\n * are authored in the browser and therefore untrusted on a server; the\n * default policy allows only `http:`, `https:` and `data:`. Supply a\n * narrower predicate (e.g. an origin allowlist) to also stop requests to\n * internal hosts.\n */\n allowImageUrl?: (url: string) => boolean;\n}\n\nexport interface NodeRenderResult {\n format: 'png' | 'jpeg' | 'webp' | 'svg';\n mimeType: string;\n data: Uint8Array | string;\n width: number;\n height: number;\n}\n\n// `fabric/node` resolves bare paths and `file:` URLs against the local disk, so\n// an unrestricted state is a local-file-read and SSRF primitive on a server.\nconst ALLOWED_PROTOCOLS = new Set(['http:', 'https:', 'data:']);\n\n/** Keys whose string values are fetched as images during a render. */\nconst URL_KEYS = new Set(['src', 'image']);\n\nfunction defaultAllowImageUrl(url: string): boolean {\n const scheme = /^([a-z][a-z\\d+.-]*):/i.exec(url.trim());\n return scheme !== null && ALLOWED_PROTOCOLS.has(`${scheme[1].toLowerCase()}:`);\n}\n\nfunction assertImageUrlsAllowed(value: unknown, allow: (url: string) => boolean): void {\n if (Array.isArray(value)) {\n for (const item of value) assertImageUrlsAllowed(item, allow);\n return;\n }\n if (!value || typeof value !== 'object') return;\n for (const [key, entry] of Object.entries(value)) {\n if (typeof entry === 'string') {\n if (URL_KEYS.has(key) && !allow(entry)) {\n throw new Error(`Blocked disallowed image URL: ${entry.slice(0, 120)}`);\n }\n } else {\n assertImageUrlsAllowed(entry, allow);\n }\n }\n}\n\nfunction validateState(state: EditorState): void {\n if (\n !state?.canvas ||\n !Array.isArray(state.layers) ||\n !Number.isFinite(state.canvas.width) ||\n !Number.isFinite(state.canvas.height) ||\n state.canvas.width <= 0 ||\n state.canvas.height <= 0\n ) {\n throw new Error('Invalid editor state');\n }\n const major = Number.parseInt(state.version?.split('.')[0] ?? '1', 10);\n if (!Number.isFinite(major) || major > 2) {\n throw new Error(`Unsupported editor state version: ${state.version}`);\n }\n}\n\nfunction dataUrlBytes(dataUrl: string): Uint8Array {\n const encoded = dataUrl.slice(dataUrl.indexOf(',') + 1);\n const binary = atob(encoded);\n const bytes = new Uint8Array(binary.length);\n for (let index = 0; index < binary.length; index += 1) bytes[index] = binary.charCodeAt(index);\n return bytes;\n}\n\nfunction validateOptions(options: NodeRenderOptions): Required<NodeRenderOptions> {\n const format = options.format ?? 'png';\n const multiplier = options.multiplier ?? 1;\n const quality = options.quality ?? 1;\n const allowImageUrl = options.allowImageUrl ?? defaultAllowImageUrl;\n if (!Number.isFinite(multiplier) || multiplier <= 0) {\n throw new Error('Render multiplier must be positive');\n }\n if (!Number.isFinite(quality) || quality < 0 || quality > 1) {\n throw new Error('Render quality must be between 0 and 1');\n }\n return { format, multiplier, quality, allowImageUrl };\n}\n\nasync function createStateCanvas(state: EditorState, transparent = false): Promise<StaticCanvas> {\n const canvas = new StaticCanvas(undefined, {\n width: state.canvas.width,\n height: state.canvas.height,\n backgroundColor: transparent ? '' : (state.background ?? ''),\n preserveObjectStacking: true,\n });\n try {\n if (!transparent && state.backgroundImage) {\n canvas.backgroundImage = (\n await util.enlivenObjects([state.backgroundImage])\n )[0] as FabricObject;\n }\n const objects = (await util.enlivenObjects(\n state.layers.map((layer) => layer.fabricObject),\n )) as FabricObject[];\n objects.forEach((object, index) => {\n const layer = state.layers[index];\n object.set({ visible: layer.visible, opacity: layer.opacity });\n canvas.add(object);\n });\n canvas.renderAll();\n return canvas;\n } catch (error) {\n canvas.dispose();\n throw error;\n }\n}\n\nfunction encodeCanvas(\n canvas: StaticCanvas,\n options: Required<NodeRenderOptions>,\n): NodeRenderResult {\n const { format, multiplier, quality } = options;\n const width = Math.round(canvas.getWidth() * multiplier);\n const height = Math.round(canvas.getHeight() * multiplier);\n if (format === 'svg') {\n return { format, mimeType: 'image/svg+xml', data: canvas.toSVG(), width, height };\n }\n const dataUrl = canvas.toDataURL({ format: format as ImageFormat, multiplier, quality });\n return {\n format,\n mimeType: format === 'jpeg' ? 'image/jpeg' : `image/${format}`,\n data: dataUrlBytes(dataUrl),\n width,\n height,\n };\n}\n\nfunction compositeOperation(mode?: MockupBlendMode): GlobalCompositeOperation {\n return !mode || mode === 'normal' ? 'source-over' : mode;\n}\n\nfunction clampOpacity(value = 1): number {\n return Math.max(0, Math.min(1, value));\n}\n\nasync function coverImage(url: string, width: number, height: number): Promise<FabricImage> {\n let image: FabricImage;\n try {\n image = await FabricImage.fromURL(url);\n } catch (error) {\n throw new Error(`Failed to load mockup image: ${url}`, { cause: error });\n }\n const sourceWidth = image.width;\n const sourceHeight = image.height;\n const placement = computeCoverPlacement(sourceWidth, sourceHeight, width, height);\n image.set({\n originX: 'left',\n originY: 'top',\n left: placement.left,\n top: placement.top,\n scaleX: placement.width / sourceWidth,\n scaleY: placement.height / sourceHeight,\n selectable: false,\n evented: false,\n });\n return image;\n}\n\nasync function displacedDesignUrl(\n designCanvas: StaticCanvas,\n displacement: MockupDisplacement,\n width: number,\n height: number,\n): Promise<string> {\n const mapCanvas = new StaticCanvas(undefined, { width, height });\n const warpedCanvas = new StaticCanvas(undefined, { width, height });\n try {\n mapCanvas.add(await coverImage(displacement.image, width, height));\n mapCanvas.renderAll();\n const pixels = displaceRgba(\n designCanvas.getContext().getImageData(0, 0, width, height).data,\n mapCanvas.getContext().getImageData(0, 0, width, height).data,\n width,\n height,\n displacement,\n );\n const imageData = warpedCanvas.getContext().createImageData(width, height);\n imageData.data.set(pixels);\n warpedCanvas.getContext().putImageData(imageData, 0, 0);\n return warpedCanvas.toDataURL({ format: 'png', multiplier: 1 });\n } catch (error) {\n throw new Error('Failed to apply mockup displacement map', { cause: error });\n } finally {\n mapCanvas.dispose();\n warpedCanvas.dispose();\n }\n}\n\n/** Render browser-authored EditorState without a DOM or live editor instance. */\nexport async function renderEditorState(\n state: EditorState,\n options: NodeRenderOptions = {},\n): Promise<NodeRenderResult> {\n validateState(state);\n const resolved = validateOptions(options);\n assertImageUrlsAllowed(state, resolved.allowImageUrl);\n const canvas = await createStateCanvas(state);\n try {\n return encodeCanvas(canvas, resolved);\n } finally {\n canvas.dispose();\n }\n}\n\n/** Render a saved product mockup with the transparent design composited above it. */\nexport async function renderMockupState(\n state: EditorState,\n options: NodeRenderOptions = {},\n): Promise<NodeRenderResult> {\n validateState(state);\n const resolved = validateOptions(options);\n assertImageUrlsAllowed(state, resolved.allowImageUrl);\n if (resolved.format === 'svg') {\n throw new Error('Mockup rendering supports PNG, JPEG, and WebP output');\n }\n const mockup: MockupConfig | null | undefined = state.mockup;\n if (!mockup?.image) throw new Error('No mockup is configured');\n\n const designCanvas = await createStateCanvas(state, true);\n const output = new StaticCanvas(undefined, {\n width: state.canvas.width,\n height: state.canvas.height,\n preserveObjectStacking: true,\n });\n try {\n output.add(await coverImage(mockup.image, state.canvas.width, state.canvas.height));\n\n const designUrl = mockup.displacement\n ? await displacedDesignUrl(\n designCanvas,\n mockup.displacement,\n state.canvas.width,\n state.canvas.height,\n )\n : designCanvas.toDataURL({ format: 'png', multiplier: 1 });\n const design = await FabricImage.fromURL(designUrl);\n design.set({\n originX: 'left',\n originY: 'top',\n left: 0,\n top: 0,\n opacity: clampOpacity(mockup.designOpacity),\n globalCompositeOperation: compositeOperation(mockup.designBlendMode),\n selectable: false,\n evented: false,\n });\n if (mockup.printArea && mockup.clipToPrintArea !== false) {\n const clip = computePrintAreaClip(\n mockup.printArea,\n 1,\n 1,\n state.canvas.width,\n state.canvas.height,\n );\n design.clipPath = new Rect({\n originX: 'left',\n originY: 'top',\n left: clip.left,\n top: clip.top,\n width: clip.width,\n height: clip.height,\n absolutePositioned: true,\n });\n }\n output.add(design);\n\n if (mockup.overlay) {\n const overlay = await coverImage(\n mockup.overlay.image,\n state.canvas.width,\n state.canvas.height,\n );\n overlay.set({\n opacity: clampOpacity(mockup.overlay.opacity),\n globalCompositeOperation: compositeOperation(mockup.overlay.blendMode ?? 'multiply'),\n });\n output.add(overlay);\n }\n output.renderAll();\n return encodeCanvas(output, resolved);\n } finally {\n designCanvas.dispose();\n output.dispose();\n }\n}\n\nasync function renderBatch(\n states: EditorState[],\n options: NodeRenderOptions & { concurrency?: number },\n renderer: (state: EditorState, options: NodeRenderOptions) => Promise<NodeRenderResult>,\n): Promise<NodeRenderResult[]> {\n const concurrency = Math.max(1, Math.floor(options.concurrency ?? 2));\n const results = new Array<NodeRenderResult>(states.length);\n let nextIndex = 0;\n await Promise.all(\n Array.from({ length: Math.min(concurrency, states.length) }, async () => {\n while (nextIndex < states.length) {\n const index = nextIndex++;\n results[index] = await renderer(states[index], options);\n }\n }),\n );\n return results;\n}\n\n/** Render multiple states with bounded concurrency for fulfillment jobs. */\nexport async function renderEditorStateBatch(\n states: EditorState[],\n options: NodeRenderOptions & { concurrency?: number } = {},\n): Promise<NodeRenderResult[]> {\n return renderBatch(states, options, renderEditorState);\n}\n\n/** Render multiple mockup states with bounded concurrency for fulfillment jobs. */\nexport async function renderMockupStateBatch(\n states: EditorState[],\n options: NodeRenderOptions & { concurrency?: number } = {},\n): Promise<NodeRenderResult[]> {\n return renderBatch(states, options, renderMockupState);\n}\n"],"mappings":"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","names":["response","renderEditorState"]}
|
package/dist/node.mjs
CHANGED
|
@@ -19,8 +19,35 @@ interface LayerMeta {
|
|
|
19
19
|
height: number;
|
|
20
20
|
revision: number;
|
|
21
21
|
};
|
|
22
|
+
/** Preset silhouette or texture the layer is clipped to. */
|
|
23
|
+
maskPreset?: MaskPresetId;
|
|
24
|
+
/** Baseline curve applied to a text layer. */
|
|
25
|
+
curve?: TextCurveConfig;
|
|
26
|
+
/** Text box width authored before a curve widened it, in px. */
|
|
27
|
+
curveWidth?: number;
|
|
28
|
+
/** Layer resizes uniformly: single-axis handles are hidden. */
|
|
29
|
+
lockAspect?: boolean;
|
|
22
30
|
[key: string]: unknown;
|
|
23
31
|
}
|
|
32
|
+
interface TextCurveConfig {
|
|
33
|
+
/**
|
|
34
|
+
* Baseline bend, −100…100. Positive arcs the run upward (a rainbow),
|
|
35
|
+
* negative into a valley; ±100 closes it into a full ring. 0 is straight.
|
|
36
|
+
*/
|
|
37
|
+
arc: number;
|
|
38
|
+
/** Sine-wave amplitude, 0…100, as a share of the font size. Ignored when arced. */
|
|
39
|
+
wave: number;
|
|
40
|
+
}
|
|
41
|
+
type ShapeMaskPresetId = 'circle' | 'square' | 'triangle' | 'star' | 'heart' | 'octagram' | 'arch' | 'zigzag';
|
|
42
|
+
type TextureMaskPresetId = 'vignette' | 'halftone' | 'spray' | 'grunge' | 'torn' | 'band';
|
|
43
|
+
type MaskPresetId = ShapeMaskPresetId | TextureMaskPresetId;
|
|
44
|
+
interface LayerShadowConfig {
|
|
45
|
+
enabled: boolean;
|
|
46
|
+
color: string;
|
|
47
|
+
blur: number;
|
|
48
|
+
offsetX: number;
|
|
49
|
+
offsetY: number;
|
|
50
|
+
}
|
|
24
51
|
interface SerializedLayer extends LayerData {
|
|
25
52
|
fabricObject: Record<string, unknown>;
|
|
26
53
|
}
|
|
@@ -458,4 +485,4 @@ interface EditorEvents {
|
|
|
458
485
|
};
|
|
459
486
|
}
|
|
460
487
|
|
|
461
|
-
export { type
|
|
488
|
+
export { type TemplateParameter as $, type MockupOverlay as A, type BackgroundImageOptions as B, type CanvasSizePreset as C, DEFAULT_PATTERN_CONFIG as D, type EditorConfig as E, type FileAdapter as F, type MockupPrintArea as G, type PatternLocks as H, type ImageAdjustments as I, type PatternSourceResolver as J, type PatternState as K, type LayerData as L, type MaskBrushOptions as M, type NormalizedLayerPosition as N, type PositioningAdapter as O, type PatternConfig as P, type PrintifyPositioning as Q, type ProjectPage as R, type ProjectState as S, type ResizeOptions as T, type SemanticExportOptions as U, type SerializedBackgroundImageOptions as V, type SerializedLayer as W, type ShapeMaskPresetId as X, type ShapePlugin as Y, type SvgExportOptions as Z, type TemplateDefinition as _, type DpiIssue as a, type TextCurveConfig as a0, type TextureMaskPresetId as a1, type TileMode as a2, type Unit as a3, type EditorEvents as b, type EditorState as c, type ExportFormat as d, type FontDefinition as e, type ImageAttribution as f, type ImageProvider as g, type ImageProviderResult as h, type ImageSearchOptions as i, type ImageSearchResult as j, type LayerMeta as k, type LayerShadowConfig as l, type LayerType as m, type LicenseConfig as n, type LicensePayload as o, type LicenseStatus as p, type MaskPoint as q, type MaskPresetId as r, type MaskRefinementPrompt as s, type MaskRefinementProvider as t, type MaskRefinementRequest as u, type MaskRefinementResult as v, type MockupBlendMode as w, type MockupConfig as x, type MockupDisplacement as y, type MockupDisplacementChannel as z };
|
|
@@ -19,8 +19,35 @@ interface LayerMeta {
|
|
|
19
19
|
height: number;
|
|
20
20
|
revision: number;
|
|
21
21
|
};
|
|
22
|
+
/** Preset silhouette or texture the layer is clipped to. */
|
|
23
|
+
maskPreset?: MaskPresetId;
|
|
24
|
+
/** Baseline curve applied to a text layer. */
|
|
25
|
+
curve?: TextCurveConfig;
|
|
26
|
+
/** Text box width authored before a curve widened it, in px. */
|
|
27
|
+
curveWidth?: number;
|
|
28
|
+
/** Layer resizes uniformly: single-axis handles are hidden. */
|
|
29
|
+
lockAspect?: boolean;
|
|
22
30
|
[key: string]: unknown;
|
|
23
31
|
}
|
|
32
|
+
interface TextCurveConfig {
|
|
33
|
+
/**
|
|
34
|
+
* Baseline bend, −100…100. Positive arcs the run upward (a rainbow),
|
|
35
|
+
* negative into a valley; ±100 closes it into a full ring. 0 is straight.
|
|
36
|
+
*/
|
|
37
|
+
arc: number;
|
|
38
|
+
/** Sine-wave amplitude, 0…100, as a share of the font size. Ignored when arced. */
|
|
39
|
+
wave: number;
|
|
40
|
+
}
|
|
41
|
+
type ShapeMaskPresetId = 'circle' | 'square' | 'triangle' | 'star' | 'heart' | 'octagram' | 'arch' | 'zigzag';
|
|
42
|
+
type TextureMaskPresetId = 'vignette' | 'halftone' | 'spray' | 'grunge' | 'torn' | 'band';
|
|
43
|
+
type MaskPresetId = ShapeMaskPresetId | TextureMaskPresetId;
|
|
44
|
+
interface LayerShadowConfig {
|
|
45
|
+
enabled: boolean;
|
|
46
|
+
color: string;
|
|
47
|
+
blur: number;
|
|
48
|
+
offsetX: number;
|
|
49
|
+
offsetY: number;
|
|
50
|
+
}
|
|
24
51
|
interface SerializedLayer extends LayerData {
|
|
25
52
|
fabricObject: Record<string, unknown>;
|
|
26
53
|
}
|
|
@@ -458,4 +485,4 @@ interface EditorEvents {
|
|
|
458
485
|
};
|
|
459
486
|
}
|
|
460
487
|
|
|
461
|
-
export { type
|
|
488
|
+
export { type TemplateParameter as $, type MockupOverlay as A, type BackgroundImageOptions as B, type CanvasSizePreset as C, DEFAULT_PATTERN_CONFIG as D, type EditorConfig as E, type FileAdapter as F, type MockupPrintArea as G, type PatternLocks as H, type ImageAdjustments as I, type PatternSourceResolver as J, type PatternState as K, type LayerData as L, type MaskBrushOptions as M, type NormalizedLayerPosition as N, type PositioningAdapter as O, type PatternConfig as P, type PrintifyPositioning as Q, type ProjectPage as R, type ProjectState as S, type ResizeOptions as T, type SemanticExportOptions as U, type SerializedBackgroundImageOptions as V, type SerializedLayer as W, type ShapeMaskPresetId as X, type ShapePlugin as Y, type SvgExportOptions as Z, type TemplateDefinition as _, type DpiIssue as a, type TextCurveConfig as a0, type TextureMaskPresetId as a1, type TileMode as a2, type Unit as a3, type EditorEvents as b, type EditorState as c, type ExportFormat as d, type FontDefinition as e, type ImageAttribution as f, type ImageProvider as g, type ImageProviderResult as h, type ImageSearchOptions as i, type ImageSearchResult as j, type LayerMeta as k, type LayerShadowConfig as l, type LayerType as m, type LicenseConfig as n, type LicensePayload as o, type LicenseStatus as p, type MaskPoint as q, type MaskPresetId as r, type MaskRefinementPrompt as s, type MaskRefinementProvider as t, type MaskRefinementRequest as u, type MaskRefinementResult as v, type MockupBlendMode as w, type MockupConfig as x, type MockupDisplacement as y, type MockupDisplacementChannel as z };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@overtone-art/canvas-editor-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Abstract pluggable canvas editor built on Fabric.js",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -64,6 +64,7 @@
|
|
|
64
64
|
}
|
|
65
65
|
},
|
|
66
66
|
"devDependencies": {
|
|
67
|
+
"@types/node": "^22.12.0",
|
|
67
68
|
"@types/fontkit": "^2.0.9",
|
|
68
69
|
"@types/opentype.js": "^1.3.10",
|
|
69
70
|
"@types/pdfkit": "^0.17.6",
|
|
@@ -83,10 +84,11 @@
|
|
|
83
84
|
"scripts": {
|
|
84
85
|
"build": "tsup",
|
|
85
86
|
"dev": "tsup --watch",
|
|
86
|
-
"lint": "eslint src/",
|
|
87
|
-
"type-check": "tsc --noEmit",
|
|
87
|
+
"lint": "eslint src/ acceptance/ vitest.config.ts vitest.acceptance.config.ts",
|
|
88
|
+
"type-check": "tsc --noEmit && tsc --noEmit -p tsconfig.acceptance.json",
|
|
88
89
|
"test": "vitest run",
|
|
89
90
|
"test:coverage": "vitest run --coverage",
|
|
90
|
-
"test:watch": "vitest"
|
|
91
|
+
"test:watch": "vitest",
|
|
92
|
+
"acceptance:print": "vitest run --config vitest.acceptance.config.ts acceptance/generate-print.test.ts"
|
|
91
93
|
}
|
|
92
94
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/displacement.ts","../src/export.ts"],"sourcesContent":["import type { MockupDisplacement, MockupDisplacementChannel } from './types';\n\nconst CHANNEL_INDEX: Record<MockupDisplacementChannel, number> = {\n red: 0,\n green: 1,\n blue: 2,\n alpha: 3,\n};\n\nfunction finiteScale(value: number | undefined, fallback: number, label: string): number {\n const resolved = value ?? fallback;\n if (!Number.isFinite(resolved)) throw new Error(`${label} must be finite`);\n return resolved;\n}\n\nfunction sample(\n source: Uint8ClampedArray,\n width: number,\n height: number,\n x: number,\n y: number,\n channel: number,\n): number {\n const clampedX = Math.max(0, Math.min(width - 1, x));\n const clampedY = Math.max(0, Math.min(height - 1, y));\n const x0 = Math.floor(clampedX);\n const y0 = Math.floor(clampedY);\n const x1 = Math.min(width - 1, x0 + 1);\n const y1 = Math.min(height - 1, y0 + 1);\n const tx = clampedX - x0;\n const ty = clampedY - y0;\n const top =\n source[(y0 * width + x0) * 4 + channel] * (1 - tx) +\n source[(y0 * width + x1) * 4 + channel] * tx;\n const bottom =\n source[(y1 * width + x0) * 4 + channel] * (1 - tx) +\n source[(y1 * width + x1) * 4 + channel] * tx;\n return top * (1 - ty) + bottom * ty;\n}\n\n/**\n * Warp RGBA pixels with an equally sized channel map. A channel value of 128\n * is neutral; 0 and 255 move by the configured negative/positive maximum.\n */\nexport function displaceRgba(\n source: Uint8ClampedArray,\n map: Uint8ClampedArray,\n width: number,\n height: number,\n options: Omit<MockupDisplacement, 'image'>,\n): Uint8ClampedArray {\n if (!Number.isInteger(width) || !Number.isInteger(height) || width <= 0 || height <= 0) {\n throw new Error('Displacement dimensions must be positive integers');\n }\n const expectedLength = width * height * 4;\n if (source.length !== expectedLength || map.length !== expectedLength) {\n throw new Error('Displacement source and map must match the requested dimensions');\n }\n\n const scaleX = finiteScale(options.scaleX, 10, 'Displacement scaleX');\n const scaleY = finiteScale(options.scaleY, 10, 'Displacement scaleY');\n const channelX = CHANNEL_INDEX[options.channelX ?? 'red'];\n const channelY = CHANNEL_INDEX[options.channelY ?? 'green'];\n const output = new Uint8ClampedArray(expectedLength);\n\n for (let y = 0; y < height; y += 1) {\n for (let x = 0; x < width; x += 1) {\n const offset = (y * width + x) * 4;\n const sourceX = x + ((map[offset + channelX] - 128) / 127) * scaleX;\n const sourceY = y + ((map[offset + channelY] - 128) / 127) * scaleY;\n for (let channel = 0; channel < 4; channel += 1) {\n output[offset + channel] = Math.round(\n sample(source, width, height, sourceX, sourceY, channel),\n );\n }\n }\n }\n return output;\n}\n","import { StaticCanvas } from 'fabric';\nimport type { Canvas, FabricObject, ImageFormat } from 'fabric';\nimport type { MockupConfig, MockupPrintArea } from './types';\nimport { displaceRgba } from './displacement';\n\nexport interface PngExportOptions {\n multiplier?: number;\n format?: ImageFormat;\n quality?: number;\n}\n\nexport interface CoverPlacement {\n left: number;\n top: number;\n width: number;\n height: number;\n}\n\nexport function computePrintAreaClip(\n area: MockupPrintArea,\n scaleX: number,\n scaleY: number,\n targetWidth: number,\n targetHeight: number,\n): MockupPrintArea {\n const left = Math.max(0, Math.min(targetWidth, area.left * scaleX));\n const top = Math.max(0, Math.min(targetHeight, area.top * scaleY));\n const right = Math.max(left, Math.min(targetWidth, (area.left + area.width) * scaleX));\n const bottom = Math.max(top, Math.min(targetHeight, (area.top + area.height) * scaleY));\n return { left, top, width: right - left, height: bottom - top };\n}\n\n/** Object-fit: cover geometry, exported for deterministic preview/composite tests. */\nexport function computeCoverPlacement(\n sourceWidth: number,\n sourceHeight: number,\n targetWidth: number,\n targetHeight: number,\n): CoverPlacement {\n if (sourceWidth <= 0 || sourceHeight <= 0 || targetWidth <= 0 || targetHeight <= 0) {\n throw new Error('Cover dimensions must be positive');\n }\n const scale = Math.max(targetWidth / sourceWidth, targetHeight / sourceHeight);\n const width = sourceWidth * scale;\n const height = sourceHeight * scale;\n return {\n left: (targetWidth - width) / 2,\n top: (targetHeight - height) / 2,\n width,\n height,\n };\n}\n\nfunction canvasElementToBlob(\n output: HTMLCanvasElement,\n format: ImageFormat,\n quality: number,\n): Promise<Blob> {\n const mime = format === 'jpeg' ? 'image/jpeg' : `image/${format}`;\n return new Promise<Blob>((resolve, reject) => {\n output.toBlob(\n (blob) => (blob ? resolve(blob) : reject(new Error(`Failed to export ${format}`))),\n mime,\n quality,\n );\n });\n}\n\nexport async function exportPNG(canvas: Canvas, options: PngExportOptions = {}): Promise<Blob> {\n const { multiplier = 1, format = 'png' as ImageFormat, quality = 1 } = options;\n const output = canvas.toCanvasElement(multiplier);\n return canvasElementToBlob(output, format, quality);\n}\n\n/** Render cloned objects without mutating the live editor canvas. */\nexport async function exportIsolatedPNG(\n source: Canvas,\n objects: FabricObject[],\n options: PngExportOptions & {\n width?: number;\n height?: number;\n backgroundColor?: string;\n backgroundImage?: FabricObject | null;\n cloneObjects?: boolean;\n } = {},\n): Promise<Blob> {\n const element = source.lowerCanvasEl.ownerDocument.createElement('canvas');\n const canvas = new StaticCanvas(element, {\n width: options.width ?? source.getWidth(),\n height: options.height ?? source.getHeight(),\n backgroundColor: options.backgroundColor || undefined,\n });\n try {\n const clones =\n options.cloneObjects === false\n ? objects\n : await Promise.all(objects.map((object) => object.clone()));\n if (clones.length) canvas.add(...clones);\n if (options.backgroundImage) canvas.backgroundImage = await options.backgroundImage.clone();\n canvas.requestRenderAll();\n // Awaited, not returned: `finally` would otherwise dispose the canvas while\n // the export is still reading from it.\n return await exportPNG(canvas as unknown as Canvas, options);\n } finally {\n canvas.dispose();\n }\n}\n\n/** Rasterize the browser mockup preview together with the transparent design. */\nexport async function exportMockup(\n canvas: Canvas,\n mockup: MockupConfig,\n options: PngExportOptions = {},\n): Promise<Blob> {\n const { multiplier = 1, format = 'png' as ImageFormat, quality = 1 } = options;\n const design = canvas.toCanvasElement(multiplier);\n const output = design.ownerDocument.createElement('canvas');\n output.width = design.width;\n output.height = design.height;\n const context = output.getContext('2d');\n if (!context) throw new Error('2D canvas context is unavailable');\n\n const loadImage = (url: string) =>\n new Promise<HTMLImageElement>((resolve, reject) => {\n const element = new Image();\n element.crossOrigin = 'anonymous';\n element.onload = () => resolve(element);\n element.onerror = () => reject(new Error(`Failed to load mockup image: ${url}`));\n element.src = url;\n });\n const drawCover = (\n image: HTMLImageElement,\n targetContext: CanvasRenderingContext2D = context,\n ) => {\n const placement = computeCoverPlacement(\n image.naturalWidth || image.width,\n image.naturalHeight || image.height,\n output.width,\n output.height,\n );\n targetContext.drawImage(\n image,\n placement.left,\n placement.top,\n placement.width,\n placement.height,\n );\n };\n\n // Full-size scratch buffers, released explicitly in the finally below: a\n // detached canvas element can hold its backing store well past its last\n // reference, and a 4K mockup allocates three of them per export.\n const scratch: HTMLCanvasElement[] = [design];\n try {\n drawCover(await loadImage(mockup.image));\n let compositedDesign: CanvasImageSource = design;\n if (mockup.displacement) {\n const sourceContext = design.getContext('2d');\n if (!sourceContext) throw new Error('2D design context is unavailable');\n const mapCanvas = design.ownerDocument.createElement('canvas');\n scratch.push(mapCanvas);\n mapCanvas.width = design.width;\n mapCanvas.height = design.height;\n const mapContext = mapCanvas.getContext('2d');\n if (!mapContext) throw new Error('2D displacement-map context is unavailable');\n drawCover(await loadImage(mockup.displacement.image), mapContext);\n\n const warped = design.ownerDocument.createElement('canvas');\n scratch.push(warped);\n warped.width = design.width;\n warped.height = design.height;\n const warpedContext = warped.getContext('2d');\n if (!warpedContext) throw new Error('2D displaced-design context is unavailable');\n let sourcePixels: Uint8ClampedArray;\n let mapPixels: Uint8ClampedArray;\n try {\n sourcePixels = sourceContext.getImageData(0, 0, design.width, design.height).data;\n mapPixels = mapContext.getImageData(0, 0, design.width, design.height).data;\n } catch (error) {\n throw new Error('Failed to apply mockup displacement map; verify image CORS access', {\n cause: error,\n });\n }\n const pixels = displaceRgba(sourcePixels, mapPixels, design.width, design.height, {\n ...mockup.displacement,\n scaleX: (mockup.displacement.scaleX ?? 10) * multiplier,\n scaleY: (mockup.displacement.scaleY ?? 10) * multiplier,\n });\n const imageData = warpedContext.createImageData(design.width, design.height);\n imageData.data.set(pixels);\n warpedContext.putImageData(imageData, 0, 0);\n compositedDesign = warped;\n }\n context.save();\n if (mockup.printArea && mockup.clipToPrintArea !== false) {\n const clip = computePrintAreaClip(\n mockup.printArea,\n output.width / canvas.getWidth(),\n output.height / canvas.getHeight(),\n output.width,\n output.height,\n );\n context.beginPath();\n context.rect(clip.left, clip.top, clip.width, clip.height);\n context.clip();\n }\n context.globalAlpha = Math.max(0, Math.min(1, mockup.designOpacity ?? 1));\n context.globalCompositeOperation =\n !mockup.designBlendMode || mockup.designBlendMode === 'normal'\n ? 'source-over'\n : mockup.designBlendMode;\n context.drawImage(compositedDesign, 0, 0);\n context.restore();\n\n if (mockup.overlay) {\n context.save();\n context.globalAlpha = Math.max(0, Math.min(1, mockup.overlay.opacity ?? 1));\n context.globalCompositeOperation =\n mockup.overlay.blendMode === 'normal'\n ? 'source-over'\n : (mockup.overlay.blendMode ?? 'multiply');\n drawCover(await loadImage(mockup.overlay.image));\n context.restore();\n }\n return await canvasElementToBlob(output, format, quality);\n } finally {\n for (const element of scratch) {\n element.width = 0;\n element.height = 0;\n }\n }\n}\n\nexport function exportSVG(canvas: Canvas): string {\n return canvas.toSVG();\n}\n\nexport function exportDataURL(canvas: Canvas, format: ImageFormat = 'png', multiplier = 1): string {\n return canvas.toDataURL({ format, multiplier });\n}\n"],"mappings":"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","names":[]}
|