@su-engineering/heic 0.1.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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/bytes.ts","../src/errors.ts","../src/render/canvas.ts","../src/decoders/native.ts","../src/parser/reader.ts","../src/parser/hvcc.ts","../src/parser/boxes.ts","../src/parser/meta.ts","../src/parser/grid.ts","../src/plan.ts","../src/decoders/webcodecs.ts","../src/parser/detect.ts","../src/render/transform.ts","../src/probe.ts"],"sourcesContent":["import { toHeicBlob } from './bytes.ts';\nimport { HeicAbortError, HeicUnsupportedError } from './errors.ts';\nimport { decodeNative } from './decoders/native.ts';\nimport { decodeWithWebCodecs, isWebCodecsAvailable } from './decoders/webcodecs.ts';\nimport { DETECTION_PREFIX_BYTES, detectFromBuffer } from './parser/detect.ts';\nimport { planDecode, type ImagePlan } from './plan.ts';\nimport { createCanvas, throwIfAborted } from './render/canvas.ts';\nimport { applyTransforms, summarizeTransforms } from './render/transform.ts';\nimport type {\n DecodeOptions,\n DecodedImage,\n DecoderAdapter,\n Strategy,\n TransformsApplied,\n} from './types.ts';\n\nexport {\n HeicAbortError,\n HeicDecodeError,\n HeicError,\n HeicParseError,\n HeicUnsupportedError,\n} from './errors.ts';\nexport type { HeicErrorContext } from './errors.ts';\nexport { parseHeif, propertiesForItem, findProperty, readItemData } from './parser/meta.ts';\nexport type {\n HeifFile,\n ItemInfo,\n ItemLocation,\n ItemProperty,\n ItemProperties,\n ItemReferences,\n} from './parser/meta.ts';\nexport { readGrid, parseGridPayload } from './parser/grid.ts';\nexport type { GridDescriptor } from './parser/grid.ts';\nexport {\n hvccToAnnexBPrologue,\n hvccToCodecString,\n lengthPrefixedToAnnexB,\n parseHvcC,\n} from './parser/hvcc.ts';\nexport type { HvcC } from './parser/hvcc.ts';\nexport { planDecode } from './plan.ts';\nexport type { ImagePlan, PlannedTile, TileGroup, TransformOp } from './plan.ts';\nexport { probeSupport } from './probe.ts';\nexport type {\n AdapterRequest,\n AdapterResult,\n DecodeOptions,\n DecodedImage,\n DecoderAdapter,\n HeicWarning,\n OutputColorSpace,\n SourceColor,\n Strategy,\n SupportReport,\n TransformsApplied,\n} from './types.ts';\n\nexport type BinaryInput = Blob | ArrayBuffer | Uint8Array;\n\nexport interface IsHeicResult {\n isHeic: boolean;\n /** ftyp major brand, when the file had one. */\n brand?: string | undefined;\n /** item_type of the primary item ('hvc1', 'grid', 'av01', ...). */\n primaryItemType?: string | undefined;\n /** What the primary item is coded with. 'av1' means this is an AVIF. */\n coding?: 'hevc' | 'av1' | 'unknown' | undefined;\n}\n\n/**\n * Identifies a HEIC file from its contents.\n *\n * Reads the `ftyp` brands and the primary item type — never the filename or the\n * MIME type the browser guessed, both of which are routinely wrong for photos\n * copied off a phone.\n *\n * Given a Blob, only the first 64 KB are read, because this gets called\n * speculatively on every file a user drops. AVIF also uses the `mif1` brand, so\n * the result is discriminated rather than boolean: `{ isHeic: false, coding:\n * 'av1' }` tells a caller to route the file to an AVIF decoder instead of\n * treating it as garbage.\n */\nexport async function isHeic(input: BinaryInput): Promise<IsHeicResult> {\n const prefix = await readPrefix(input, DETECTION_PREFIX_BYTES);\n const detection = detectFromBuffer(prefix);\n const result: IsHeicResult = { isHeic: detection.isHeic };\n if (detection.brand !== undefined) result.brand = detection.brand;\n if (detection.primaryItemType !== undefined) result.primaryItemType = detection.primaryItemType;\n if (detection.coding !== undefined) result.coding = detection.coding;\n return result;\n}\n\n/**\n * Decodes a HEIC image to an `ImageBitmap`.\n *\n * The container is parsed first regardless of which strategy ends up decoding —\n * parsing costs microseconds and every strategy needs its output. The cascade\n * then picks a *decode* path:\n *\n * 1. `createImageBitmap` — free, works on Safari and some Chrome builds\n * 2. WebCodecs `VideoDecoder` — ~15 KB of JS, hardware decode, most Chromium\n * 3. a wasm adapter — ~1.2 MB, only if the caller supplied one\n *\n * Step 3 never happens behind the caller's back: without `wasmLoader` or a\n * registered adapter, a file that needs wasm throws `HeicUnsupportedError`\n * naming what was missing, rather than silently fetching a megabyte.\n */\nexport async function decodeHeic(\n input: BinaryInput,\n options: DecodeOptions = {},\n): Promise<DecodedImage> {\n const {\n strategy = 'auto',\n colorSpace = 'srgb',\n maxDimension,\n signal,\n wasmLoader,\n } = options;\n\n throwIfAborted(signal);\n\n // Read the whole buffer once and reuse it for both parse and decode.\n const bytes = await readAll(input);\n throwIfAborted(signal);\n\n const plan = planDecode(bytes);\n throwIfAborted(signal);\n\n const attempts: { strategy: string; reason: string }[] = [];\n const wants = (candidate: Strategy): boolean => strategy === 'auto' || strategy === candidate;\n\n // --- 1. native -----------------------------------------------------------\n if (wants('native')) {\n const blob = input instanceof Blob ? input : toHeicBlob(bytes);\n const outcome = await decodeNative(blob, plan, signal);\n if (outcome.status === 'ok') {\n // The native decoder already applied irot/imir/clap. Applying them again\n // would double-rotate, so the transform stage is skipped entirely.\n const finalBitmap = await resizeBitmap(outcome.bitmap, maxDimension, signal);\n return describe(plan, finalBitmap, 'native', summarizeTransforms(plan.transforms));\n }\n attempts.push({ strategy: 'native', reason: outcome.reason });\n }\n\n // --- 2. WebCodecs --------------------------------------------------------\n if (wants('webcodecs')) {\n if (!isWebCodecsAvailable()) {\n attempts.push({ strategy: 'webcodecs', reason: 'VideoDecoder is not available' });\n } else {\n try {\n const composited = await decodeWithWebCodecs(plan, colorSpace, signal);\n const { canvas, applied } = applyTransforms(composited, plan.transforms, colorSpace);\n const bitmap = await canvasToBitmap(canvas, maxDimension, signal);\n return describe(plan, bitmap, 'webcodecs', applied);\n } catch (error) {\n if (error instanceof HeicAbortError) throw error;\n if (strategy === 'webcodecs') throw error;\n attempts.push({ strategy: 'webcodecs', reason: describeError(error) });\n }\n }\n }\n\n // --- 3. wasm -------------------------------------------------------------\n if (wants('wasm')) {\n const adapter = await resolveAdapter(wasmLoader);\n if (!adapter) {\n attempts.push({\n strategy: 'wasm',\n reason: 'no adapter: pass options.wasmLoader or call registerDecoderAdapter()',\n });\n } else {\n try {\n const result = await adapter.decode({ data: bytes, colorSpace, signal });\n // Contract: an adapter that applies transforms itself gets ours skipped,\n // or the image comes out rotated twice relative to the WebCodecs path.\n const applied = summarizeTransforms(plan.transforms);\n let bitmap: ImageBitmap;\n if (result.image instanceof ImageBitmap) {\n const source = adapter.appliesTransforms\n ? result.image\n : await transformBitmap(result.image, plan, colorSpace);\n bitmap = await resizeBitmap(source, maxDimension, signal);\n } else {\n const canvas = adapter.appliesTransforms\n ? result.image\n : applyTransforms(result.image, plan.transforms, colorSpace).canvas;\n bitmap = await canvasToBitmap(canvas, maxDimension, signal);\n }\n return describe(plan, bitmap, 'wasm', applied);\n } catch (error) {\n if (error instanceof HeicAbortError) throw error;\n if (strategy === 'wasm') throw error;\n attempts.push({ strategy: 'wasm', reason: describeError(error) });\n }\n }\n }\n\n throw new HeicUnsupportedError('Could not decode this HEIC', attempts, {\n brand: plan.file.majorBrand,\n itemType: plan.file.items.get(plan.primaryItemId)?.itemType,\n itemId: plan.primaryItemId,\n });\n}\n\n// ---------------------------------------------------------------------------\n// Adapter registration\n// ---------------------------------------------------------------------------\n\nlet registeredAdapter: DecoderAdapter | undefined;\n\n/**\n * Registers a wasm (or other) fallback adapter for every subsequent decode.\n *\n * An alternative to passing `wasmLoader` on each call. Either way the caller\n * chooses when the megabyte is paid for; nothing is fetched implicitly.\n */\nexport function registerDecoderAdapter(adapter: DecoderAdapter | undefined): void {\n registeredAdapter = adapter;\n}\n\nexport function getRegisteredAdapter(): DecoderAdapter | undefined {\n return registeredAdapter;\n}\n\nasync function resolveAdapter(\n loader?: () => Promise<DecoderAdapter>,\n): Promise<DecoderAdapter | undefined> {\n if (registeredAdapter) return registeredAdapter;\n if (!loader) return undefined;\n return loader();\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nasync function readAll(input: BinaryInput): Promise<Uint8Array> {\n if (input instanceof Uint8Array) return input;\n if (input instanceof ArrayBuffer) return new Uint8Array(input);\n return new Uint8Array(await input.arrayBuffer());\n}\n\nasync function readPrefix(input: BinaryInput, byteCount: number): Promise<Uint8Array> {\n if (input instanceof Blob) {\n // The reason isHeic takes a Blob at all: slicing avoids pulling a 5 MB photo\n // into memory to read a 24-byte header.\n return new Uint8Array(await input.slice(0, byteCount).arrayBuffer());\n }\n const bytes = await readAll(input);\n return bytes.subarray(0, byteCount);\n}\n\n/** Scale factor that fits the longest side within `maxDimension`. Never upscales. */\nfunction scaleFor(width: number, height: number, maxDimension?: number): number {\n if (!maxDimension || maxDimension <= 0) return 1;\n const longest = Math.max(width, height);\n return longest <= maxDimension ? 1 : maxDimension / longest;\n}\n\n/**\n * Turns the composited canvas into the returned bitmap, releasing the canvas\n * immediately.\n *\n * This is where `maxDimension` earns its place: a 48 MP photo is a ~190 MB\n * canvas, and a caller building a 512 px avatar should never have to hold that.\n * Only the decoder can free it this early.\n */\nasync function canvasToBitmap(\n canvas: OffscreenCanvas,\n maxDimension?: number,\n signal?: AbortSignal,\n): Promise<ImageBitmap> {\n throwIfAborted(signal);\n const scale = scaleFor(canvas.width, canvas.height, maxDimension);\n\n if (scale === 1) {\n // Zero-copy: hands the backing store to the bitmap and empties the canvas.\n return canvas.transferToImageBitmap();\n }\n\n const resizeWidth = Math.max(1, Math.round(canvas.width * scale));\n const resizeHeight = Math.max(1, Math.round(canvas.height * scale));\n try {\n return await createImageBitmap(canvas, {\n resizeWidth,\n resizeHeight,\n resizeQuality: 'high',\n });\n } finally {\n canvas.width = 0;\n canvas.height = 0;\n }\n}\n\nasync function resizeBitmap(\n bitmap: ImageBitmap,\n maxDimension?: number,\n signal?: AbortSignal,\n): Promise<ImageBitmap> {\n throwIfAborted(signal);\n const scale = scaleFor(bitmap.width, bitmap.height, maxDimension);\n if (scale === 1) return bitmap;\n\n const resized = await createImageBitmap(bitmap, {\n resizeWidth: Math.max(1, Math.round(bitmap.width * scale)),\n resizeHeight: Math.max(1, Math.round(bitmap.height * scale)),\n resizeQuality: 'high',\n });\n bitmap.close();\n return resized;\n}\n\n/** Runs an untransformed adapter bitmap through the transform stage. */\nasync function transformBitmap(\n bitmap: ImageBitmap,\n plan: ImagePlan,\n colorSpace: PredefinedColorSpace,\n): Promise<ImageBitmap> {\n if (plan.transforms.length === 0) return bitmap;\n const canvas = createCanvas(bitmap.width, bitmap.height);\n const ctx = canvas.getContext('2d', { colorSpace, alpha: false });\n if (!ctx) return bitmap;\n ctx.drawImage(bitmap, 0, 0);\n bitmap.close();\n const { canvas: transformed } = applyTransforms(canvas, plan.transforms, colorSpace);\n return transformed.transferToImageBitmap();\n}\n\nfunction describe(\n plan: ImagePlan,\n image: ImageBitmap,\n strategy: Strategy,\n transformsApplied: TransformsApplied,\n): DecodedImage {\n return {\n image,\n width: image.width,\n height: image.height,\n sourceWidth: plan.displayWidth,\n sourceHeight: plan.displayHeight,\n strategy,\n bitDepth: plan.bitDepth,\n isGrid: plan.isGrid,\n tileCount: plan.tiles.length,\n sourceColor: plan.sourceColor,\n transformsApplied,\n warnings: plan.warnings,\n };\n}\n\nfunction describeError(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n","/**\n * TypeScript 5.7 models `Uint8Array` as generic over `ArrayBufferLike`, which\n * includes `SharedArrayBuffer`, and `BlobPart` accepts only `ArrayBuffer`-backed\n * views. Every buffer in this package comes from a `Blob`, an `ArrayBuffer`, or\n * an allocation of our own, so none is ever shared-backed.\n *\n * One narrow helper rather than a cast scattered at each call site.\n */\nexport function toBlobPart(bytes: Uint8Array): BlobPart {\n return bytes as unknown as BlobPart;\n}\n\n/** Wraps bytes in a Blob the browser will try to decode as HEIC. */\nexport function toHeicBlob(bytes: Uint8Array): Blob {\n return new Blob([toBlobPart(bytes)], { type: 'image/heic' });\n}\n","/**\n * Typed error hierarchy. The parser consumes hostile input and the decode path\n * fails in browser-specific ways, so every throw carries enough context to file\n * a useful bug report without the reporter having to reproduce it.\n */\n\nexport interface HeicErrorContext {\n /** ftyp major brand, when we got far enough to read it. */\n brand?: string | undefined;\n /** item_type of the item being worked on ('grid', 'hvc1', ...). */\n itemType?: string | undefined;\n /** Item ID being worked on. */\n itemId?: number | undefined;\n /** Strategy that produced the failure. */\n strategy?: string | undefined;\n /** Codec string handed to VideoDecoder. */\n codec?: string | undefined;\n /** Byte offset in the source buffer, for parse failures. */\n offset?: number | undefined;\n /** Four-character box type being read, for parse failures. */\n box?: string | undefined;\n}\n\nexport class HeicError extends Error {\n readonly context: HeicErrorContext;\n\n constructor(message: string, context: HeicErrorContext = {}, options?: ErrorOptions) {\n const detail = formatContext(context);\n super(detail ? `${message} (${detail})` : message, options);\n this.name = 'HeicError';\n this.context = context;\n }\n}\n\n/** The file is malformed, truncated, or uses a container feature we refuse to guess at. */\nexport class HeicParseError extends HeicError {\n constructor(message: string, context: HeicErrorContext = {}, options?: ErrorOptions) {\n super(message, context, options);\n this.name = 'HeicParseError';\n }\n}\n\n/** The file is well-formed but this environment cannot decode it. */\nexport class HeicUnsupportedError extends HeicError {\n /** Strategies that were tried, and why each one was unavailable or failed. */\n readonly attempts: ReadonlyArray<{ strategy: string; reason: string }>;\n\n constructor(\n message: string,\n attempts: ReadonlyArray<{ strategy: string; reason: string }> = [],\n context: HeicErrorContext = {},\n options?: ErrorOptions,\n ) {\n const summary = attempts.map((a) => `${a.strategy}: ${a.reason}`).join('; ');\n super(summary ? `${message} [${summary}]` : message, context, options);\n this.name = 'HeicUnsupportedError';\n this.attempts = attempts;\n }\n}\n\n/** A decoder was available and accepted the config, but decoding failed. */\nexport class HeicDecodeError extends HeicError {\n constructor(message: string, context: HeicErrorContext = {}, options?: ErrorOptions) {\n super(message, context, options);\n this.name = 'HeicDecodeError';\n }\n}\n\n/** The caller's AbortSignal fired. */\nexport class HeicAbortError extends HeicError {\n constructor(message = 'Decode aborted', context: HeicErrorContext = {}, options?: ErrorOptions) {\n super(message, context, options);\n this.name = 'HeicAbortError';\n }\n}\n\nfunction formatContext(context: HeicErrorContext): string {\n const parts: string[] = [];\n for (const [key, value] of Object.entries(context)) {\n if (value !== undefined) parts.push(`${key}=${value}`);\n }\n return parts.join(' ');\n}\n","import { HeicAbortError, HeicDecodeError } from '../errors.ts';\n\n/**\n * Creates an OffscreenCanvas.\n *\n * Deliberately never touches `document`: the whole package must run inside a Web\n * Worker, and a single `document.createElement('canvas')` anywhere would make\n * that impossible. This is the only place a canvas is created, so that guarantee\n * is enforceable by review.\n */\nexport function createCanvas(width: number, height: number): OffscreenCanvas {\n if (typeof OffscreenCanvas === 'undefined') {\n throw new HeicDecodeError(\n 'OffscreenCanvas is not available; this environment cannot composite',\n {},\n );\n }\n return new OffscreenCanvas(width, height);\n}\n\nexport function throwIfAborted(signal?: AbortSignal): void {\n if (signal?.aborted) throw new HeicAbortError();\n}\n","import { toHeicBlob } from '../bytes.ts';\nimport type { ImagePlan } from '../plan.ts';\nimport { throwIfAborted } from '../render/canvas.ts';\n\n/**\n * Why a native failure is remembered.\n *\n * On a browser with no HEIC support, `createImageBitmap` rejects for every file,\n * every time. Left alone, the cascade would build a Blob and lose a decode\n * attempt on each image — invisible for one avatar, real when a user drops\n * twenty photos at once. A browser does not gain or lose an image decoder\n * mid-session, so the first outright rejection is conclusive.\n *\n * Only an outright rejection sets this. A dimension mismatch does not: that\n * means the decoder returned *something* (usually the embedded thumbnail), which\n * is a property of the file rather than of the browser, and the next file may\n * well decode properly.\n */\nlet nativeDecoderRejects = false;\n\nexport type NativeOutcome =\n | { status: 'ok'; bitmap: ImageBitmap }\n /** The browser has no HEIC decoder at all. */\n | { status: 'unsupported'; reason: string }\n /** It decoded something, but not the primary image. */\n | { status: 'wrong-image'; reason: string };\n\n/**\n * Tries the browser's own image decoder.\n *\n * Free when it works (Safari on every platform, and some Chrome builds), so it\n * leads the cascade. The catch is that browsers fail in unhelpful ways here:\n * some return a bitmap of the embedded *thumbnail* rather than the primary\n * image, and some resolve with something unusable rather than rejecting.\n *\n * So the result is only accepted if its dimensions match the primary item's\n * `ispe` **in either orientation**. Native decoders apply `irot` themselves, so a\n * 90-degree-rotated image legitimately comes back with width and height swapped.\n * A thumbnail (typically 512 px or smaller) matches neither and is rejected,\n * falling through to WebCodecs.\n */\nexport async function decodeNative(\n blob: Blob,\n plan: ImagePlan,\n signal?: AbortSignal,\n): Promise<NativeOutcome> {\n if (typeof createImageBitmap === 'undefined') {\n return { status: 'unsupported', reason: 'createImageBitmap is not available' };\n }\n if (nativeDecoderRejects) {\n return { status: 'unsupported', reason: 'this browser has no HEIC image decoder' };\n }\n throwIfAborted(signal);\n\n let bitmap: ImageBitmap;\n try {\n bitmap = await createImageBitmap(blob);\n } catch {\n // The overwhelmingly common case on Chrome and Firefox: no HEIC decoder.\n nativeDecoderRejects = true;\n return { status: 'unsupported', reason: 'createImageBitmap rejected the file' };\n }\n\n throwIfAborted(signal);\n\n if (!dimensionsMatch(bitmap, plan)) {\n const got = `${bitmap.width}x${bitmap.height}`;\n // Very likely the embedded thumbnail. Close it and let WebCodecs try.\n bitmap.close();\n return {\n status: 'wrong-image',\n reason: `returned ${got}, expected ${plan.displayWidth}x${plan.displayHeight}`,\n };\n }\n\n return { status: 'ok', bitmap };\n}\n\nfunction dimensionsMatch(bitmap: ImageBitmap, plan: ImagePlan): boolean {\n const { displayWidth, displayHeight } = plan;\n const upright = bitmap.width === displayWidth && bitmap.height === displayHeight;\n const swapped = bitmap.width === displayHeight && bitmap.height === displayWidth;\n return upright || swapped;\n}\n\n/**\n * Whether this environment decodes HEIC natively.\n *\n * Probed with a minimal real HEIC rather than by sniffing the user agent. The\n * fixture below is a 2x2 single-item HEIC, small enough to inline.\n */\nexport async function probeNativeSupport(): Promise<boolean> {\n if (typeof createImageBitmap === 'undefined') return false;\n try {\n const bytes = decodeBase64(TINY_HEIC_BASE64);\n const bitmap = await createImageBitmap(toHeicBlob(bytes));\n const ok = bitmap.width === TINY_HEIC_WIDTH && bitmap.height === TINY_HEIC_HEIGHT;\n bitmap.close();\n return ok;\n } catch {\n return false;\n }\n}\n\nfunction decodeBase64(input: string): Uint8Array {\n const binary = atob(input);\n const out = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) out[i] = binary.charCodeAt(i);\n return out;\n}\n\n/**\n * A 2x2 single-item HEIC, produced by libheif's `heif-enc`. 471 bytes.\n *\n * Inlined so that probing native support costs no network request and no\n * fixture plumbing. Regenerate with:\n * magick -size 2x2 xc:'rgb(200,60,40)' tiny.png && heif-enc -q 90 -o tiny.heic tiny.png\n */\nexport const TINY_HEIC_WIDTH = 2;\nexport const TINY_HEIC_HEIGHT = 2;\nexport const TINY_HEIC_BASE64 =\n 'AAAAHGZ0eXBoZWljAAAAAG1pZjFoZWljbWlhZgAAAXxtZXRhAAAAAAAAACFoZGxyAAAAAAAAAABwaWN0AAAAA' +\n 'AAAAAAAAAAAAAAAACJpbG9jAAAAAERAAAEAAQAAAAABoAABAAAAAAAAADcAAAAjaWluZgAAAAAAAQAAABVpbm' +\n 'ZlAgAAAAABAABodmMxAAAAAA5waXRtAAAAAAABAAAA/GlwcnAAAADcaXBjbwAAAHVodmNDAQNwAAAAAAAAAAA' +\n 'AHvAA/P34+AAADwNgAAEAGEABDAH//wNwAAADAJAAAAMAAAMAHroCQGEAAQApQgEBA3AAAAMAkAAAAwAAAwAe' +\n 'oCCBBZbqrprm4CGgwIAAAAyAAAADAIRiAAEABkQBwXPBiQAAABNjb2xybmNseAABAA0ABoAAAAAUaXNwZQAAA' +\n 'AAAAABAAAAAQAAAAChjbGFwAAAAAgAAAAEAAAACAAAAAf///8IAAAAC////wgAAAAIAAAAQcGl4aQAAAAADCA' +\n 'gIAAAAGGlwbWEAAAAAAAAAAQABBYECAwWEAAAAP21kYXQAAAAzKAGvBjIWhzSJIPC/cov//8tX9l+i9qzWyeu' +\n 'EfoBjx+S3kJGe9F97GFLlPHQg9JxTuc2A';\n","import { HeicParseError } from '../errors.ts';\n\n/**\n * Bounds-checked big-endian byte reader.\n *\n * Every single read validates against the window before touching the buffer.\n * This is the only place in the package that indexes raw bytes, so the security\n * guarantee is enforceable by review: if it isn't going through Reader, it isn't\n * reading the file.\n *\n * A Reader is a *window* onto a shared ArrayBuffer, not a copy. Sub-readers for\n * nested boxes are free.\n */\nexport class Reader {\n readonly bytes: Uint8Array;\n private readonly view: DataView;\n /** Absolute offset of this window's start within the underlying ArrayBuffer. */\n readonly base: number;\n /** Cursor, relative to the window start. */\n private pos = 0;\n\n constructor(source: ArrayBuffer | Uint8Array, byteOffset = 0, byteLength?: number) {\n const u8 = source instanceof Uint8Array ? source : new Uint8Array(source);\n const start = u8.byteOffset + byteOffset;\n const length = byteLength ?? u8.byteLength - byteOffset;\n if (byteOffset < 0 || length < 0 || byteOffset + length > u8.byteLength) {\n throw new HeicParseError('Reader window is outside the source buffer', {\n offset: byteOffset,\n });\n }\n this.bytes = new Uint8Array(u8.buffer, start, length);\n this.view = new DataView(u8.buffer, start, length);\n this.base = start;\n }\n\n get length(): number {\n return this.bytes.byteLength;\n }\n\n get offset(): number {\n return this.pos;\n }\n\n /** Absolute offset of the cursor in the underlying buffer, for error reports. */\n get absoluteOffset(): number {\n return this.base + this.pos;\n }\n\n get remaining(): number {\n return this.length - this.pos;\n }\n\n get eof(): boolean {\n return this.pos >= this.length;\n }\n\n seek(to: number): void {\n this.require(0, to);\n this.pos = to;\n }\n\n skip(count: number): void {\n this.require(count);\n this.pos += count;\n }\n\n /**\n * Throws unless `count` bytes are readable at `at` (default: the cursor).\n * Callers that are about to allocate should call this first with the declared\n * size, so a hostile length field fails here rather than in the allocator.\n */\n require(count: number, at = this.pos): void {\n if (!Number.isFinite(count) || count < 0 || !Number.isFinite(at) || at < 0) {\n throw new HeicParseError('Malformed read request', { offset: this.base + this.pos });\n }\n if (at + count > this.length) {\n throw new HeicParseError(\n `Read of ${count} bytes at ${at} exceeds the ${this.length}-byte window`,\n { offset: this.base + at },\n );\n }\n }\n\n u8(): number {\n this.require(1);\n return this.view.getUint8(this.pos++);\n }\n\n u16(): number {\n this.require(2);\n const value = this.view.getUint16(this.pos);\n this.pos += 2;\n return value;\n }\n\n u24(): number {\n this.require(3);\n const value =\n (this.view.getUint8(this.pos) << 16) |\n (this.view.getUint8(this.pos + 1) << 8) |\n this.view.getUint8(this.pos + 2);\n this.pos += 3;\n return value >>> 0;\n }\n\n u32(): number {\n this.require(4);\n const value = this.view.getUint32(this.pos);\n this.pos += 4;\n return value >>> 0;\n }\n\n /**\n * Returns a JS number, not a BigInt. Values above Number.MAX_SAFE_INTEGER are\n * rejected rather than silently losing precision — a 9-petabyte box size is a\n * malformed file, not something to accommodate.\n */\n u64(): number {\n this.require(8);\n const value = this.view.getBigUint64(this.pos);\n this.pos += 8;\n if (value > BigInt(Number.MAX_SAFE_INTEGER)) {\n throw new HeicParseError('64-bit value exceeds the safe integer range', {\n offset: this.base + this.pos - 8,\n });\n }\n return Number(value);\n }\n\n /** Reads a big-endian unsigned integer of 0, 1, 2, 4 or 8 bytes. `iloc` needs this. */\n uint(byteCount: number): number {\n switch (byteCount) {\n case 0:\n return 0;\n case 1:\n return this.u8();\n case 2:\n return this.u16();\n case 4:\n return this.u32();\n case 8:\n return this.u64();\n default:\n throw new HeicParseError(`Unsupported integer width: ${byteCount} bytes`, {\n offset: this.base + this.pos,\n });\n }\n }\n\n /** Four-character box type. Non-printable bytes are escaped so error messages stay readable. */\n fourCC(): string {\n this.require(4);\n let out = '';\n for (let i = 0; i < 4; i++) {\n const byte = this.view.getUint8(this.pos + i);\n out += byte >= 0x20 && byte <= 0x7e ? String.fromCharCode(byte) : `\\\\x${byte.toString(16).padStart(2, '0')}`;\n }\n this.pos += 4;\n return out;\n }\n\n /** NUL-terminated UTF-8 string. Stops at the window end if the NUL is missing. */\n cString(): string {\n const start = this.pos;\n while (this.pos < this.length && this.bytes[this.pos] !== 0) this.pos++;\n const raw = this.bytes.subarray(start, this.pos);\n if (this.pos < this.length) this.pos++; // consume the NUL\n return new TextDecoder().decode(raw);\n }\n\n /** A view onto the next `count` bytes. No copy — do not retain past the buffer's life. */\n view_(count: number): Uint8Array {\n this.require(count);\n const out = this.bytes.subarray(this.pos, this.pos + count);\n this.pos += count;\n return out;\n }\n\n /** A copy of the next `count` bytes. Use when the result outlives the source buffer. */\n copy(count: number): Uint8Array {\n return new Uint8Array(this.view_(count));\n }\n\n /** A sub-reader over `count` bytes, advancing this reader past them. */\n sub(count: number): Reader {\n this.require(count);\n const child = new Reader(this.bytes, this.pos, count);\n this.pos += count;\n return child;\n }\n\n /** A sub-reader over the rest of the window, without advancing this reader. */\n peekRest(): Reader {\n return new Reader(this.bytes, this.pos, this.remaining);\n }\n}\n\n/** FullBox header: 8-bit version, 24-bit flags. */\nexport interface FullBoxHeader {\n version: number;\n flags: number;\n}\n\nexport function readFullBoxHeader(reader: Reader): FullBoxHeader {\n const version = reader.u8();\n const flags = reader.u24();\n return { version, flags };\n}\n","import { HeicParseError } from '../errors.ts';\nimport { Reader } from './reader.ts';\n\n/** NAL unit types that appear in an hvcC parameter-set array. */\nexport const NAL_VPS = 32;\nexport const NAL_SPS = 33;\nexport const NAL_PPS = 34;\n\nexport interface HvccNalArray {\n arrayCompleteness: boolean;\n nalUnitType: number;\n /** Views into the source buffer, not copies. */\n nalus: Uint8Array[];\n}\n\n/** Parsed HEVCDecoderConfigurationRecord (ISO/IEC 14496-15 §8.3.3.1). */\nexport interface HvcC {\n configurationVersion: number;\n generalProfileSpace: number;\n generalTierFlag: number;\n generalProfileIdc: number;\n generalProfileCompatibilityFlags: number;\n /** Six bytes, big-endian order as stored. */\n generalConstraintIndicatorFlags: Uint8Array;\n generalLevelIdc: number;\n minSpatialSegmentationIdc: number;\n parallelismType: number;\n chromaFormat: number;\n bitDepthLumaMinus8: number;\n bitDepthChromaMinus8: number;\n avgFrameRate: number;\n constantFrameRate: number;\n numTemporalLayers: number;\n temporalIdNested: number;\n /** Byte width of the length prefix on each NAL unit in the item payload. */\n lengthSizeMinusOne: number;\n arrays: HvccNalArray[];\n /** The raw record, which is what VideoDecoderConfig.description wants. */\n raw: Uint8Array;\n}\n\n/** Sanity cap: no real hvcC has more than a handful of arrays or NAL units. */\nconst MAX_HVCC_ARRAYS = 32;\nconst MAX_NALUS_PER_ARRAY = 256;\n\nexport function parseHvcC(reader: Reader): HvcC {\n const raw = reader.peekRest().bytes;\n\n const configurationVersion = reader.u8();\n if (configurationVersion !== 1) {\n // The spec reserves other values; libheif and Chromium both only accept 1.\n throw new HeicParseError(\n `Unsupported HEVCDecoderConfigurationRecord version ${configurationVersion}`,\n { box: 'hvcC' },\n );\n }\n\n const profileByte = reader.u8();\n const generalProfileSpace = (profileByte >> 6) & 0x03;\n const generalTierFlag = (profileByte >> 5) & 0x01;\n const generalProfileIdc = profileByte & 0x1f;\n\n const generalProfileCompatibilityFlags = reader.u32();\n const generalConstraintIndicatorFlags = reader.copy(6);\n const generalLevelIdc = reader.u8();\n\n const minSpatialSegmentationIdc = reader.u16() & 0x0fff;\n const parallelismType = reader.u8() & 0x03;\n const chromaFormat = reader.u8() & 0x03;\n const bitDepthLumaMinus8 = reader.u8() & 0x07;\n const bitDepthChromaMinus8 = reader.u8() & 0x07;\n\n const avgFrameRate = reader.u16();\n const rateByte = reader.u8();\n const constantFrameRate = (rateByte >> 6) & 0x03;\n const numTemporalLayers = (rateByte >> 3) & 0x07;\n const temporalIdNested = (rateByte >> 2) & 0x01;\n const lengthSizeMinusOne = rateByte & 0x03;\n\n const numOfArrays = reader.u8();\n if (numOfArrays > MAX_HVCC_ARRAYS) {\n throw new HeicParseError(`hvcC declares ${numOfArrays} NAL arrays`, { box: 'hvcC' });\n }\n\n const arrays: HvccNalArray[] = [];\n for (let i = 0; i < numOfArrays; i++) {\n const head = reader.u8();\n const arrayCompleteness = ((head >> 7) & 0x01) === 1;\n const nalUnitType = head & 0x3f;\n const numNalus = reader.u16();\n if (numNalus > MAX_NALUS_PER_ARRAY) {\n throw new HeicParseError(`hvcC array declares ${numNalus} NAL units`, { box: 'hvcC' });\n }\n const nalus: Uint8Array[] = [];\n for (let j = 0; j < numNalus; j++) {\n const nalUnitLength = reader.u16();\n nalus.push(reader.view_(nalUnitLength));\n }\n arrays.push({ arrayCompleteness, nalUnitType, nalus });\n }\n\n return {\n configurationVersion,\n generalProfileSpace,\n generalTierFlag,\n generalProfileIdc,\n generalProfileCompatibilityFlags,\n generalConstraintIndicatorFlags,\n generalLevelIdc,\n minSpatialSegmentationIdc,\n parallelismType,\n chromaFormat,\n bitDepthLumaMinus8,\n bitDepthChromaMinus8,\n avgFrameRate,\n constantFrameRate,\n numTemporalLayers,\n temporalIdNested,\n lengthSizeMinusOne,\n arrays,\n raw,\n };\n}\n\nconst PROFILE_SPACE_PREFIX = ['', 'A', 'B', 'C'] as const;\n\n/**\n * Builds the RFC 6381 codec string for a VideoDecoderConfig.\n *\n * Format: `{fourcc}.{space}{profile_idc}.{compat}.{tier}{level}.{constraints}`\n * A typical iPhone Main-profile record produces `hvc1.1.6.L93.B0`.\n */\nexport function hvccToCodecString(hvcc: HvcC, fourCC: 'hvc1' | 'hev1' = 'hvc1'): string {\n const space = PROFILE_SPACE_PREFIX[hvcc.generalProfileSpace] ?? '';\n const profile = `${space}${hvcc.generalProfileIdc}`;\n\n // The compatibility flags are printed bit-reversed. This is not a quirk of any\n // one implementation: RFC 6381 specifies the value \"in reverse bit order\",\n // which is why Main profile's 0x60000000 prints as \"6\" and not \"60000000\".\n const compat = reverseBits32(hvcc.generalProfileCompatibilityFlags).toString(16);\n\n const tier = hvcc.generalTierFlag === 1 ? 'H' : 'L';\n const level = `${tier}${hvcc.generalLevelIdc}`;\n\n // Trailing zero constraint bytes are omitted; a record with no constraint bits\n // set contributes no trailing component at all.\n const constraintBytes = [...hvcc.generalConstraintIndicatorFlags];\n while (constraintBytes.length > 0 && constraintBytes[constraintBytes.length - 1] === 0) {\n constraintBytes.pop();\n }\n const constraints = constraintBytes.map((b) => b.toString(16).padStart(2, '0').toUpperCase());\n\n return [fourCC, profile, compat, level, ...constraints].join('.');\n}\n\n/** Reverses the bit order of a 32-bit unsigned integer. */\nexport function reverseBits32(value: number): number {\n let v = value >>> 0;\n v = ((v & 0x55555555) << 1) | ((v >>> 1) & 0x55555555);\n v = ((v & 0x33333333) << 2) | ((v >>> 2) & 0x33333333);\n v = ((v & 0x0f0f0f0f) << 4) | ((v >>> 4) & 0x0f0f0f0f);\n v = ((v & 0x00ff00ff) << 8) | ((v >>> 8) & 0x00ff00ff);\n v = (v >>> 16) | (v << 16);\n return v >>> 0;\n}\n\n/** Bit depth reported by the decoder configuration record. */\nexport function hvccBitDepth(hvcc: HvcC): number {\n return hvcc.bitDepthLumaMinus8 + 8;\n}\n\n/**\n * Builds an Annex B parameter-set prologue (VPS/SPS/PPS, each start-code\n * prefixed) for the `hev1` fallback configuration mode.\n */\nexport function hvccToAnnexBPrologue(hvcc: HvcC): Uint8Array {\n const wanted = [NAL_VPS, NAL_SPS, NAL_PPS];\n const selected = wanted\n .flatMap((type) => hvcc.arrays.filter((a) => a.nalUnitType === type))\n .flatMap((a) => a.nalus);\n\n let total = 0;\n for (const nalu of selected) total += 4 + nalu.byteLength;\n\n const out = new Uint8Array(total);\n let pos = 0;\n for (const nalu of selected) {\n out.set([0x00, 0x00, 0x00, 0x01], pos);\n pos += 4;\n out.set(nalu, pos);\n pos += nalu.byteLength;\n }\n return out;\n}\n\n/**\n * Rewrites a length-prefixed NAL unit stream to Annex B start codes.\n * `lengthSize` is `lengthSizeMinusOne + 1` from the hvcC.\n */\nexport function lengthPrefixedToAnnexB(data: Uint8Array, lengthSize: number): Uint8Array {\n if (lengthSize < 1 || lengthSize > 4) {\n throw new HeicParseError(`Invalid NAL length size ${lengthSize}`, { box: 'hvcC' });\n }\n // Start codes are 4 bytes, so the output is at most (4 - lengthSize) bytes\n // larger per NAL unit. Counting first avoids growing a buffer in a loop.\n const out = new Uint8Array(data.byteLength + countNalUnits(data, lengthSize) * (4 - lengthSize));\n let read = 0;\n let write = 0;\n while (read + lengthSize <= data.byteLength) {\n let naluLength = 0;\n for (let i = 0; i < lengthSize; i++) naluLength = (naluLength << 8) | data[read + i]!;\n read += lengthSize;\n if (naluLength < 0 || read + naluLength > data.byteLength) {\n throw new HeicParseError('NAL unit length runs past the end of the item payload', {\n offset: read,\n });\n }\n out.set([0x00, 0x00, 0x00, 0x01], write);\n write += 4;\n out.set(data.subarray(read, read + naluLength), write);\n write += naluLength;\n read += naluLength;\n }\n return out.subarray(0, write);\n}\n\nfunction countNalUnits(data: Uint8Array, lengthSize: number): number {\n let read = 0;\n let count = 0;\n while (read + lengthSize <= data.byteLength) {\n let naluLength = 0;\n for (let i = 0; i < lengthSize; i++) naluLength = (naluLength << 8) | data[read + i]!;\n read += lengthSize + naluLength;\n if (naluLength < 0 || read > data.byteLength) break;\n count++;\n }\n return count;\n}\n","import { HeicParseError } from '../errors.ts';\nimport { Reader } from './reader.ts';\n\n/** Hard cap on box nesting. A legitimate HEIF tree is ~4 deep; 32 is generous. */\nexport const MAX_BOX_DEPTH = 32;\n\n/**\n * A cap on how many sibling boxes we will walk at one level. Without it, a file\n * full of zero-payload 8-byte boxes turns into an unbounded loop over the whole\n * buffer. 64k siblings is far past any real file.\n */\nexport const MAX_SIBLING_BOXES = 65_536;\n\nexport interface Box {\n type: string;\n /** Absolute offset of the box header in the source buffer. */\n offset: number;\n /** Total box size including its header. */\n size: number;\n /** Size of the header (8, 16 for largesize). */\n headerSize: number;\n /** A reader positioned at the start of the box payload, windowed to its end. */\n body: Reader;\n}\n\n/**\n * Walks the boxes in `reader`'s window, yielding each in turn.\n *\n * Each yielded box carries its own body reader, so a consumer that only cares\n * about `meta` costs nothing for the megabytes of `mdat` next to it.\n */\nexport interface WalkOptions {\n depth?: number;\n /**\n * Stop cleanly at the first box that runs past the end of the window instead\n * of throwing. Detection is handed only the first few KB of a file, where a\n * truncated trailing box is expected rather than a sign of corruption.\n */\n lenient?: boolean;\n}\n\nexport function* walkBoxes(reader: Reader, options: WalkOptions | number = {}): Generator<Box> {\n const { depth = 0, lenient = false } =\n typeof options === 'number' ? { depth: options, lenient: false } : options;\n if (depth > MAX_BOX_DEPTH) {\n throw new HeicParseError(`Box nesting deeper than ${MAX_BOX_DEPTH}`, {\n offset: reader.absoluteOffset,\n });\n }\n\n let count = 0;\n while (reader.remaining >= 8) {\n if (++count > MAX_SIBLING_BOXES) {\n throw new HeicParseError(`More than ${MAX_SIBLING_BOXES} sibling boxes at one level`, {\n offset: reader.absoluteOffset,\n });\n }\n\n const offset = reader.absoluteOffset;\n const start = reader.offset;\n let size = reader.u32();\n const type = reader.fourCC();\n let headerSize = 8;\n\n if (size === 1) {\n size = reader.u64();\n headerSize = 16;\n } else if (size === 0) {\n // \"extends to the end of the enclosing container\"\n size = reader.length - start;\n }\n\n if (size < headerSize) {\n if (lenient) return;\n throw new HeicParseError(`Box size ${size} is smaller than its ${headerSize}-byte header`, {\n offset,\n box: type,\n });\n }\n if (start + size > reader.length) {\n if (lenient) return;\n throw new HeicParseError(\n `Box extends ${start + size - reader.length} bytes past its container`,\n { offset, box: type },\n );\n }\n\n const payloadSize = size - headerSize;\n const body = reader.sub(payloadSize);\n yield { type, offset, size, headerSize, body };\n\n // Boxes are consumed via `body`, whose cursor the caller may have moved.\n // Reposition absolutely so a partially-read box cannot desynchronise the walk.\n reader.seek(start + size);\n }\n}\n\n/** Collects the child boxes of a container into an array. */\nexport function childBoxes(reader: Reader, options: WalkOptions | number = {}): Box[] {\n return [...walkBoxes(reader, options)];\n}\n\n/** Returns the first child box of the given type, or undefined. */\nexport function findBox(boxes: readonly Box[], type: string): Box | undefined {\n return boxes.find((box) => box.type === type);\n}\n\n/** Returns every child box of the given type. */\nexport function findBoxes(boxes: readonly Box[], type: string): Box[] {\n return boxes.filter((box) => box.type === type);\n}\n","import { HeicParseError } from '../errors.ts';\nimport { childBoxes, findBox, findBoxes, walkBoxes, type Box } from './boxes.ts';\nimport { parseHvcC, type HvcC } from './hvcc.ts';\nimport { Reader, readFullBoxHeader } from './reader.ts';\n\n/** Sanity caps. Every one of these is far past any real file. */\nconst MAX_ITEMS = 65_536;\nconst MAX_EXTENTS_PER_ITEM = 4096;\nconst MAX_PROPERTIES = 4096;\nconst MAX_ASSOCIATIONS_PER_ITEM = 256;\nconst MAX_REFERENCES_PER_ITEM = 8192;\n\n// ---------------------------------------------------------------------------\n// Item info (iinf / infe)\n// ---------------------------------------------------------------------------\n\nexport interface ItemInfo {\n itemId: number;\n protectionIndex: number;\n /** 'hvc1', 'grid', 'Exif', 'mime', ... Empty for version 0/1 infe boxes. */\n itemType: string;\n itemName: string;\n contentType?: string;\n /** Set when the infe declares the item hidden. */\n hidden: boolean;\n}\n\nfunction parseInfe(box: Box): ItemInfo {\n const r = box.body;\n const { version, flags } = readFullBoxHeader(r);\n const hidden = (flags & 0x01) === 1;\n\n if (version >= 2) {\n const itemId = version === 2 ? r.u16() : r.u32();\n const protectionIndex = r.u16();\n const itemType = r.fourCC();\n const itemName = r.cString();\n const info: ItemInfo = { itemId, protectionIndex, itemType, itemName, hidden };\n if (itemType === 'mime') info.contentType = r.cString();\n return info;\n }\n\n // Version 0/1 predate item_type; only 'mime'-ish metadata items use these and\n // we never need to decode them, but they must not break the walk.\n const itemId = r.u16();\n const protectionIndex = r.u16();\n const itemName = r.cString();\n const contentType = r.cString();\n return { itemId, protectionIndex, itemType: '', itemName, contentType, hidden };\n}\n\nfunction parseIinf(box: Box): Map<number, ItemInfo> {\n const r = box.body;\n const { version } = readFullBoxHeader(r);\n const entryCount = version === 0 ? r.u16() : r.u32();\n if (entryCount > MAX_ITEMS) {\n throw new HeicParseError(`iinf declares ${entryCount} items`, { box: 'iinf' });\n }\n\n const items = new Map<number, ItemInfo>();\n // Trust the box structure over the declared count: walk the actual children\n // and stop at the container end. A wrong entry_count is then harmless.\n let seen = 0;\n for (const child of walkBoxes(r.peekRest())) {\n if (child.type !== 'infe') continue;\n if (++seen > MAX_ITEMS) break;\n const info = parseInfe(child);\n items.set(info.itemId, info);\n }\n return items;\n}\n\n// ---------------------------------------------------------------------------\n// Item locations (iloc)\n// ---------------------------------------------------------------------------\n\nexport interface ItemExtent {\n /** Offset, relative to whatever `constructionMethod` selects. */\n offset: number;\n length: number;\n}\n\nexport interface ItemLocation {\n itemId: number;\n /** 0 = offset into the file, 1 = offset into idat, 2 = offset into another item. */\n constructionMethod: number;\n baseOffset: number;\n extents: ItemExtent[];\n}\n\nfunction parseIloc(box: Box): Map<number, ItemLocation> {\n const r = box.body;\n const { version } = readFullBoxHeader(r);\n\n const sizesByte = r.u8();\n const offsetSize = (sizesByte >> 4) & 0x0f;\n const lengthSize = sizesByte & 0x0f;\n const baseByte = r.u8();\n const baseOffsetSize = (baseByte >> 4) & 0x0f;\n // index_size occupies the low nibble in versions 1 and 2; reserved in version 0.\n const indexSize = version === 1 || version === 2 ? baseByte & 0x0f : 0;\n\n const itemCount = version < 2 ? r.u16() : r.u32();\n if (itemCount > MAX_ITEMS) {\n throw new HeicParseError(`iloc declares ${itemCount} items`, { box: 'iloc' });\n }\n\n const locations = new Map<number, ItemLocation>();\n for (let i = 0; i < itemCount; i++) {\n const itemId = version < 2 ? r.u16() : r.u32();\n\n let constructionMethod = 0;\n if (version === 1 || version === 2) {\n constructionMethod = r.u16() & 0x0f; // 12 reserved bits, then 4 bits of method\n }\n\n r.u16(); // data_reference_index — external references are not supported\n const baseOffset = r.uint(baseOffsetSize);\n\n const extentCount = r.u16();\n if (extentCount > MAX_EXTENTS_PER_ITEM) {\n throw new HeicParseError(`Item ${itemId} declares ${extentCount} extents`, {\n box: 'iloc',\n itemId,\n });\n }\n\n const extents: ItemExtent[] = [];\n for (let j = 0; j < extentCount; j++) {\n if ((version === 1 || version === 2) && indexSize > 0) r.uint(indexSize); // extent_index\n const offset = r.uint(offsetSize);\n const length = r.uint(lengthSize);\n extents.push({ offset, length });\n }\n\n locations.set(itemId, { itemId, constructionMethod, baseOffset, extents });\n }\n return locations;\n}\n\n// ---------------------------------------------------------------------------\n// Item properties (iprp → ipco / ipma)\n// ---------------------------------------------------------------------------\n\nexport interface IspeProperty {\n type: 'ispe';\n width: number;\n height: number;\n}\nexport interface HvccProperty {\n type: 'hvcC';\n hvcc: HvcC;\n}\nexport interface IrotProperty {\n type: 'irot';\n /** Counter-clockwise rotation in degrees. */\n angle: 0 | 90 | 180 | 270;\n}\nexport interface ImirProperty {\n type: 'imir';\n /** Raw `axis` field. See render/transform.ts for the semantics, which are verified empirically. */\n axis: 0 | 1;\n}\nexport interface ColrNclxProperty {\n type: 'colr';\n colorType: 'nclx';\n primaries: number;\n transfer: number;\n matrix: number;\n fullRange: boolean;\n}\nexport interface ColrIccProperty {\n type: 'colr';\n colorType: 'icc';\n profile: Uint8Array;\n}\nexport interface PixiProperty {\n type: 'pixi';\n bitsPerChannel: number[];\n}\nexport interface ClapProperty {\n type: 'clap';\n widthN: number;\n widthD: number;\n heightN: number;\n heightD: number;\n horizOffN: number;\n horizOffD: number;\n vertOffN: number;\n vertOffD: number;\n}\nexport interface AuxCProperty {\n type: 'auxC';\n auxType: string;\n}\nexport interface UnknownProperty {\n type: 'unknown';\n boxType: string;\n}\n\nexport type ItemProperty =\n | IspeProperty\n | HvccProperty\n | IrotProperty\n | ImirProperty\n | ColrNclxProperty\n | ColrIccProperty\n | PixiProperty\n | ClapProperty\n | AuxCProperty\n | UnknownProperty;\n\n/** Properties we know how to honour. An *essential* association to anything else is fatal. */\nconst UNDERSTOOD_PROPERTY_TYPES = new Set([\n 'ispe',\n 'hvcC',\n 'irot',\n 'imir',\n 'colr',\n 'pixi',\n 'clap',\n 'auxC',\n // Understood in the sense of \"safe to ignore\": these carry display hints and\n // metadata that do not change the decoded pixels.\n 'pasp',\n 'clli',\n 'mdcv',\n 'rloc',\n 'cclv',\n 'amve',\n]);\n\nfunction parseProperty(box: Box): ItemProperty {\n const r = box.body;\n switch (box.type) {\n case 'ispe': {\n readFullBoxHeader(r);\n return { type: 'ispe', width: r.u32(), height: r.u32() };\n }\n case 'hvcC':\n return { type: 'hvcC', hvcc: parseHvcC(r) };\n case 'irot': {\n const angle = ((r.u8() & 0x03) * 90) as 0 | 90 | 180 | 270;\n return { type: 'irot', angle };\n }\n case 'imir': {\n const axis = (r.u8() & 0x01) as 0 | 1;\n return { type: 'imir', axis };\n }\n case 'colr': {\n const colorType = r.fourCC();\n if (colorType === 'nclx') {\n const primaries = r.u16();\n const transfer = r.u16();\n const matrix = r.u16();\n const fullRange = (r.u8() & 0x80) !== 0;\n return { type: 'colr', colorType: 'nclx', primaries, transfer, matrix, fullRange };\n }\n if (colorType === 'rICC' || colorType === 'prof') {\n return { type: 'colr', colorType: 'icc', profile: r.copy(r.remaining) };\n }\n return { type: 'unknown', boxType: `colr:${colorType}` };\n }\n case 'pixi': {\n readFullBoxHeader(r);\n const numChannels = r.u8();\n const bitsPerChannel: number[] = [];\n for (let i = 0; i < numChannels; i++) bitsPerChannel.push(r.u8());\n return { type: 'pixi', bitsPerChannel };\n }\n case 'clap':\n return {\n type: 'clap',\n widthN: r.u32(),\n widthD: r.u32(),\n heightN: r.u32(),\n heightD: r.u32(),\n horizOffN: r.u32() | 0, // stored as a signed 32-bit numerator\n horizOffD: r.u32(),\n vertOffN: r.u32() | 0,\n vertOffD: r.u32(),\n };\n case 'auxC': {\n readFullBoxHeader(r);\n return { type: 'auxC', auxType: r.cString() };\n }\n default:\n return { type: 'unknown', boxType: box.type };\n }\n}\n\nexport interface PropertyAssociation {\n /** 1-based index into the ipco child list. */\n index: number;\n essential: boolean;\n}\n\nfunction parseIpma(box: Box, into: Map<number, PropertyAssociation[]>): void {\n const r = box.body;\n const { version, flags } = readFullBoxHeader(r);\n const wideIndex = (flags & 0x01) === 1;\n\n const entryCount = r.u32();\n if (entryCount > MAX_ITEMS) {\n throw new HeicParseError(`ipma declares ${entryCount} entries`, { box: 'ipma' });\n }\n\n for (let i = 0; i < entryCount; i++) {\n const itemId = version === 0 ? r.u16() : r.u32();\n const associationCount = r.u8();\n if (associationCount > MAX_ASSOCIATIONS_PER_ITEM) {\n throw new HeicParseError(`Item ${itemId} declares ${associationCount} properties`, {\n box: 'ipma',\n itemId,\n });\n }\n\n // Association *order* is load-bearing: transformative properties apply in the\n // order they appear here (HEIF §6.5.1), so this list must never be sorted.\n const associations: PropertyAssociation[] = [];\n for (let j = 0; j < associationCount; j++) {\n if (wideIndex) {\n const value = r.u16();\n associations.push({ essential: (value & 0x8000) !== 0, index: value & 0x7fff });\n } else {\n const value = r.u8();\n associations.push({ essential: (value & 0x80) !== 0, index: value & 0x7f });\n }\n }\n\n // A file may carry several ipma boxes; later entries append to the item.\n const existing = into.get(itemId);\n if (existing) existing.push(...associations);\n else into.set(itemId, associations);\n }\n}\n\nexport interface ItemProperties {\n /** 1-indexed in the file; index 0 is \"no property\" and is never present here. */\n properties: ItemProperty[];\n associations: Map<number, PropertyAssociation[]>;\n}\n\nfunction parseIprp(box: Box): ItemProperties {\n const children = childBoxes(box.body);\n const ipco = findBox(children, 'ipco');\n\n const properties: ItemProperty[] = [];\n if (ipco) {\n for (const child of walkBoxes(ipco.body)) {\n if (properties.length >= MAX_PROPERTIES) {\n throw new HeicParseError(`ipco holds more than ${MAX_PROPERTIES} properties`, {\n box: 'ipco',\n });\n }\n properties.push(parseProperty(child));\n }\n }\n\n const associations = new Map<number, PropertyAssociation[]>();\n for (const ipma of findBoxes(children, 'ipma')) parseIpma(ipma, associations);\n\n return { properties, associations };\n}\n\n// ---------------------------------------------------------------------------\n// Item references (iref)\n// ---------------------------------------------------------------------------\n\n/** referenceType → fromItemId → toItemIds, in file order. */\nexport type ItemReferences = Map<string, Map<number, number[]>>;\n\nfunction parseIref(box: Box): ItemReferences {\n const r = box.body;\n const { version } = readFullBoxHeader(r);\n const refs: ItemReferences = new Map();\n\n for (const child of walkBoxes(r.peekRest())) {\n const cr = child.body;\n const fromItemId = version === 0 ? cr.u16() : cr.u32();\n const referenceCount = cr.u16();\n if (referenceCount > MAX_REFERENCES_PER_ITEM) {\n throw new HeicParseError(`Item ${fromItemId} declares ${referenceCount} references`, {\n box: child.type,\n itemId: fromItemId,\n });\n }\n const toItemIds: number[] = [];\n for (let i = 0; i < referenceCount; i++) {\n toItemIds.push(version === 0 ? cr.u16() : cr.u32());\n }\n\n let byType = refs.get(child.type);\n if (!byType) refs.set(child.type, (byType = new Map()));\n byType.set(fromItemId, toItemIds);\n }\n\n return refs;\n}\n\n// ---------------------------------------------------------------------------\n// The parsed file\n// ---------------------------------------------------------------------------\n\nexport interface HeifFile {\n majorBrand: string;\n minorVersion: number;\n compatibleBrands: string[];\n /** Item ID named by `pitm`. */\n primaryItemId: number;\n handlerType: string;\n items: Map<number, ItemInfo>;\n locations: Map<number, ItemLocation>;\n itemProperties: ItemProperties;\n references: ItemReferences;\n /** Payload of the `idat` box, for construction_method 1. */\n itemData: Uint8Array | undefined;\n /** The whole source buffer, for construction_method 0 offsets. */\n source: Uint8Array;\n}\n\nexport interface ParseOptions {\n /**\n * Tolerate a top-level box that runs past the end of the buffer, stopping the\n * walk there instead of throwing. Only for detection, which is deliberately\n * handed a truncated prefix; a full-file parse stays strict so that genuine\n * truncation is reported rather than silently half-decoded.\n */\n truncated?: boolean;\n}\n\nexport function parseHeif(input: ArrayBuffer | Uint8Array, options: ParseOptions = {}): HeifFile {\n const source = input instanceof Uint8Array ? input : new Uint8Array(input);\n const root = new Reader(source);\n const boxes = childBoxes(root, { lenient: options.truncated === true });\n\n const ftyp = findBox(boxes, 'ftyp');\n if (!ftyp) throw new HeicParseError(\"No 'ftyp' box: this is not an ISOBMFF file\", { offset: 0 });\n const majorBrand = ftyp.body.fourCC();\n const minorVersion = ftyp.body.u32();\n const compatibleBrands: string[] = [];\n while (ftyp.body.remaining >= 4) compatibleBrands.push(ftyp.body.fourCC());\n\n const meta = findBox(boxes, 'meta');\n if (!meta) {\n throw new HeicParseError(\"No 'meta' box: not a HEIF image file\", { brand: majorBrand });\n }\n readFullBoxHeader(meta.body); // meta is a FullBox\n const metaChildren = childBoxes(meta.body, 1);\n\n const hdlr = findBox(metaChildren, 'hdlr');\n let handlerType = '';\n if (hdlr) {\n readFullBoxHeader(hdlr.body);\n hdlr.body.u32(); // pre_defined\n handlerType = hdlr.body.fourCC();\n }\n if (handlerType && handlerType !== 'pict') {\n throw new HeicParseError(`meta handler is '${handlerType}', expected 'pict'`, {\n brand: majorBrand,\n });\n }\n\n let primaryItemId = 0;\n const pitm = findBox(metaChildren, 'pitm');\n if (pitm) {\n const { version } = readFullBoxHeader(pitm.body);\n primaryItemId = version === 0 ? pitm.body.u16() : pitm.body.u32();\n }\n\n const iinf = findBox(metaChildren, 'iinf');\n const items = iinf ? parseIinf(iinf) : new Map<number, ItemInfo>();\n\n const iloc = findBox(metaChildren, 'iloc');\n const locations = iloc ? parseIloc(iloc) : new Map<number, ItemLocation>();\n\n const iprp = findBox(metaChildren, 'iprp');\n const itemProperties = iprp ? parseIprp(iprp) : { properties: [], associations: new Map() };\n\n const iref = findBox(metaChildren, 'iref');\n const references = iref ? parseIref(iref) : (new Map() as ItemReferences);\n\n const idat = findBox(metaChildren, 'idat');\n const itemData = idat ? idat.body.copy(idat.body.remaining) : undefined;\n\n // With no pitm, fall back to the first image item rather than failing: some\n // non-Apple encoders omit it for single-image files.\n if (primaryItemId === 0) {\n for (const [id, info] of items) {\n if (info.itemType === 'hvc1' || info.itemType === 'hev1' || info.itemType === 'grid') {\n primaryItemId = id;\n break;\n }\n }\n }\n\n return {\n majorBrand,\n minorVersion,\n compatibleBrands,\n primaryItemId,\n handlerType,\n items,\n locations,\n itemProperties,\n references,\n itemData,\n source,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Accessors\n// ---------------------------------------------------------------------------\n\n/** Properties associated with an item, in `ipma` order. Order matters for transforms. */\nexport function propertiesForItem(file: HeifFile, itemId: number): ItemProperty[] {\n const associations = file.itemProperties.associations.get(itemId) ?? [];\n const out: ItemProperty[] = [];\n\n for (const association of associations) {\n if (association.index === 0) continue; // 0 means \"no property\"\n const property = file.itemProperties.properties[association.index - 1];\n if (!property) {\n throw new HeicParseError(\n `Item ${itemId} references property ${association.index}, but ipco holds ${file.itemProperties.properties.length}`,\n { itemId, box: 'ipma' },\n );\n }\n // \"Essential\" means the file is asserting we cannot render correctly without\n // honouring this. Producing a confidently wrong image is worse than failing.\n if (association.essential && property.type === 'unknown') {\n throw new HeicParseError(\n `Item ${itemId} requires unsupported essential property '${property.boxType}'`,\n { itemId, box: property.boxType },\n );\n }\n out.push(property);\n }\n return out;\n}\n\n/** First property of the given kind for an item, or undefined. */\nexport function findProperty<T extends ItemProperty['type']>(\n properties: readonly ItemProperty[],\n type: T,\n): Extract<ItemProperty, { type: T }> | undefined {\n return properties.find((p) => p.type === type) as Extract<ItemProperty, { type: T }> | undefined;\n}\n\n/**\n * Assembles an item's payload from its extents.\n *\n * Extents are concatenated in order. Every offset and length is validated\n * against the actual buffer before a single byte is allocated, so a malformed\n * `extent_length` fails here rather than in the allocator.\n */\nexport function readItemData(file: HeifFile, itemId: number): Uint8Array {\n const location = file.locations.get(itemId);\n if (!location) {\n throw new HeicParseError(`No iloc entry for item ${itemId}`, { itemId, box: 'iloc' });\n }\n\n const info = file.items.get(itemId);\n const context = { itemId, itemType: info?.itemType, box: 'iloc' };\n\n let container: Uint8Array;\n switch (location.constructionMethod) {\n case 0:\n container = file.source;\n break;\n case 1:\n if (!file.itemData) {\n throw new HeicParseError(\n `Item ${itemId} points into 'idat', but the file has no idat box`,\n context,\n );\n }\n container = file.itemData;\n break;\n case 2:\n throw new HeicParseError(\n `Item ${itemId} uses construction_method 2 (item offset), which is not supported`,\n context,\n );\n default:\n throw new HeicParseError(\n `Item ${itemId} uses unknown construction_method ${location.constructionMethod}`,\n context,\n );\n }\n\n // Validate every extent before allocating anything.\n let total = 0;\n for (const extent of location.extents) {\n const start = location.baseOffset + extent.offset;\n // An extent_length of 0 means \"to the end of the container\" (ISO 14496-12).\n const length = extent.length === 0 ? container.byteLength - start : extent.length;\n if (start < 0 || length < 0 || start + length > container.byteLength) {\n throw new HeicParseError(\n `Item ${itemId} extent [${start}, ${start + length}) is outside its ${container.byteLength}-byte container`,\n context,\n );\n }\n total += length;\n }\n\n if (location.extents.length === 1) {\n const extent = location.extents[0]!;\n const start = location.baseOffset + extent.offset;\n return container.subarray(start, start + total);\n }\n\n const out = new Uint8Array(total);\n let pos = 0;\n for (const extent of location.extents) {\n const start = location.baseOffset + extent.offset;\n const length = extent.length === 0 ? container.byteLength - start : extent.length;\n out.set(container.subarray(start, start + length), pos);\n pos += length;\n }\n return out;\n}\n","import { HeicParseError } from '../errors.ts';\nimport { findProperty, propertiesForItem, readItemData, type HeifFile } from './meta.ts';\nimport { Reader } from './reader.ts';\n\n/** A grid of more than this many tiles is rejected rather than allocated for. */\nexport const MAX_TILES = 4096;\n\nexport interface GridDescriptor {\n rows: number;\n columns: number;\n /** Output dimensions the grid declares in its payload. */\n outputWidth: number;\n outputHeight: number;\n /** Tile item IDs in raster order (left to right, top to bottom). */\n tileItemIds: number[];\n}\n\n/**\n * Parses an ImageGrid payload (HEIF §6.6.2.3.1).\n *\n * ```\n * u8 version (0)\n * u8 flags bit 0 = field_length_size: 0 -> u16 dims, 1 -> u32 dims\n * u8 rows_minus_one\n * u8 columns_minus_one\n * output_width u16 or u32\n * output_height u16 or u32\n * ```\n */\nexport function parseGridPayload(payload: Uint8Array): Omit<GridDescriptor, 'tileItemIds'> {\n const r = new Reader(payload);\n const version = r.u8();\n if (version !== 0) {\n throw new HeicParseError(`Unsupported grid version ${version}`, { itemType: 'grid' });\n }\n const flags = r.u8();\n const wideFields = (flags & 0x01) === 1;\n const rows = r.u8() + 1;\n const columns = r.u8() + 1;\n const outputWidth = wideFields ? r.u32() : r.u16();\n const outputHeight = wideFields ? r.u32() : r.u16();\n return { rows, columns, outputWidth, outputHeight };\n}\n\nexport interface GridWarning {\n code: string;\n message: string;\n}\n\n/**\n * Reads the full grid description for an item, cross-checking the declared\n * dimensions against `ispe` and the declared tile count against `dimg`.\n */\nexport function readGrid(\n file: HeifFile,\n itemId: number,\n warnings: GridWarning[] = [],\n): GridDescriptor {\n const payload = readItemData(file, itemId);\n const { rows, columns, outputWidth, outputHeight } = parseGridPayload(payload);\n\n const tileItemIds = file.references.get('dimg')?.get(itemId) ?? [];\n if (tileItemIds.length === 0) {\n throw new HeicParseError(`Grid item ${itemId} has no 'dimg' tile references`, {\n itemId,\n itemType: 'grid',\n });\n }\n\n // rows x columns is file-supplied and drives both the tile loop and the canvas\n // layout, so it must agree with the reference list before we allocate.\n const expected = rows * columns;\n if (expected !== tileItemIds.length) {\n throw new HeicParseError(\n `Grid item ${itemId} declares ${rows}x${columns} = ${expected} tiles but 'dimg' lists ${tileItemIds.length}`,\n { itemId, itemType: 'grid' },\n );\n }\n if (expected > MAX_TILES) {\n throw new HeicParseError(`Grid item ${itemId} declares ${expected} tiles (max ${MAX_TILES})`, {\n itemId,\n itemType: 'grid',\n });\n }\n\n // The grid item's own ispe is the authority when the two disagree; libheif and\n // Preview both render from ispe, so matching them keeps output consistent.\n let width = outputWidth;\n let height = outputHeight;\n const ispe = findProperty(propertiesForItem(file, itemId), 'ispe');\n if (ispe && (ispe.width !== outputWidth || ispe.height !== outputHeight)) {\n warnings.push({\n code: 'grid-dimension-mismatch',\n message: `Grid payload declares ${outputWidth}x${outputHeight} but ispe declares ${ispe.width}x${ispe.height}; using ispe`,\n });\n width = ispe.width;\n height = ispe.height;\n }\n\n return { rows, columns, outputWidth: width, outputHeight: height, tileItemIds };\n}\n","import { HeicParseError, HeicUnsupportedError } from './errors.ts';\nimport { readGrid } from './parser/grid.ts';\nimport { hvccBitDepth, hvccToCodecString, type HvcC } from './parser/hvcc.ts';\nimport {\n findProperty,\n parseHeif,\n propertiesForItem,\n readItemData,\n type HeifFile,\n type ItemProperty,\n} from './parser/meta.ts';\nimport type { HeicWarning, SourceColor } from './types.ts';\n\n/**\n * Total pixels we are willing to composite. 256 MP is roughly 4x the largest\n * consumer camera output, and caps a single canvas at about a gigabyte of RGBA.\n * Rejecting before allocating is the point.\n */\nexport const MAX_TOTAL_PIXELS = 256_000_000;\n\n/** A transform to apply, in the order the file associated it. */\nexport type TransformOp =\n | { kind: 'rotate'; angle: 90 | 180 | 270 }\n | { kind: 'mirror'; axis: 0 | 1 }\n | { kind: 'crop'; width: number; height: number; offsetX: number; offsetY: number };\n\nexport interface TileGroup {\n /** ipco property index of the hvcC these tiles share. */\n configIndex: number;\n hvcc: HvcC;\n codec: string;\n /** Indices into `ImagePlan.tiles`, in submission order. */\n tileIndices: number[];\n}\n\nexport interface PlannedTile {\n itemId: number;\n /** Position in the composited canvas, before any transform. */\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\nexport interface ImagePlan {\n file: HeifFile;\n primaryItemId: number;\n isGrid: boolean;\n /** Coded dimensions, before transforms. */\n codedWidth: number;\n codedHeight: number;\n /** Dimensions as displayed, after transforms. What the caller sees. */\n displayWidth: number;\n displayHeight: number;\n tiles: PlannedTile[];\n /** Tiles grouped by decoder configuration. Normally exactly one group. */\n tileGroups: TileGroup[];\n /** Transforms in `ipma` association order. */\n transforms: TransformOp[];\n bitDepth: number;\n sourceColor: SourceColor;\n warnings: HeicWarning[];\n}\n\n/**\n * Parses the container and works out everything every strategy needs.\n *\n * Always runs, whichever strategy ends up decoding: the native path needs the\n * dimensions to validate its output, the WebCodecs path needs the tiles, and the\n * wasm path needs the metadata we report back.\n */\nexport function planDecode(input: ArrayBuffer | Uint8Array): ImagePlan {\n const file = parseHeif(input);\n const warnings: HeicWarning[] = [];\n\n const primaryItemId = file.primaryItemId;\n const info = file.items.get(primaryItemId);\n if (!info) {\n throw new HeicParseError(`Primary item ${primaryItemId} is not described by iinf`, {\n brand: file.majorBrand,\n itemId: primaryItemId,\n });\n }\n\n const isGrid = info.itemType === 'grid';\n\n // Checked before reading properties: an AVIF's primary item carries an\n // essential 'av1C', and \"primary item type 'av01' is not supported\" is a far\n // more useful message than \"unsupported essential property 'av1C'\".\n if (!isGrid && info.itemType !== 'hvc1' && info.itemType !== 'hev1') {\n throw new HeicUnsupportedError(\n `Primary item type '${info.itemType}' is not a supported image item`,\n [],\n { brand: file.majorBrand, itemType: info.itemType, itemId: primaryItemId },\n );\n }\n\n const primaryProps = propertiesForItem(file, primaryItemId);\n\n const tiles: PlannedTile[] = [];\n let codedWidth: number;\n let codedHeight: number;\n\n if (isGrid) {\n const grid = readGrid(file, primaryItemId, warnings);\n codedWidth = grid.outputWidth;\n codedHeight = grid.outputHeight;\n\n const firstTileProps = propertiesForItem(file, grid.tileItemIds[0]!);\n const firstIspe = findProperty(firstTileProps, 'ispe');\n if (!firstIspe) {\n throw new HeicParseError(`Grid tile ${grid.tileItemIds[0]} has no ispe`, {\n itemId: grid.tileItemIds[0]!,\n });\n }\n\n for (const [index, itemId] of grid.tileItemIds.entries()) {\n // Tiles are uniform in every file observed, but read each one's own ispe\n // rather than assuming: a wrong tile size silently shifts the mosaic.\n const ispe = findProperty(propertiesForItem(file, itemId), 'ispe') ?? firstIspe;\n tiles.push({\n itemId,\n x: (index % grid.columns) * firstIspe.width,\n y: Math.floor(index / grid.columns) * firstIspe.height,\n width: ispe.width,\n height: ispe.height,\n });\n }\n } else {\n const ispe = findProperty(primaryProps, 'ispe');\n if (!ispe) {\n throw new HeicParseError(`Primary item ${primaryItemId} has no ispe`, {\n itemId: primaryItemId,\n });\n }\n codedWidth = ispe.width;\n codedHeight = ispe.height;\n tiles.push({ itemId: primaryItemId, x: 0, y: 0, width: ispe.width, height: ispe.height });\n }\n\n if (codedWidth <= 0 || codedHeight <= 0) {\n throw new HeicParseError(`Implausible image dimensions ${codedWidth}x${codedHeight}`, {\n itemId: primaryItemId,\n });\n }\n if (codedWidth * codedHeight > MAX_TOTAL_PIXELS) {\n throw new HeicUnsupportedError(\n `Image is ${codedWidth}x${codedHeight}, above the ${MAX_TOTAL_PIXELS}-pixel limit`,\n [],\n { itemId: primaryItemId },\n );\n }\n\n const tileGroups = groupTilesByConfig(file, tiles, warnings);\n const transforms = readTransforms(primaryProps, codedWidth, codedHeight);\n const { displayWidth, displayHeight } = applyTransformsToSize(\n codedWidth,\n codedHeight,\n transforms,\n );\n\n const pixi = findProperty(primaryProps, 'pixi');\n const bitDepth =\n pixi?.bitsPerChannel[0] ?? hvccBitDepth(tileGroups[0]!.hvcc);\n\n collectFeatureWarnings(file, primaryItemId, warnings);\n\n return {\n file,\n primaryItemId,\n isGrid,\n codedWidth,\n codedHeight,\n displayWidth,\n displayHeight,\n tiles,\n tileGroups,\n transforms,\n bitDepth,\n sourceColor: readSourceColor(primaryProps, propertiesForItem(file, tiles[0]!.itemId)),\n warnings,\n };\n}\n\n/**\n * Groups tiles by their `hvcC`, comparing ipco property *indices* rather than\n * parsed records, so identical-but-separate properties still group correctly.\n *\n * Nearly every file yields a single group and a single VideoDecoder. Files that\n * genuinely mix configurations get one reconfigure per group — never one decoder\n * per tile, which exhausts hardware decoder handles.\n */\nfunction groupTilesByConfig(\n file: HeifFile,\n tiles: readonly PlannedTile[],\n warnings: HeicWarning[],\n): TileGroup[] {\n const groups = new Map<number, TileGroup>();\n\n for (const [index, tile] of tiles.entries()) {\n const associations = file.itemProperties.associations.get(tile.itemId) ?? [];\n const association = associations.find(\n (a) => file.itemProperties.properties[a.index - 1]?.type === 'hvcC',\n );\n if (!association) {\n throw new HeicParseError(`Item ${tile.itemId} has no hvcC property`, { itemId: tile.itemId });\n }\n\n let group = groups.get(association.index);\n if (!group) {\n const property = file.itemProperties.properties[association.index - 1];\n if (property?.type !== 'hvcC') {\n throw new HeicParseError(`Property ${association.index} is not an hvcC`, {\n itemId: tile.itemId,\n });\n }\n group = {\n configIndex: association.index,\n hvcc: property.hvcc,\n codec: hvccToCodecString(property.hvcc),\n tileIndices: [],\n };\n groups.set(association.index, group);\n }\n group.tileIndices.push(index);\n }\n\n const result = [...groups.values()];\n if (result.length === 0) {\n throw new HeicParseError('No decoder configuration found for any tile', {});\n }\n if (result.length > 1) {\n warnings.push({\n code: 'mixed-tile-configs',\n message: `Tiles use ${result.length} different decoder configurations; decoding in ${result.length} groups`,\n });\n }\n return result;\n}\n\n/**\n * Collects transformative properties in association order.\n *\n * HEIF §6.5.1 says these apply in the order they appear in `ipma`, and requires\n * writers to associate them as clap, irot, imir. Reading the order out of the\n * file rather than hardcoding that sequence costs nothing and makes malformed\n * files render the way other software renders them.\n */\nfunction readTransforms(\n properties: readonly ItemProperty[],\n width: number,\n height: number,\n): TransformOp[] {\n const ops: TransformOp[] = [];\n let currentWidth = width;\n let currentHeight = height;\n\n for (const property of properties) {\n switch (property.type) {\n case 'clap': {\n const crop = resolveCleanAperture(property, currentWidth, currentHeight);\n if (crop) {\n ops.push(crop);\n currentWidth = crop.width;\n currentHeight = crop.height;\n }\n break;\n }\n case 'irot':\n if (property.angle !== 0) {\n ops.push({ kind: 'rotate', angle: property.angle });\n if (property.angle === 90 || property.angle === 270) {\n [currentWidth, currentHeight] = [currentHeight, currentWidth];\n }\n }\n break;\n case 'imir':\n ops.push({ kind: 'mirror', axis: property.axis });\n break;\n default:\n break;\n }\n }\n return ops;\n}\n\n/**\n * Converts a `clap` box's rational centre-relative description into a pixel rect.\n *\n * The box gives cropped width/height as fractions and the offset of the cropped\n * centre from the *uncropped* centre, which is why this is not a plain rect.\n */\nfunction resolveCleanAperture(\n clap: Extract<ItemProperty, { type: 'clap' }>,\n width: number,\n height: number,\n): Extract<TransformOp, { kind: 'crop' }> | undefined {\n if (clap.widthD === 0 || clap.heightD === 0 || clap.horizOffD === 0 || clap.vertOffD === 0) {\n return undefined;\n }\n const cropWidth = Math.round(clap.widthN / clap.widthD);\n const cropHeight = Math.round(clap.heightN / clap.heightD);\n const centreOffsetX = clap.horizOffN / clap.horizOffD;\n const centreOffsetY = clap.vertOffN / clap.vertOffD;\n\n const offsetX = Math.round((width - cropWidth) / 2 + centreOffsetX);\n const offsetY = Math.round((height - cropHeight) / 2 + centreOffsetY);\n\n // A clap that is a no-op, or that describes a region outside the image, is\n // ignored rather than trusted; other decoders do the same.\n if (cropWidth <= 0 || cropHeight <= 0) return undefined;\n if (cropWidth === width && cropHeight === height && offsetX === 0 && offsetY === 0) {\n return undefined;\n }\n if (offsetX < 0 || offsetY < 0 || offsetX + cropWidth > width || offsetY + cropHeight > height) {\n return undefined;\n }\n return { kind: 'crop', width: cropWidth, height: cropHeight, offsetX, offsetY };\n}\n\nfunction applyTransformsToSize(\n width: number,\n height: number,\n transforms: readonly TransformOp[],\n): { displayWidth: number; displayHeight: number } {\n let w = width;\n let h = height;\n for (const op of transforms) {\n if (op.kind === 'crop') {\n w = op.width;\n h = op.height;\n } else if (op.kind === 'rotate' && (op.angle === 90 || op.angle === 270)) {\n [w, h] = [h, w];\n }\n }\n return { displayWidth: w, displayHeight: h };\n}\n\n/** `colr` lives on the primary item, but some encoders put it only on the tiles. */\nfunction readSourceColor(\n primaryProps: readonly ItemProperty[],\n tileProps: readonly ItemProperty[],\n): SourceColor {\n const colr = findProperty(primaryProps, 'colr') ?? findProperty(tileProps, 'colr');\n if (!colr) return null;\n return colr.colorType === 'nclx'\n ? {\n type: 'nclx',\n primaries: colr.primaries,\n transfer: colr.transfer,\n matrix: colr.matrix,\n fullRange: colr.fullRange,\n }\n : { type: 'icc', profile: colr.profile };\n}\n\n/**\n * Reports features present in the file that v0.1 deliberately does not decode.\n *\n * The primary image still comes back; this is how a caller finds out that the\n * alpha channel or gain map they were counting on was dropped, rather than\n * discovering it from a user's bug report.\n */\nfunction collectFeatureWarnings(\n file: HeifFile,\n primaryItemId: number,\n warnings: HeicWarning[],\n): void {\n const seen = new Set<string>();\n const add = (warning: HeicWarning): void => {\n // A gain map is described by both an 'auxl' aux image and a 'tmap' item, so\n // dedupe by code: one ignored feature, one warning.\n if (seen.has(warning.code)) return;\n seen.add(warning.code);\n warnings.push(warning);\n };\n\n const auxTargets = file.references.get('auxl');\n if (auxTargets) {\n for (const [auxItemId, targets] of auxTargets) {\n if (!targets.includes(primaryItemId)) continue;\n const auxType = findProperty(propertiesForItem(file, auxItemId), 'auxC')?.auxType ?? '';\n if (/alpha/i.test(auxType)) {\n add({ code: 'alpha-ignored', message: `Alpha aux image ${auxItemId} ignored` });\n } else if (/depth|disparity/i.test(auxType)) {\n add({ code: 'depth-ignored', message: `Depth aux image ${auxItemId} ignored` });\n } else if (/hdrgainmap|gainmap/i.test(auxType)) {\n add({\n code: 'gain-map-ignored',\n message: `HDR gain map ${auxItemId} ignored; the image decodes as SDR`,\n });\n }\n }\n }\n\n // A 'tmap' item is iOS 18's tone-mapped HDR representation; we decode the SDR\n // base image, which is what a browser would show anyway.\n for (const item of file.items.values()) {\n if (item.itemType === 'tmap') {\n add({\n code: 'gain-map-ignored',\n message: `Tone-map item ${item.itemId} ignored; the image decodes as SDR`,\n });\n break;\n }\n }\n}\n\n/** Item payload for a planned tile. */\nexport function tileData(plan: ImagePlan, tile: PlannedTile): Uint8Array {\n return readItemData(plan.file, tile.itemId);\n}\n","import { HeicAbortError, HeicDecodeError, HeicUnsupportedError } from '../errors.ts';\nimport { hvccToAnnexBPrologue, hvccToCodecString, lengthPrefixedToAnnexB } from '../parser/hvcc.ts';\nimport { tileData, type ImagePlan, type TileGroup } from '../plan.ts';\nimport type { OutputColorSpace } from '../types.ts';\nimport { createCanvas, throwIfAborted } from '../render/canvas.ts';\n\n/**\n * How a VideoDecoder was configured for a tile group.\n *\n * `hvc1` passes the raw hvcC as `description` and submits tile payloads\n * untouched, which is what HEIF already stores. `hev1` is the fallback for\n * environments that reject a description: parameter sets and tile data are\n * rewritten to Annex B start codes.\n */\ninterface ResolvedConfig {\n mode: 'hvc1' | 'hev1';\n config: VideoDecoderConfig;\n /** Annex B parameter sets, prepended to every chunk in 'hev1' mode. */\n prologue?: Uint8Array;\n lengthSize: number;\n}\n\nexport function isWebCodecsAvailable(): boolean {\n return typeof VideoDecoder !== 'undefined' && typeof EncodedVideoChunk !== 'undefined';\n}\n\n/**\n * Picks a working VideoDecoder configuration for a tile group, probing both\n * modes before committing to either.\n */\nasync function resolveConfig(\n group: TileGroup,\n codedWidth: number,\n codedHeight: number,\n): Promise<ResolvedConfig> {\n const lengthSize = group.hvcc.lengthSizeMinusOne + 1;\n const failures: { strategy: string; reason: string }[] = [];\n\n const hvc1: VideoDecoderConfig = {\n codec: group.codec,\n // A fresh copy: VideoDecoderConfig.description is retained by the decoder,\n // and hvcc.raw is a view onto the caller's buffer.\n description: new Uint8Array(group.hvcc.raw),\n codedWidth,\n codedHeight,\n optimizeForLatency: true,\n };\n try {\n const support = await VideoDecoder.isConfigSupported(hvc1);\n if (support.supported) return { mode: 'hvc1', config: support.config ?? hvc1, lengthSize };\n failures.push({ strategy: 'hvc1', reason: 'isConfigSupported returned false' });\n } catch (error) {\n failures.push({ strategy: 'hvc1', reason: String(error) });\n }\n\n const hev1: VideoDecoderConfig = {\n codec: hvccToCodecString(group.hvcc, 'hev1'),\n codedWidth,\n codedHeight,\n optimizeForLatency: true,\n };\n try {\n const support = await VideoDecoder.isConfigSupported(hev1);\n if (support.supported) {\n return {\n mode: 'hev1',\n config: support.config ?? hev1,\n prologue: hvccToAnnexBPrologue(group.hvcc),\n lengthSize,\n };\n }\n failures.push({ strategy: 'hev1', reason: 'isConfigSupported returned false' });\n } catch (error) {\n failures.push({ strategy: 'hev1', reason: String(error) });\n }\n\n throw new HeicUnsupportedError(\n 'No HEVC decoder configuration was accepted',\n failures,\n { strategy: 'webcodecs', codec: group.codec },\n );\n}\n\n/** Builds the chunk bytes to submit for one tile under a resolved configuration. */\nfunction chunkBytes(config: ResolvedConfig, payload: Uint8Array): Uint8Array {\n if (config.mode === 'hvc1') return payload;\n const body = lengthPrefixedToAnnexB(payload, config.lengthSize);\n const prologue = config.prologue!;\n const out = new Uint8Array(prologue.byteLength + body.byteLength);\n out.set(prologue, 0);\n out.set(body, prologue.byteLength);\n return out;\n}\n\n/**\n * Decodes every tile and composites them onto a single canvas.\n *\n * ## The frame-pool deadlock\n *\n * Hardware decoders draw output frames from a small fixed pool, often 8 to 10\n * frames. A `VideoFrame` that has not been `close()`d holds a slot. Submitting\n * 48 tiles and *collecting* the frames to composite after `flush()` exhausts the\n * pool: the decoder stops emitting, `flush()` never resolves, and the decode\n * hangs forever with no error. It fails only on grid images, only on some\n * hardware, which makes it miserable to debug.\n *\n * So each frame is drawn at its grid position and closed inside the output\n * callback, before the callback returns. Frames arrive in submission order, so a\n * counter is enough to map frame to tile.\n */\nexport async function decodeWithWebCodecs(\n plan: ImagePlan,\n colorSpace: OutputColorSpace,\n signal?: AbortSignal,\n): Promise<OffscreenCanvas> {\n if (!isWebCodecsAvailable()) {\n throw new HeicUnsupportedError(\n 'WebCodecs VideoDecoder is not available in this environment',\n [{ strategy: 'webcodecs', reason: 'VideoDecoder is undefined' }],\n { strategy: 'webcodecs' },\n );\n }\n throwIfAborted(signal);\n\n // Sized to the coded image: tiles that overhang the right or bottom edge are\n // clipped by the canvas bounds, so no separate crop pass is needed.\n const canvas = createCanvas(plan.codedWidth, plan.codedHeight);\n const ctx = canvas.getContext('2d', { colorSpace, alpha: false, willReadFrequently: false });\n if (!ctx) {\n throw new HeicDecodeError('Could not get a 2d context for compositing', {\n strategy: 'webcodecs',\n });\n }\n\n for (const group of plan.tileGroups) {\n throwIfAborted(signal);\n await decodeGroup(plan, group, ctx, signal);\n }\n\n return canvas;\n}\n\nasync function decodeGroup(\n plan: ImagePlan,\n group: TileGroup,\n ctx: OffscreenCanvasRenderingContext2D,\n signal?: AbortSignal,\n): Promise<void> {\n const first = plan.tiles[group.tileIndices[0]!]!;\n const config = await resolveConfig(group, first.width, first.height);\n throwIfAborted(signal);\n\n let nextTile = 0;\n let drawn = 0;\n let settle: ((error: Error) => void) | undefined;\n // Resolves only on failure; raced against flush() so a decoder error or an\n // abort surfaces immediately instead of waiting for a flush that never comes.\n const failure = new Promise<never>((_, reject) => {\n settle = reject;\n });\n\n const decoder = new VideoDecoder({\n output: (frame) => {\n try {\n const tile = plan.tiles[group.tileIndices[nextTile++]!];\n if (tile) {\n ctx.drawImage(frame, tile.x, tile.y, tile.width, tile.height);\n drawn++;\n }\n } finally {\n // Always, on every path: a frame left open holds a decoder pool slot.\n frame.close();\n }\n },\n error: (error) => {\n settle?.(\n new HeicDecodeError(`VideoDecoder failed: ${error.message}`, {\n strategy: 'webcodecs',\n codec: config.config.codec,\n }),\n );\n },\n });\n\n const onAbort = (): void => settle?.(new HeicAbortError());\n signal?.addEventListener('abort', onAbort, { once: true });\n\n try {\n // configure() and decode() both throw synchronously when the decoder rejects\n // something, separately from the async error callback. Converting here is\n // what keeps the promise of typed errors: a caller must never see a bare\n // DOMException surface from inside the cascade.\n try {\n decoder.configure(config.config);\n\n for (const tileIndex of group.tileIndices) {\n const tile = plan.tiles[tileIndex]!;\n const bytes = chunkBytes(config, tileData(plan, tile));\n // Every tile is an independent keyframe. The timestamp is the submission\n // index, which makes ordering observable when debugging.\n decoder.decode(\n new EncodedVideoChunk({ type: 'key', timestamp: tileIndex, duration: 0, data: bytes }),\n );\n }\n } catch (error) {\n if (error instanceof HeicAbortError || error instanceof HeicDecodeError) throw error;\n throw new HeicDecodeError(\n `VideoDecoder rejected the stream: ${error instanceof Error ? error.message : String(error)}`,\n { strategy: 'webcodecs', codec: config.config.codec },\n { cause: error },\n );\n }\n\n // flush() is required: without it the decoder is free to hold the last\n // frames indefinitely, and the bottom of the image never arrives.\n await Promise.race([decoder.flush(), failure]);\n\n if (drawn !== group.tileIndices.length) {\n throw new HeicDecodeError(\n `Decoder emitted ${drawn} frames for ${group.tileIndices.length} tiles`,\n { strategy: 'webcodecs', codec: config.config.codec },\n );\n }\n } finally {\n signal?.removeEventListener('abort', onAbort);\n // close() also releases any frame the decoder still holds. Safe to call on\n // an already-closed decoder, so it belongs on the error path too.\n try {\n decoder.close();\n } catch {\n // A decoder that already failed is already closed; nothing to do.\n }\n }\n}\n\n/**\n * Codec strings probed by `probeSupport()`. Deliberately small: Main 8-bit and\n * Main10, which between them cover every HEIC a phone produces. Main Still\n * Picture (profile 3) is what Apple actually writes, so it leads.\n */\nexport const PROBE_CODEC_STRINGS = [\n 'hvc1.3.e.L93.B0', // Main Still Picture, 8-bit — what iPhones write\n 'hvc1.1.6.L93.B0', // Main, 8-bit\n 'hvc1.2.4.L120.B0', // Main10, 10-bit\n];\n\n/** Which of the representative HEVC codec strings this environment accepts. */\nexport async function probeHevcCodecStrings(): Promise<string[]> {\n if (!isWebCodecsAvailable()) return [];\n const supported: string[] = [];\n for (const codec of PROBE_CODEC_STRINGS) {\n try {\n // No description and no decode: isConfigSupported is a cheap capability\n // query, not a decoder instantiation.\n const support = await VideoDecoder.isConfigSupported({\n codec,\n codedWidth: 1920,\n codedHeight: 1080,\n });\n if (support.supported) supported.push(codec);\n } catch {\n // An unparseable codec string throws rather than returning false.\n }\n }\n return supported;\n}\n","import { childBoxes, findBox } from './boxes.ts';\nimport { parseHeif, type HeifFile } from './meta.ts';\nimport { Reader } from './reader.ts';\n\n/**\n * Brands that indicate an ISOBMFF still-image file we might be able to decode.\n *\n * `mif1` and `msf1` are generic HEIF structural brands used by AVIF as well as\n * HEIC, so a match on those alone is not enough to claim the file is HEIC.\n */\nexport const HEIF_BRANDS = new Set([\n 'heic',\n 'heix',\n 'hevc',\n 'hevx',\n 'heim',\n 'heis',\n 'hevm',\n 'hevs',\n 'mif1',\n 'msf1',\n]);\n\n/** Brands that mean HEVC-coded on their own, without consulting the item type. */\nconst UNAMBIGUOUS_HEIC_BRANDS = new Set([\n 'heic',\n 'heix',\n 'hevc',\n 'hevx',\n 'heim',\n 'heis',\n 'hevm',\n 'hevs',\n]);\n\nexport type DetectedCoding = 'hevc' | 'av1' | 'unknown';\n\nexport interface DetectionResult {\n isHeic: boolean;\n /** ftyp major brand, when the file had one. */\n brand?: string | undefined;\n /** item_type of the primary item ('hvc1', 'grid', 'av01', ...). */\n primaryItemType?: string | undefined;\n /** What the primary item is coded with, resolved through any derived item. */\n coding?: DetectedCoding | undefined;\n}\n\n/**\n * Bytes `isHeic` needs from the front of a file. `ftyp` is tiny, but `meta`\n * (which carries the item types that disambiguate `mif1`) follows it and runs to\n * a few KB in Apple files. 64 KB covers every file observed and is still a cheap\n * `blob.slice()` against a 5 MB photo.\n */\nexport const DETECTION_PREFIX_BYTES = 65_536;\n\n/**\n * Identifies a HEIC file from its `ftyp` brands and primary item type.\n *\n * Never consults the filename or the MIME type the browser guessed. Returns a\n * discriminated result rather than a boolean, so a caller holding an AVIF can\n * route it to a decoder that handles AVIF instead of getting a bare `false`.\n *\n * Tolerates a truncated buffer throughout: it is designed to be handed the first\n * `DETECTION_PREFIX_BYTES` of a file, so a failed parse degrades to brand-only\n * detection rather than throwing.\n */\nexport function detectFromBuffer(input: ArrayBuffer | Uint8Array): DetectionResult {\n const source = input instanceof Uint8Array ? input : new Uint8Array(input);\n\n let brands: Set<string>;\n let brand: string;\n try {\n const boxes = childBoxes(new Reader(source), { lenient: true });\n const ftyp = findBox(boxes, 'ftyp');\n if (!ftyp) return { isHeic: false };\n brand = ftyp.body.fourCC();\n brands = new Set([brand]);\n ftyp.body.u32(); // minor_version\n while (ftyp.body.remaining >= 4) brands.add(ftyp.body.fourCC());\n } catch {\n return { isHeic: false };\n }\n\n if (![...brands].some((b) => HEIF_BRANDS.has(b))) return { isHeic: false, brand };\n\n let file: HeifFile | undefined;\n try {\n file = parseHeif(source, { truncated: true });\n } catch {\n file = undefined;\n }\n\n const primaryItemType = file?.items.get(file.primaryItemId)?.itemType;\n const coding = file ? codingOf(file, primaryItemType) : 'unknown';\n\n if (coding === 'av1') return { isHeic: false, brand, primaryItemType, coding };\n if (coding === 'hevc') return { isHeic: true, brand, primaryItemType, coding };\n\n // No usable item type (truncated prefix, or an encoder that omits iinf).\n // Fall back to the brand, which is decisive for everything but mif1/msf1.\n const result: DetectionResult = {\n isHeic: [...brands].some((b) => UNAMBIGUOUS_HEIC_BRANDS.has(b)),\n brand,\n coding: 'unknown',\n };\n if (primaryItemType !== undefined) result.primaryItemType = primaryItemType;\n return result;\n}\n\n/** Resolves a derived item's coding through its first `dimg` reference. */\nfunction codingOf(file: HeifFile, itemType: string | undefined, depth = 0): DetectedCoding {\n if (itemType === 'hvc1' || itemType === 'hev1') return 'hevc';\n if (itemType === 'av01') return 'av1';\n if (depth < 4 && (itemType === 'grid' || itemType === 'iovl' || itemType === 'iden')) {\n const first = file.references.get('dimg')?.get(file.primaryItemId)?.[0];\n if (first !== undefined) return codingOf(file, file.items.get(first)?.itemType, depth + 1);\n }\n return 'unknown';\n}\n","import type { TransformOp } from '../plan.ts';\nimport type { TransformsApplied } from '../types.ts';\nimport { createCanvas } from './canvas.ts';\n\n/**\n * Applies container transforms to a composited canvas, in the order given.\n *\n * Order is taken from the file's `ipma` associations rather than hardcoded (see\n * `readTransforms` in plan.ts). Each op produces a new canvas; the input is\n * released as it goes, so a 48 MP image never holds two full-size canvases plus\n * an intermediate at once.\n */\nexport function applyTransforms(\n source: OffscreenCanvas,\n transforms: readonly TransformOp[],\n colorSpace: PredefinedColorSpace,\n): { canvas: OffscreenCanvas; applied: TransformsApplied } {\n let current = source;\n\n for (const op of transforms) {\n switch (op.kind) {\n case 'crop':\n current = release(current, crop(current, op, colorSpace), source);\n break;\n case 'rotate':\n current = release(current, rotate(current, op.angle, colorSpace), source);\n break;\n case 'mirror':\n current = release(current, mirror(current, op.axis, colorSpace), source);\n break;\n }\n }\n\n return { canvas: current, applied: summarizeTransforms(transforms) };\n}\n\n/**\n * The net effect of a transform list, without rendering anything.\n *\n * Strategies that apply transforms themselves (the browser's native decoder,\n * and any adapter declaring `appliesTransforms`) still have to report what was\n * applied. Deriving it here keeps that report identical to the render path's.\n */\nexport function summarizeTransforms(transforms: readonly TransformOp[]): TransformsApplied {\n const applied: TransformsApplied = { rotation: 0, mirrored: 'none', cropped: false };\n for (const op of transforms) {\n switch (op.kind) {\n case 'crop':\n applied.cropped = true;\n break;\n case 'rotate':\n applied.rotation = ((applied.rotation + op.angle) % 360) as TransformsApplied['rotation'];\n break;\n case 'mirror': {\n const direction = mirrorDirection(op.axis);\n // Two mirrors on the same axis cancel; on different axes they compose\n // into a 180 degree rotation. Tracking that keeps the report honest.\n if (applied.mirrored === 'none') applied.mirrored = direction;\n else if (applied.mirrored === direction) applied.mirrored = 'none';\n else {\n applied.mirrored = 'none';\n applied.rotation = ((applied.rotation + 180) % 360) as TransformsApplied['rotation'];\n }\n break;\n }\n }\n }\n return applied;\n}\n\n/**\n * `imir.axis` semantics, established by measurement rather than by reading.\n *\n * axis = 0 -> mirror **vertically**: top and bottom are swapped\n * axis = 1 -> mirror **horizontally**: left and right are swapped\n *\n * This is the single most commonly inverted detail in HEIF implementations, and\n * it is inverted in the obvious reading of the spec text. ISO/IEC 23008-12\n * describes `axis` as selecting \"a vertical (axis = 0) or horizontal (axis = 1)\n * axis for the mirroring operation\", which reads as naming the *axis of\n * reflection* — and reflecting about a vertical axis swaps left and right, the\n * exact opposite of what decoders actually do. Later wording in the standard\n * instead says the mirroring \"is applied vertically\" for axis 0, which is the\n * behaviour real decoders implement. Widely-copied blog posts follow the first\n * reading and are wrong.\n *\n * So this was measured instead of argued. `tools/inject-property.ts` forges a\n * fixture carrying each axis value, libheif renders it, and the render is\n * compared against an explicit flip of the untransformed image:\n *\n * libheif imir=0 vs top-bottom swap MAE 0 <- exact match\n * libheif imir=0 vs left-right swap MAE 10015.5\n * libheif imir=1 vs left-right swap MAE 0 <- exact match\n * libheif imir=1 vs top-bottom swap MAE 10015.5\n *\n * The fixtures live in test/fixtures/generated/asym-imir-{0,1}.heic and are\n * covered by the cross-strategy consistency test, so an inversion here fails the\n * suite rather than shipping.\n *\n * The names returned are the ones used in `TransformsApplied.mirrored`, in their\n * ordinary web sense: 'horizontal' is a left-right flip (CSS `scaleX(-1)`),\n * 'vertical' is a top-bottom flip.\n */\nfunction mirrorDirection(axis: 0 | 1): 'horizontal' | 'vertical' {\n return axis === 0 ? 'vertical' : 'horizontal';\n}\n\nfunction crop(\n source: OffscreenCanvas,\n op: Extract<TransformOp, { kind: 'crop' }>,\n colorSpace: PredefinedColorSpace,\n): OffscreenCanvas {\n const target = createCanvas(op.width, op.height);\n const ctx = context(target, colorSpace);\n ctx.drawImage(\n source,\n op.offsetX,\n op.offsetY,\n op.width,\n op.height,\n 0,\n 0,\n op.width,\n op.height,\n );\n return target;\n}\n\n/** `angle` is counter-clockwise, as stored in `irot`. */\nfunction rotate(\n source: OffscreenCanvas,\n angle: 90 | 180 | 270,\n colorSpace: PredefinedColorSpace,\n): OffscreenCanvas {\n const swap = angle === 90 || angle === 270;\n const target = createCanvas(\n swap ? source.height : source.width,\n swap ? source.width : source.height,\n );\n const ctx = context(target, colorSpace);\n\n // Canvas rotate() is clockwise for positive angles, so a counter-clockwise\n // irot angle is applied as its negation.\n ctx.translate(target.width / 2, target.height / 2);\n ctx.rotate((-angle * Math.PI) / 180);\n ctx.drawImage(source, -source.width / 2, -source.height / 2);\n return target;\n}\n\nfunction mirror(\n source: OffscreenCanvas,\n axis: 0 | 1,\n colorSpace: PredefinedColorSpace,\n): OffscreenCanvas {\n const target = createCanvas(source.width, source.height);\n const ctx = context(target, colorSpace);\n if (mirrorDirection(axis) === 'horizontal') {\n ctx.translate(source.width, 0);\n ctx.scale(-1, 1);\n } else {\n ctx.translate(0, source.height);\n ctx.scale(1, -1);\n }\n ctx.drawImage(source, 0, 0);\n return target;\n}\n\nfunction context(\n canvas: OffscreenCanvas,\n colorSpace: PredefinedColorSpace,\n): OffscreenCanvasRenderingContext2D {\n const ctx = canvas.getContext('2d', { colorSpace, alpha: false });\n if (!ctx) throw new Error('Could not get a 2d context');\n return ctx;\n}\n\n/**\n * Frees an intermediate canvas once its successor exists.\n *\n * Setting the dimensions to zero is the portable way to release canvas backing\n * store; the original source canvas is left alone because the caller owns it.\n */\nfunction release(\n previous: OffscreenCanvas,\n next: OffscreenCanvas,\n original: OffscreenCanvas,\n): OffscreenCanvas {\n if (previous !== original) {\n previous.width = 0;\n previous.height = 0;\n }\n return next;\n}\n","import { probeNativeSupport } from './decoders/native.ts';\nimport { isWebCodecsAvailable, probeHevcCodecStrings } from './decoders/webcodecs.ts';\nimport type { SupportReport } from './types.ts';\n\n/**\n * Reports what this environment can decode, before anything is downloaded.\n *\n * The point is to let a caller decide whether to preload the wasm fallback:\n * `recommended === 'wasm'` means the ~1.2 MB codec will be needed, and knowing\n * that at page load is much better than discovering it when a user drops a file.\n *\n * Cheap: `isConfigSupported` is a capability query, not a decoder, and the native\n * probe decodes a 471-byte inline image.\n */\nexport async function probeSupport(): Promise<SupportReport> {\n const [native, hevcCodecStrings] = await Promise.all([\n probeNativeSupport(),\n probeHevcCodecStrings(),\n ]);\n\n const webcodecs = isWebCodecsAvailable() && hevcCodecStrings.length > 0;\n\n const recommended: SupportReport['recommended'] = native\n ? 'native'\n : webcodecs\n ? 'webcodecs'\n : 'wasm';\n\n return { native, webcodecs, hevcCodecStrings, recommended };\n}\n"],"mappings":"6cAAA,IAAAA,GAAA,GAAAC,GAAAD,GAAA,oBAAAE,EAAA,oBAAAC,EAAA,cAAAC,EAAA,mBAAAC,EAAA,yBAAAC,EAAA,eAAAC,GAAA,iBAAAC,EAAA,yBAAAC,GAAA,yBAAAC,EAAA,sBAAAC,EAAA,WAAAC,GAAA,2BAAAC,EAAA,qBAAAC,GAAA,cAAAC,EAAA,cAAAC,EAAA,eAAAC,EAAA,iBAAAC,GAAA,sBAAAC,EAAA,aAAAC,EAAA,iBAAAC,EAAA,2BAAAC,KCaO,SAASC,EAAWC,EAAyB,CAClD,OAAO,IAAI,KAAK,CAAYA,CAAM,EAAG,CAAE,KAAM,YAAa,CAAC,CAC7D,CCQO,IAAMC,EAAN,cAAwB,KAAM,CAC1B,QAET,YAAYC,EAAiBC,EAA4B,CAAC,EAAGC,EAAwB,CACnF,IAAMC,EAASC,GAAcH,CAAO,EACpC,MAAME,EAAS,GAAGH,CAAO,KAAKG,CAAM,IAAMH,EAASE,CAAO,EAC1D,KAAK,KAAO,YACZ,KAAK,QAAUD,CACjB,CACF,EAGaI,EAAN,cAA6BN,CAAU,CAC5C,YAAYC,EAAiBC,EAA4B,CAAC,EAAGC,EAAwB,CACnF,MAAMF,EAASC,EAASC,CAAO,EAC/B,KAAK,KAAO,gBACd,CACF,EAGaI,EAAN,cAAmCP,CAAU,CAEzC,SAET,YACEC,EACAO,EAAgE,CAAC,EACjEN,EAA4B,CAAC,EAC7BC,EACA,CACA,IAAMM,EAAUD,EAAS,IAAKE,GAAM,GAAGA,EAAE,QAAQ,KAAKA,EAAE,MAAM,EAAE,EAAE,KAAK,IAAI,EAC3E,MAAMD,EAAU,GAAGR,CAAO,KAAKQ,CAAO,IAAMR,EAASC,EAASC,CAAO,EACrE,KAAK,KAAO,uBACZ,KAAK,SAAWK,CAClB,CACF,EAGaG,EAAN,cAA8BX,CAAU,CAC7C,YAAYC,EAAiBC,EAA4B,CAAC,EAAGC,EAAwB,CACnF,MAAMF,EAASC,EAASC,CAAO,EAC/B,KAAK,KAAO,iBACd,CACF,EAGaS,EAAN,cAA6BZ,CAAU,CAC5C,YAAYC,EAAU,iBAAkBC,EAA4B,CAAC,EAAGC,EAAwB,CAC9F,MAAMF,EAASC,EAASC,CAAO,EAC/B,KAAK,KAAO,gBACd,CACF,EAEA,SAASE,GAAcH,EAAmC,CACxD,IAAMW,EAAkB,CAAC,EACzB,OAAW,CAACC,EAAKC,CAAK,IAAK,OAAO,QAAQb,CAAO,EAC3Ca,IAAU,QAAWF,EAAM,KAAK,GAAGC,CAAG,IAAIC,CAAK,EAAE,EAEvD,OAAOF,EAAM,KAAK,GAAG,CACvB,CCxEO,SAASG,EAAaC,EAAeC,EAAiC,CAC3E,GAAI,OAAO,gBAAoB,IAC7B,MAAM,IAAIC,EACR,sEACA,CAAC,CACH,EAEF,OAAO,IAAI,gBAAgBF,EAAOC,CAAM,CAC1C,CAEO,SAASE,EAAeC,EAA4B,CACzD,GAAIA,GAAQ,QAAS,MAAM,IAAIC,CACjC,CCJA,IAAIC,GAAuB,GAuB3B,eAAsBC,GACpBC,EACAC,EACAC,EACwB,CACxB,GAAI,OAAO,kBAAsB,IAC/B,MAAO,CAAE,OAAQ,cAAe,OAAQ,oCAAqC,EAE/E,GAAIJ,GACF,MAAO,CAAE,OAAQ,cAAe,OAAQ,wCAAyC,EAEnFK,EAAeD,CAAM,EAErB,IAAIE,EACJ,GAAI,CACFA,EAAS,MAAM,kBAAkBJ,CAAI,CACvC,MAAQ,CAEN,OAAAF,GAAuB,GAChB,CAAE,OAAQ,cAAe,OAAQ,qCAAsC,CAChF,CAIA,GAFAK,EAAeD,CAAM,EAEjB,CAACG,GAAgBD,EAAQH,CAAI,EAAG,CAClC,IAAMK,EAAM,GAAGF,EAAO,KAAK,IAAIA,EAAO,MAAM,GAE5C,OAAAA,EAAO,MAAM,EACN,CACL,OAAQ,cACR,OAAQ,YAAYE,CAAG,cAAcL,EAAK,YAAY,IAAIA,EAAK,aAAa,EAC9E,CACF,CAEA,MAAO,CAAE,OAAQ,KAAM,OAAAG,CAAO,CAChC,CAEA,SAASC,GAAgBD,EAAqBH,EAA0B,CACtE,GAAM,CAAE,aAAAM,EAAc,cAAAC,CAAc,EAAIP,EAClCQ,EAAUL,EAAO,QAAUG,GAAgBH,EAAO,SAAWI,EAC7DE,EAAUN,EAAO,QAAUI,GAAiBJ,EAAO,SAAWG,EACpE,OAAOE,GAAWC,CACpB,CAQA,eAAsBC,IAAuC,CAC3D,GAAI,OAAO,kBAAsB,IAAa,MAAO,GACrD,GAAI,CACF,IAAMC,EAAQC,GAAaC,EAAgB,EACrCV,EAAS,MAAM,kBAAkBW,EAAWH,CAAK,CAAC,EAClDI,EAAKZ,EAAO,QAAUa,IAAmBb,EAAO,SAAWc,GACjE,OAAAd,EAAO,MAAM,EACNY,CACT,MAAQ,CACN,MAAO,EACT,CACF,CAEA,SAASH,GAAaM,EAA2B,CAC/C,IAAMC,EAAS,KAAKD,CAAK,EACnBE,EAAM,IAAI,WAAWD,EAAO,MAAM,EACxC,QAASE,EAAI,EAAGA,EAAIF,EAAO,OAAQE,IAAKD,EAAIC,CAAC,EAAIF,EAAO,WAAWE,CAAC,EACpE,OAAOD,CACT,CASO,IAAMJ,GAAkB,EAClBC,GAAmB,EACnBJ,GACX,unBC5GK,IAAMS,EAAN,MAAMC,CAAO,CACT,MACQ,KAER,KAED,IAAM,EAEd,YAAYC,EAAkCC,EAAa,EAAGC,EAAqB,CACjF,IAAMC,EAAKH,aAAkB,WAAaA,EAAS,IAAI,WAAWA,CAAM,EAClEI,EAAQD,EAAG,WAAaF,EACxBI,EAASH,GAAcC,EAAG,WAAaF,EAC7C,GAAIA,EAAa,GAAKI,EAAS,GAAKJ,EAAaI,EAASF,EAAG,WAC3D,MAAM,IAAIG,EAAe,6CAA8C,CACrE,OAAQL,CACV,CAAC,EAEH,KAAK,MAAQ,IAAI,WAAWE,EAAG,OAAQC,EAAOC,CAAM,EACpD,KAAK,KAAO,IAAI,SAASF,EAAG,OAAQC,EAAOC,CAAM,EACjD,KAAK,KAAOD,CACd,CAEA,IAAI,QAAiB,CACnB,OAAO,KAAK,MAAM,UACpB,CAEA,IAAI,QAAiB,CACnB,OAAO,KAAK,GACd,CAGA,IAAI,gBAAyB,CAC3B,OAAO,KAAK,KAAO,KAAK,GAC1B,CAEA,IAAI,WAAoB,CACtB,OAAO,KAAK,OAAS,KAAK,GAC5B,CAEA,IAAI,KAAe,CACjB,OAAO,KAAK,KAAO,KAAK,MAC1B,CAEA,KAAKG,EAAkB,CACrB,KAAK,QAAQ,EAAGA,CAAE,EAClB,KAAK,IAAMA,CACb,CAEA,KAAKC,EAAqB,CACxB,KAAK,QAAQA,CAAK,EAClB,KAAK,KAAOA,CACd,CAOA,QAAQA,EAAeC,EAAK,KAAK,IAAW,CAC1C,GAAI,CAAC,OAAO,SAASD,CAAK,GAAKA,EAAQ,GAAK,CAAC,OAAO,SAASC,CAAE,GAAKA,EAAK,EACvE,MAAM,IAAIH,EAAe,yBAA0B,CAAE,OAAQ,KAAK,KAAO,KAAK,GAAI,CAAC,EAErF,GAAIG,EAAKD,EAAQ,KAAK,OACpB,MAAM,IAAIF,EACR,WAAWE,CAAK,aAAaC,CAAE,gBAAgB,KAAK,MAAM,eAC1D,CAAE,OAAQ,KAAK,KAAOA,CAAG,CAC3B,CAEJ,CAEA,IAAa,CACX,YAAK,QAAQ,CAAC,EACP,KAAK,KAAK,SAAS,KAAK,KAAK,CACtC,CAEA,KAAc,CACZ,KAAK,QAAQ,CAAC,EACd,IAAMC,EAAQ,KAAK,KAAK,UAAU,KAAK,GAAG,EAC1C,YAAK,KAAO,EACLA,CACT,CAEA,KAAc,CACZ,KAAK,QAAQ,CAAC,EACd,IAAMA,EACH,KAAK,KAAK,SAAS,KAAK,GAAG,GAAK,GAChC,KAAK,KAAK,SAAS,KAAK,IAAM,CAAC,GAAK,EACrC,KAAK,KAAK,SAAS,KAAK,IAAM,CAAC,EACjC,YAAK,KAAO,EACLA,IAAU,CACnB,CAEA,KAAc,CACZ,KAAK,QAAQ,CAAC,EACd,IAAMA,EAAQ,KAAK,KAAK,UAAU,KAAK,GAAG,EAC1C,YAAK,KAAO,EACLA,IAAU,CACnB,CAOA,KAAc,CACZ,KAAK,QAAQ,CAAC,EACd,IAAMA,EAAQ,KAAK,KAAK,aAAa,KAAK,GAAG,EAE7C,GADA,KAAK,KAAO,EACRA,EAAQ,OAAO,OAAO,gBAAgB,EACxC,MAAM,IAAIJ,EAAe,8CAA+C,CACtE,OAAQ,KAAK,KAAO,KAAK,IAAM,CACjC,CAAC,EAEH,OAAO,OAAOI,CAAK,CACrB,CAGA,KAAKC,EAA2B,CAC9B,OAAQA,EAAW,CACjB,IAAK,GACH,MAAO,GACT,IAAK,GACH,OAAO,KAAK,GAAG,EACjB,IAAK,GACH,OAAO,KAAK,IAAI,EAClB,IAAK,GACH,OAAO,KAAK,IAAI,EAClB,IAAK,GACH,OAAO,KAAK,IAAI,EAClB,QACE,MAAM,IAAIL,EAAe,8BAA8BK,CAAS,SAAU,CACxE,OAAQ,KAAK,KAAO,KAAK,GAC3B,CAAC,CACL,CACF,CAGA,QAAiB,CACf,KAAK,QAAQ,CAAC,EACd,IAAIC,EAAM,GACV,QAASC,EAAI,EAAGA,EAAI,EAAGA,IAAK,CAC1B,IAAMC,EAAO,KAAK,KAAK,SAAS,KAAK,IAAMD,CAAC,EAC5CD,GAAOE,GAAQ,IAAQA,GAAQ,IAAO,OAAO,aAAaA,CAAI,EAAI,MAAMA,EAAK,SAAS,EAAE,EAAE,SAAS,EAAG,GAAG,CAAC,EAC5G,CACA,YAAK,KAAO,EACLF,CACT,CAGA,SAAkB,CAChB,IAAMR,EAAQ,KAAK,IACnB,KAAO,KAAK,IAAM,KAAK,QAAU,KAAK,MAAM,KAAK,GAAG,IAAM,GAAG,KAAK,MAClE,IAAMW,EAAM,KAAK,MAAM,SAASX,EAAO,KAAK,GAAG,EAC/C,OAAI,KAAK,IAAM,KAAK,QAAQ,KAAK,MAC1B,IAAI,YAAY,EAAE,OAAOW,CAAG,CACrC,CAGA,MAAMP,EAA2B,CAC/B,KAAK,QAAQA,CAAK,EAClB,IAAMI,EAAM,KAAK,MAAM,SAAS,KAAK,IAAK,KAAK,IAAMJ,CAAK,EAC1D,YAAK,KAAOA,EACLI,CACT,CAGA,KAAKJ,EAA2B,CAC9B,OAAO,IAAI,WAAW,KAAK,MAAMA,CAAK,CAAC,CACzC,CAGA,IAAIA,EAAuB,CACzB,KAAK,QAAQA,CAAK,EAClB,IAAMQ,EAAQ,IAAIjB,EAAO,KAAK,MAAO,KAAK,IAAKS,CAAK,EACpD,YAAK,KAAOA,EACLQ,CACT,CAGA,UAAmB,CACjB,OAAO,IAAIjB,EAAO,KAAK,MAAO,KAAK,IAAK,KAAK,SAAS,CACxD,CACF,EAQO,SAASkB,EAAkBC,EAA+B,CAC/D,IAAMC,EAAUD,EAAO,GAAG,EACpBE,EAAQF,EAAO,IAAI,EACzB,MAAO,CAAE,QAAAC,EAAS,MAAAC,CAAM,CAC1B,CC3MO,IAAMC,GAAU,GACVC,GAAU,GACVC,GAAU,GAoCjBC,GAAkB,GAClBC,GAAsB,IAErB,SAASC,EAAUC,EAAsB,CAC9C,IAAMC,EAAMD,EAAO,SAAS,EAAE,MAExBE,EAAuBF,EAAO,GAAG,EACvC,GAAIE,IAAyB,EAE3B,MAAM,IAAIC,EACR,sDAAsDD,CAAoB,GAC1E,CAAE,IAAK,MAAO,CAChB,EAGF,IAAME,EAAcJ,EAAO,GAAG,EACxBK,EAAuBD,GAAe,EAAK,EAC3CE,EAAmBF,GAAe,EAAK,EACvCG,EAAoBH,EAAc,GAElCI,EAAmCR,EAAO,IAAI,EAC9CS,EAAkCT,EAAO,KAAK,CAAC,EAC/CU,EAAkBV,EAAO,GAAG,EAE5BW,EAA4BX,EAAO,IAAI,EAAI,KAC3CY,EAAkBZ,EAAO,GAAG,EAAI,EAChCa,EAAeb,EAAO,GAAG,EAAI,EAC7Bc,EAAqBd,EAAO,GAAG,EAAI,EACnCe,EAAuBf,EAAO,GAAG,EAAI,EAErCgB,EAAehB,EAAO,IAAI,EAC1BiB,EAAWjB,EAAO,GAAG,EACrBkB,EAAqBD,GAAY,EAAK,EACtCE,EAAqBF,GAAY,EAAK,EACtCG,EAAoBH,GAAY,EAAK,EACrCI,EAAqBJ,EAAW,EAEhCK,EAActB,EAAO,GAAG,EAC9B,GAAIsB,EAAczB,GAChB,MAAM,IAAIM,EAAe,iBAAiBmB,CAAW,cAAe,CAAE,IAAK,MAAO,CAAC,EAGrF,IAAMC,EAAyB,CAAC,EAChC,QAASC,EAAI,EAAGA,EAAIF,EAAaE,IAAK,CACpC,IAAMC,EAAOzB,EAAO,GAAG,EACjB0B,GAAsBD,GAAQ,EAAK,KAAU,EAC7CE,EAAcF,EAAO,GACrBG,GAAW5B,EAAO,IAAI,EAC5B,GAAI4B,GAAW9B,GACb,MAAM,IAAIK,EAAe,uBAAuByB,EAAQ,aAAc,CAAE,IAAK,MAAO,CAAC,EAEvF,IAAMC,GAAsB,CAAC,EAC7B,QAASC,GAAI,EAAGA,GAAIF,GAAUE,KAAK,CACjC,IAAMC,GAAgB/B,EAAO,IAAI,EACjC6B,GAAM,KAAK7B,EAAO,MAAM+B,EAAa,CAAC,CACxC,CACAR,EAAO,KAAK,CAAE,kBAAAG,EAAmB,YAAAC,EAAa,MAAAE,EAAM,CAAC,CACvD,CAEA,MAAO,CACL,qBAAA3B,EACA,oBAAAG,EACA,gBAAAC,EACA,kBAAAC,EACA,iCAAAC,EACA,gCAAAC,EACA,gBAAAC,EACA,0BAAAC,EACA,gBAAAC,EACA,aAAAC,EACA,mBAAAC,EACA,qBAAAC,EACA,aAAAC,EACA,kBAAAE,EACA,kBAAAC,EACA,iBAAAC,EACA,mBAAAC,EACA,OAAAE,EACA,IAAAtB,CACF,CACF,CAEA,IAAM+B,GAAuB,CAAC,GAAI,IAAK,IAAK,GAAG,EAQxC,SAASC,EAAkBC,EAAYC,EAA0B,OAAgB,CAEtF,IAAMC,EAAU,GADFJ,GAAqBE,EAAK,mBAAmB,GAAK,EACxC,GAAGA,EAAK,iBAAiB,GAK3CG,EAASC,GAAcJ,EAAK,gCAAgC,EAAE,SAAS,EAAE,EAGzEK,EAAQ,GADDL,EAAK,kBAAoB,EAAI,IAAM,GAC3B,GAAGA,EAAK,eAAe,GAItCM,EAAkB,CAAC,GAAGN,EAAK,+BAA+B,EAChE,KAAOM,EAAgB,OAAS,GAAKA,EAAgBA,EAAgB,OAAS,CAAC,IAAM,GACnFA,EAAgB,IAAI,EAEtB,IAAMC,EAAcD,EAAgB,IAAKE,GAAMA,EAAE,SAAS,EAAE,EAAE,SAAS,EAAG,GAAG,EAAE,YAAY,CAAC,EAE5F,MAAO,CAACP,EAAQC,EAASC,EAAQE,EAAO,GAAGE,CAAW,EAAE,KAAK,GAAG,CAClE,CAGO,SAASH,GAAcK,EAAuB,CACnD,IAAIC,EAAID,IAAU,EAClB,OAAAC,GAAMA,EAAI,aAAe,EAAOA,IAAM,EAAK,WAC3CA,GAAMA,EAAI,YAAe,EAAOA,IAAM,EAAK,UAC3CA,GAAMA,EAAI,YAAe,EAAOA,IAAM,EAAK,UAC3CA,GAAMA,EAAI,WAAe,EAAOA,IAAM,EAAK,SAC3CA,EAAKA,IAAM,GAAOA,GAAK,GAChBA,IAAM,CACf,CAGO,SAASC,GAAaX,EAAoB,CAC/C,OAAOA,EAAK,mBAAqB,CACnC,CAMO,SAASY,EAAqBZ,EAAwB,CAE3D,IAAMa,EADS,CAACrD,GAASC,GAASC,EAAO,EAEtC,QAASoD,GAASd,EAAK,OAAO,OAAQ,GAAM,EAAE,cAAgBc,CAAI,CAAC,EACnE,QAASC,GAAMA,EAAE,KAAK,EAErBC,EAAQ,EACZ,QAAWC,KAAQJ,EAAUG,GAAS,EAAIC,EAAK,WAE/C,IAAMC,EAAM,IAAI,WAAWF,CAAK,EAC5BG,EAAM,EACV,QAAWF,KAAQJ,EACjBK,EAAI,IAAI,CAAC,EAAM,EAAM,EAAM,CAAI,EAAGC,CAAG,EACrCA,GAAO,EACPD,EAAI,IAAID,EAAME,CAAG,EACjBA,GAAOF,EAAK,WAEd,OAAOC,CACT,CAMO,SAASE,EAAuBC,EAAkBC,EAAgC,CACvF,GAAIA,EAAa,GAAKA,EAAa,EACjC,MAAM,IAAIrD,EAAe,2BAA2BqD,CAAU,GAAI,CAAE,IAAK,MAAO,CAAC,EAInF,IAAMJ,EAAM,IAAI,WAAWG,EAAK,WAAaE,GAAcF,EAAMC,CAAU,GAAK,EAAIA,EAAW,EAC3FE,EAAO,EACPC,EAAQ,EACZ,KAAOD,EAAOF,GAAcD,EAAK,YAAY,CAC3C,IAAIK,EAAa,EACjB,QAASpC,EAAI,EAAGA,EAAIgC,EAAYhC,IAAKoC,EAAcA,GAAc,EAAKL,EAAKG,EAAOlC,CAAC,EAEnF,GADAkC,GAAQF,EACJI,EAAa,GAAKF,EAAOE,EAAaL,EAAK,WAC7C,MAAM,IAAIpD,EAAe,wDAAyD,CAChF,OAAQuD,CACV,CAAC,EAEHN,EAAI,IAAI,CAAC,EAAM,EAAM,EAAM,CAAI,EAAGO,CAAK,EACvCA,GAAS,EACTP,EAAI,IAAIG,EAAK,SAASG,EAAMA,EAAOE,CAAU,EAAGD,CAAK,EACrDA,GAASC,EACTF,GAAQE,CACV,CACA,OAAOR,EAAI,SAAS,EAAGO,CAAK,CAC9B,CAEA,SAASF,GAAcF,EAAkBC,EAA4B,CACnE,IAAIE,EAAO,EACPG,EAAQ,EACZ,KAAOH,EAAOF,GAAcD,EAAK,YAAY,CAC3C,IAAIK,EAAa,EACjB,QAAS,EAAI,EAAG,EAAIJ,EAAY,IAAKI,EAAcA,GAAc,EAAKL,EAAKG,EAAO,CAAC,EAEnF,GADAA,GAAQF,EAAaI,EACjBA,EAAa,GAAKF,EAAOH,EAAK,WAAY,MAC9CM,GACF,CACA,OAAOA,CACT,CCzOO,IAAMC,GAAgB,GAOhBC,GAAoB,MA8B1B,SAAUC,EAAUC,EAAgBC,EAAgC,CAAC,EAAmB,CAC7F,GAAM,CAAE,MAAAC,EAAQ,EAAG,QAAAC,EAAU,EAAM,EACjC,OAAOF,GAAY,SAAW,CAAE,MAAOA,EAAS,QAAS,EAAM,EAAIA,EACrE,GAAIC,EAAQL,GACV,MAAM,IAAIO,EAAe,2BAA2BP,EAAa,GAAI,CACnE,OAAQG,EAAO,cACjB,CAAC,EAGH,IAAIK,EAAQ,EACZ,KAAOL,EAAO,WAAa,GAAG,CAC5B,GAAI,EAAEK,EAAQP,GACZ,MAAM,IAAIM,EAAe,aAAaN,EAAiB,8BAA+B,CACpF,OAAQE,EAAO,cACjB,CAAC,EAGH,IAAMM,EAASN,EAAO,eAChBO,EAAQP,EAAO,OACjBQ,EAAOR,EAAO,IAAI,EAChBS,EAAOT,EAAO,OAAO,EACvBU,EAAa,EAUjB,GARIF,IAAS,GACXA,EAAOR,EAAO,IAAI,EAClBU,EAAa,IACJF,IAAS,IAElBA,EAAOR,EAAO,OAASO,GAGrBC,EAAOE,EAAY,CACrB,GAAIP,EAAS,OACb,MAAM,IAAIC,EAAe,YAAYI,CAAI,wBAAwBE,CAAU,eAAgB,CACzF,OAAAJ,EACA,IAAKG,CACP,CAAC,CACH,CACA,GAAIF,EAAQC,EAAOR,EAAO,OAAQ,CAChC,GAAIG,EAAS,OACb,MAAM,IAAIC,EACR,eAAeG,EAAQC,EAAOR,EAAO,MAAM,4BAC3C,CAAE,OAAAM,EAAQ,IAAKG,CAAK,CACtB,CACF,CAEA,IAAME,EAAcH,EAAOE,EACrBE,EAAOZ,EAAO,IAAIW,CAAW,EACnC,KAAM,CAAE,KAAAF,EAAM,OAAAH,EAAQ,KAAAE,EAAM,WAAAE,EAAY,KAAAE,CAAK,EAI7CZ,EAAO,KAAKO,EAAQC,CAAI,CAC1B,CACF,CAGO,SAASK,EAAWb,EAAgBC,EAAgC,CAAC,EAAU,CACpF,MAAO,CAAC,GAAGF,EAAUC,EAAQC,CAAO,CAAC,CACvC,CAGO,SAASa,EAAQC,EAAuBN,EAA+B,CAC5E,OAAOM,EAAM,KAAMC,GAAQA,EAAI,OAASP,CAAI,CAC9C,CAGO,SAASQ,GAAUF,EAAuBN,EAAqB,CACpE,OAAOM,EAAM,OAAQC,GAAQA,EAAI,OAASP,CAAI,CAChD,CCxGA,IAAMS,EAAY,MACZC,GAAuB,KACvBC,GAAiB,KACjBC,GAA4B,IAC5BC,GAA0B,KAiBhC,SAASC,GAAUC,EAAoB,CACrC,IAAMC,EAAID,EAAI,KACR,CAAE,QAAAE,EAAS,MAAAC,CAAM,EAAIC,EAAkBH,CAAC,EACxCI,GAAUF,EAAQ,KAAU,EAElC,GAAID,GAAW,EAAG,CAChB,IAAMI,EAASJ,IAAY,EAAID,EAAE,IAAI,EAAIA,EAAE,IAAI,EACzCM,EAAkBN,EAAE,IAAI,EACxBO,EAAWP,EAAE,OAAO,EACpBQ,EAAWR,EAAE,QAAQ,EACrBS,EAAiB,CAAE,OAAAJ,EAAQ,gBAAAC,EAAiB,SAAAC,EAAU,SAAAC,EAAU,OAAAJ,CAAO,EAC7E,OAAIG,IAAa,SAAQE,EAAK,YAAcT,EAAE,QAAQ,GAC/CS,CACT,CAIA,IAAMJ,EAASL,EAAE,IAAI,EACfM,EAAkBN,EAAE,IAAI,EACxBQ,EAAWR,EAAE,QAAQ,EACrBU,EAAcV,EAAE,QAAQ,EAC9B,MAAO,CAAE,OAAAK,EAAQ,gBAAAC,EAAiB,SAAU,GAAI,SAAAE,EAAU,YAAAE,EAAa,OAAAN,CAAO,CAChF,CAEA,SAASO,GAAUZ,EAAiC,CAClD,IAAMC,EAAID,EAAI,KACR,CAAE,QAAAE,CAAQ,EAAIE,EAAkBH,CAAC,EACjCY,EAAaX,IAAY,EAAID,EAAE,IAAI,EAAIA,EAAE,IAAI,EACnD,GAAIY,EAAanB,EACf,MAAM,IAAIoB,EAAe,iBAAiBD,CAAU,SAAU,CAAE,IAAK,MAAO,CAAC,EAG/E,IAAME,EAAQ,IAAI,IAGdC,EAAO,EACX,QAAWC,KAASC,EAAUjB,EAAE,SAAS,CAAC,EAAG,CAC3C,GAAIgB,EAAM,OAAS,OAAQ,SAC3B,GAAI,EAAED,EAAOtB,EAAW,MACxB,IAAMgB,EAAOX,GAAUkB,CAAK,EAC5BF,EAAM,IAAIL,EAAK,OAAQA,CAAI,CAC7B,CACA,OAAOK,CACT,CAoBA,SAASI,GAAUnB,EAAqC,CACtD,IAAMC,EAAID,EAAI,KACR,CAAE,QAAAE,CAAQ,EAAIE,EAAkBH,CAAC,EAEjCmB,EAAYnB,EAAE,GAAG,EACjBoB,EAAcD,GAAa,EAAK,GAChCE,EAAaF,EAAY,GACzBG,EAAWtB,EAAE,GAAG,EAChBuB,EAAkBD,GAAY,EAAK,GAEnCE,EAAYvB,IAAY,GAAKA,IAAY,EAAIqB,EAAW,GAAO,EAE/DG,EAAYxB,EAAU,EAAID,EAAE,IAAI,EAAIA,EAAE,IAAI,EAChD,GAAIyB,EAAYhC,EACd,MAAM,IAAIoB,EAAe,iBAAiBY,CAAS,SAAU,CAAE,IAAK,MAAO,CAAC,EAG9E,IAAMC,EAAY,IAAI,IACtB,QAASC,EAAI,EAAGA,EAAIF,EAAWE,IAAK,CAClC,IAAMtB,EAASJ,EAAU,EAAID,EAAE,IAAI,EAAIA,EAAE,IAAI,EAEzC4B,EAAqB,GACrB3B,IAAY,GAAKA,IAAY,KAC/B2B,EAAqB5B,EAAE,IAAI,EAAI,IAGjCA,EAAE,IAAI,EACN,IAAM6B,EAAa7B,EAAE,KAAKuB,CAAc,EAElCO,EAAc9B,EAAE,IAAI,EAC1B,GAAI8B,EAAcpC,GAChB,MAAM,IAAImB,EAAe,QAAQR,CAAM,aAAayB,CAAW,WAAY,CACzE,IAAK,OACL,OAAAzB,CACF,CAAC,EAGH,IAAM0B,EAAwB,CAAC,EAC/B,QAASC,EAAI,EAAGA,EAAIF,EAAaE,IAAK,EAC/B/B,IAAY,GAAKA,IAAY,IAAMuB,EAAY,GAAGxB,EAAE,KAAKwB,CAAS,EACvE,IAAMS,EAASjC,EAAE,KAAKoB,CAAU,EAC1Bc,EAASlC,EAAE,KAAKqB,CAAU,EAChCU,EAAQ,KAAK,CAAE,OAAAE,EAAQ,OAAAC,CAAO,CAAC,CACjC,CAEAR,EAAU,IAAIrB,EAAQ,CAAE,OAAAA,EAAQ,mBAAAuB,EAAoB,WAAAC,EAAY,QAAAE,CAAQ,CAAC,CAC3E,CACA,OAAOL,CACT,CA8FA,SAASS,GAAcC,EAAwB,CAC7C,IAAMC,EAAID,EAAI,KACd,OAAQA,EAAI,KAAM,CAChB,IAAK,OACH,OAAAE,EAAkBD,CAAC,EACZ,CAAE,KAAM,OAAQ,MAAOA,EAAE,IAAI,EAAG,OAAQA,EAAE,IAAI,CAAE,EAEzD,IAAK,OACH,MAAO,CAAE,KAAM,OAAQ,KAAME,EAAUF,CAAC,CAAE,EAC5C,IAAK,OAEH,MAAO,CAAE,KAAM,OAAQ,OADPA,EAAE,GAAG,EAAI,GAAQ,EACJ,EAE/B,IAAK,OAEH,MAAO,CAAE,KAAM,OAAQ,KADTA,EAAE,GAAG,EAAI,CACK,EAE9B,IAAK,OAAQ,CACX,IAAMG,EAAYH,EAAE,OAAO,EAC3B,GAAIG,IAAc,OAAQ,CACxB,IAAMC,EAAYJ,EAAE,IAAI,EAClBK,EAAWL,EAAE,IAAI,EACjBM,EAASN,EAAE,IAAI,EACfO,GAAaP,EAAE,GAAG,EAAI,OAAU,EACtC,MAAO,CAAE,KAAM,OAAQ,UAAW,OAAQ,UAAAI,EAAW,SAAAC,EAAU,OAAAC,EAAQ,UAAAC,CAAU,CACnF,CACA,OAAIJ,IAAc,QAAUA,IAAc,OACjC,CAAE,KAAM,OAAQ,UAAW,MAAO,QAASH,EAAE,KAAKA,EAAE,SAAS,CAAE,EAEjE,CAAE,KAAM,UAAW,QAAS,QAAQG,CAAS,EAAG,CACzD,CACA,IAAK,OAAQ,CACXF,EAAkBD,CAAC,EACnB,IAAMQ,EAAcR,EAAE,GAAG,EACnBS,EAA2B,CAAC,EAClC,QAASC,EAAI,EAAGA,EAAIF,EAAaE,IAAKD,EAAe,KAAKT,EAAE,GAAG,CAAC,EAChE,MAAO,CAAE,KAAM,OAAQ,eAAAS,CAAe,CACxC,CACA,IAAK,OACH,MAAO,CACL,KAAM,OACN,OAAQT,EAAE,IAAI,EACd,OAAQA,EAAE,IAAI,EACd,QAASA,EAAE,IAAI,EACf,QAASA,EAAE,IAAI,EACf,UAAWA,EAAE,IAAI,EAAI,EACrB,UAAWA,EAAE,IAAI,EACjB,SAAUA,EAAE,IAAI,EAAI,EACpB,SAAUA,EAAE,IAAI,CAClB,EACF,IAAK,OACH,OAAAC,EAAkBD,CAAC,EACZ,CAAE,KAAM,OAAQ,QAASA,EAAE,QAAQ,CAAE,EAE9C,QACE,MAAO,CAAE,KAAM,UAAW,QAASD,EAAI,IAAK,CAChD,CACF,CAQA,SAASY,GAAUZ,EAAUa,EAAgD,CAC3E,IAAM,EAAIb,EAAI,KACR,CAAE,QAAAc,EAAS,MAAAC,CAAM,EAAIb,EAAkB,CAAC,EACxCc,GAAaD,EAAQ,KAAU,EAE/BE,EAAa,EAAE,IAAI,EACzB,GAAIA,EAAaC,EACf,MAAM,IAAIC,EAAe,iBAAiBF,CAAU,WAAY,CAAE,IAAK,MAAO,CAAC,EAGjF,QAASN,EAAI,EAAGA,EAAIM,EAAYN,IAAK,CACnC,IAAMS,EAASN,IAAY,EAAI,EAAE,IAAI,EAAI,EAAE,IAAI,EACzCO,EAAmB,EAAE,GAAG,EAC9B,GAAIA,EAAmBC,GACrB,MAAM,IAAIH,EAAe,QAAQC,CAAM,aAAaC,CAAgB,cAAe,CACjF,IAAK,OACL,OAAAD,CACF,CAAC,EAKH,IAAMG,EAAsC,CAAC,EAC7C,QAASC,EAAI,EAAGA,EAAIH,EAAkBG,IACpC,GAAIR,EAAW,CACb,IAAMS,EAAQ,EAAE,IAAI,EACpBF,EAAa,KAAK,CAAE,WAAYE,EAAQ,SAAY,EAAG,MAAOA,EAAQ,KAAO,CAAC,CAChF,KAAO,CACL,IAAMA,EAAQ,EAAE,GAAG,EACnBF,EAAa,KAAK,CAAE,WAAYE,EAAQ,OAAU,EAAG,MAAOA,EAAQ,GAAK,CAAC,CAC5E,CAIF,IAAMC,EAAWb,EAAK,IAAIO,CAAM,EAC5BM,EAAUA,EAAS,KAAK,GAAGH,CAAY,EACtCV,EAAK,IAAIO,EAAQG,CAAY,CACpC,CACF,CAQA,SAASI,GAAU3B,EAA0B,CAC3C,IAAM4B,EAAWC,EAAW7B,EAAI,IAAI,EAC9B8B,EAAOC,EAAQH,EAAU,MAAM,EAE/BI,EAA6B,CAAC,EACpC,GAAIF,EACF,QAAWG,KAASC,EAAUJ,EAAK,IAAI,EAAG,CACxC,GAAIE,EAAW,QAAUG,GACvB,MAAM,IAAIhB,EAAe,wBAAwBgB,EAAc,cAAe,CAC5E,IAAK,MACP,CAAC,EAEHH,EAAW,KAAKjC,GAAckC,CAAK,CAAC,CACtC,CAGF,IAAMV,EAAe,IAAI,IACzB,QAAWa,KAAQC,GAAUT,EAAU,MAAM,EAAGhB,GAAUwB,EAAMb,CAAY,EAE5E,MAAO,CAAE,WAAAS,EAAY,aAAAT,CAAa,CACpC,CASA,SAASe,GAAUtC,EAA0B,CAC3C,IAAMC,EAAID,EAAI,KACR,CAAE,QAAAc,CAAQ,EAAIZ,EAAkBD,CAAC,EACjCsC,EAAuB,IAAI,IAEjC,QAAWN,KAASC,EAAUjC,EAAE,SAAS,CAAC,EAAG,CAC3C,IAAMuC,EAAKP,EAAM,KACXQ,EAAa3B,IAAY,EAAI0B,EAAG,IAAI,EAAIA,EAAG,IAAI,EAC/CE,EAAiBF,EAAG,IAAI,EAC9B,GAAIE,EAAiBC,GACnB,MAAM,IAAIxB,EAAe,QAAQsB,CAAU,aAAaC,CAAc,cAAe,CACnF,IAAKT,EAAM,KACX,OAAQQ,CACV,CAAC,EAEH,IAAMG,EAAsB,CAAC,EAC7B,QAASjC,EAAI,EAAGA,EAAI+B,EAAgB/B,IAClCiC,EAAU,KAAK9B,IAAY,EAAI0B,EAAG,IAAI,EAAIA,EAAG,IAAI,CAAC,EAGpD,IAAIK,EAASN,EAAK,IAAIN,EAAM,IAAI,EAC3BY,GAAQN,EAAK,IAAIN,EAAM,KAAOY,EAAS,IAAI,GAAM,EACtDA,EAAO,IAAIJ,EAAYG,CAAS,CAClC,CAEA,OAAOL,CACT,CAiCO,SAASO,EAAUC,EAAiCC,EAAwB,CAAC,EAAa,CAC/F,IAAMC,EAASF,aAAiB,WAAaA,EAAQ,IAAI,WAAWA,CAAK,EACnEG,EAAO,IAAIC,EAAOF,CAAM,EACxBG,EAAQvB,EAAWqB,EAAM,CAAE,QAASF,EAAQ,YAAc,EAAK,CAAC,EAEhEK,EAAOtB,EAAQqB,EAAO,MAAM,EAClC,GAAI,CAACC,EAAM,MAAM,IAAIlC,EAAe,6CAA8C,CAAE,OAAQ,CAAE,CAAC,EAC/F,IAAMmC,EAAaD,EAAK,KAAK,OAAO,EAC9BE,EAAeF,EAAK,KAAK,IAAI,EAC7BG,EAA6B,CAAC,EACpC,KAAOH,EAAK,KAAK,WAAa,GAAGG,EAAiB,KAAKH,EAAK,KAAK,OAAO,CAAC,EAEzE,IAAMI,EAAO1B,EAAQqB,EAAO,MAAM,EAClC,GAAI,CAACK,EACH,MAAM,IAAItC,EAAe,uCAAwC,CAAE,MAAOmC,CAAW,CAAC,EAExFpD,EAAkBuD,EAAK,IAAI,EAC3B,IAAMC,EAAe7B,EAAW4B,EAAK,KAAM,CAAC,EAEtCE,EAAO5B,EAAQ2B,EAAc,MAAM,EACrCE,EAAc,GAMlB,GALID,IACFzD,EAAkByD,EAAK,IAAI,EAC3BA,EAAK,KAAK,IAAI,EACdC,EAAcD,EAAK,KAAK,OAAO,GAE7BC,GAAeA,IAAgB,OACjC,MAAM,IAAIzC,EAAe,oBAAoByC,CAAW,qBAAsB,CAC5E,MAAON,CACT,CAAC,EAGH,IAAIO,EAAgB,EACdC,EAAO/B,EAAQ2B,EAAc,MAAM,EACzC,GAAII,EAAM,CACR,GAAM,CAAE,QAAAhD,CAAQ,EAAIZ,EAAkB4D,EAAK,IAAI,EAC/CD,EAAgB/C,IAAY,EAAIgD,EAAK,KAAK,IAAI,EAAIA,EAAK,KAAK,IAAI,CAClE,CAEA,IAAMC,EAAOhC,EAAQ2B,EAAc,MAAM,EACnCM,EAAQD,EAAOE,GAAUF,CAAI,EAAI,IAAI,IAErCG,EAAOnC,EAAQ2B,EAAc,MAAM,EACnCS,EAAYD,EAAOE,GAAUF,CAAI,EAAI,IAAI,IAEzCG,EAAOtC,EAAQ2B,EAAc,MAAM,EACnCY,EAAiBD,EAAO1C,GAAU0C,CAAI,EAAI,CAAE,WAAY,CAAC,EAAG,aAAc,IAAI,GAAM,EAEpFE,EAAOxC,EAAQ2B,EAAc,MAAM,EACnCc,EAAaD,EAAOjC,GAAUiC,CAAI,EAAK,IAAI,IAE3CE,EAAO1C,EAAQ2B,EAAc,MAAM,EACnCgB,EAAWD,EAAOA,EAAK,KAAK,KAAKA,EAAK,KAAK,SAAS,EAAI,OAI9D,GAAIZ,IAAkB,GACpB,OAAW,CAACc,EAAIC,CAAI,IAAKZ,EACvB,GAAIY,EAAK,WAAa,QAAUA,EAAK,WAAa,QAAUA,EAAK,WAAa,OAAQ,CACpFf,EAAgBc,EAChB,KACF,EAIJ,MAAO,CACL,WAAArB,EACA,aAAAC,EACA,iBAAAC,EACA,cAAAK,EACA,YAAAD,EACA,MAAAI,EACA,UAAAG,EACA,eAAAG,EACA,WAAAE,EACA,SAAAE,EACA,OAAAzB,CACF,CACF,CAOO,SAAS4B,EAAkBC,EAAgB1D,EAAgC,CAChF,IAAMG,EAAeuD,EAAK,eAAe,aAAa,IAAI1D,CAAM,GAAK,CAAC,EAChE2D,EAAsB,CAAC,EAE7B,QAAWC,KAAezD,EAAc,CACtC,GAAIyD,EAAY,QAAU,EAAG,SAC7B,IAAMC,EAAWH,EAAK,eAAe,WAAWE,EAAY,MAAQ,CAAC,EACrE,GAAI,CAACC,EACH,MAAM,IAAI9D,EACR,QAAQC,CAAM,wBAAwB4D,EAAY,KAAK,oBAAoBF,EAAK,eAAe,WAAW,MAAM,GAChH,CAAE,OAAA1D,EAAQ,IAAK,MAAO,CACxB,EAIF,GAAI4D,EAAY,WAAaC,EAAS,OAAS,UAC7C,MAAM,IAAI9D,EACR,QAAQC,CAAM,6CAA6C6D,EAAS,OAAO,IAC3E,CAAE,OAAA7D,EAAQ,IAAK6D,EAAS,OAAQ,CAClC,EAEFF,EAAI,KAAKE,CAAQ,CACnB,CACA,OAAOF,CACT,CAGO,SAASG,EACdlD,EACAmD,EACgD,CAChD,OAAOnD,EAAW,KAAMoD,GAAMA,EAAE,OAASD,CAAI,CAC/C,CASO,SAASE,EAAaP,EAAgB1D,EAA4B,CACvE,IAAMkE,EAAWR,EAAK,UAAU,IAAI1D,CAAM,EAC1C,GAAI,CAACkE,EACH,MAAM,IAAInE,EAAe,0BAA0BC,CAAM,GAAI,CAAE,OAAAA,EAAQ,IAAK,MAAO,CAAC,EAGtF,IAAMwD,EAAOE,EAAK,MAAM,IAAI1D,CAAM,EAC5BmE,EAAU,CAAE,OAAAnE,EAAQ,SAAUwD,GAAM,SAAU,IAAK,MAAO,EAE5DY,EACJ,OAAQF,EAAS,mBAAoB,CACnC,IAAK,GACHE,EAAYV,EAAK,OACjB,MACF,IAAK,GACH,GAAI,CAACA,EAAK,SACR,MAAM,IAAI3D,EACR,QAAQC,CAAM,oDACdmE,CACF,EAEFC,EAAYV,EAAK,SACjB,MACF,IAAK,GACH,MAAM,IAAI3D,EACR,QAAQC,CAAM,oEACdmE,CACF,EACF,QACE,MAAM,IAAIpE,EACR,QAAQC,CAAM,qCAAqCkE,EAAS,kBAAkB,GAC9EC,CACF,CACJ,CAGA,IAAIE,EAAQ,EACZ,QAAWC,KAAUJ,EAAS,QAAS,CACrC,IAAMK,EAAQL,EAAS,WAAaI,EAAO,OAErCE,EAASF,EAAO,SAAW,EAAIF,EAAU,WAAaG,EAAQD,EAAO,OAC3E,GAAIC,EAAQ,GAAKC,EAAS,GAAKD,EAAQC,EAASJ,EAAU,WACxD,MAAM,IAAIrE,EACR,QAAQC,CAAM,YAAYuE,CAAK,KAAKA,EAAQC,CAAM,oBAAoBJ,EAAU,UAAU,kBAC1FD,CACF,EAEFE,GAASG,CACX,CAEA,GAAIN,EAAS,QAAQ,SAAW,EAAG,CACjC,IAAMI,EAASJ,EAAS,QAAQ,CAAC,EAC3BK,EAAQL,EAAS,WAAaI,EAAO,OAC3C,OAAOF,EAAU,SAASG,EAAOA,EAAQF,CAAK,CAChD,CAEA,IAAMV,EAAM,IAAI,WAAWU,CAAK,EAC5BI,EAAM,EACV,QAAWH,KAAUJ,EAAS,QAAS,CACrC,IAAMK,EAAQL,EAAS,WAAaI,EAAO,OACrCE,EAASF,EAAO,SAAW,EAAIF,EAAU,WAAaG,EAAQD,EAAO,OAC3EX,EAAI,IAAIS,EAAU,SAASG,EAAOA,EAAQC,CAAM,EAAGC,CAAG,EACtDA,GAAOD,CACT,CACA,OAAOb,CACT,CCzmBO,IAAMe,GAAY,KAwBlB,SAASC,GAAiBC,EAA0D,CACzF,IAAMC,EAAI,IAAIC,EAAOF,CAAO,EACtBG,EAAUF,EAAE,GAAG,EACrB,GAAIE,IAAY,EACd,MAAM,IAAIC,EAAe,4BAA4BD,CAAO,GAAI,CAAE,SAAU,MAAO,CAAC,EAGtF,IAAME,GADQJ,EAAE,GAAG,EACS,KAAU,EAChCK,EAAOL,EAAE,GAAG,EAAI,EAChBM,EAAUN,EAAE,GAAG,EAAI,EACnBO,EAAcH,EAAaJ,EAAE,IAAI,EAAIA,EAAE,IAAI,EAC3CQ,EAAeJ,EAAaJ,EAAE,IAAI,EAAIA,EAAE,IAAI,EAClD,MAAO,CAAE,KAAAK,EAAM,QAAAC,EAAS,YAAAC,EAAa,aAAAC,CAAa,CACpD,CAWO,SAASC,EACdC,EACAC,EACAC,EAA0B,CAAC,EACX,CAChB,IAAMb,EAAUc,EAAaH,EAAMC,CAAM,EACnC,CAAE,KAAAN,EAAM,QAAAC,EAAS,YAAAC,EAAa,aAAAC,CAAa,EAAIV,GAAiBC,CAAO,EAEvEe,EAAcJ,EAAK,WAAW,IAAI,MAAM,GAAG,IAAIC,CAAM,GAAK,CAAC,EACjE,GAAIG,EAAY,SAAW,EACzB,MAAM,IAAIX,EAAe,aAAaQ,CAAM,iCAAkC,CAC5E,OAAAA,EACA,SAAU,MACZ,CAAC,EAKH,IAAMI,EAAWV,EAAOC,EACxB,GAAIS,IAAaD,EAAY,OAC3B,MAAM,IAAIX,EACR,aAAaQ,CAAM,aAAaN,CAAI,IAAIC,CAAO,MAAMS,CAAQ,2BAA2BD,EAAY,MAAM,GAC1G,CAAE,OAAAH,EAAQ,SAAU,MAAO,CAC7B,EAEF,GAAII,EAAWlB,GACb,MAAM,IAAIM,EAAe,aAAaQ,CAAM,aAAaI,CAAQ,eAAelB,EAAS,IAAK,CAC5F,OAAAc,EACA,SAAU,MACZ,CAAC,EAKH,IAAIK,EAAQT,EACRU,EAAST,EACPU,EAAOC,EAAaC,EAAkBV,EAAMC,CAAM,EAAG,MAAM,EACjE,OAAIO,IAASA,EAAK,QAAUX,GAAeW,EAAK,SAAWV,KACzDI,EAAS,KAAK,CACZ,KAAM,0BACN,QAAS,yBAAyBL,CAAW,IAAIC,CAAY,sBAAsBU,EAAK,KAAK,IAAIA,EAAK,MAAM,cAC9G,CAAC,EACDF,EAAQE,EAAK,MACbD,EAASC,EAAK,QAGT,CAAE,KAAAb,EAAM,QAAAC,EAAS,YAAaU,EAAO,aAAcC,EAAQ,YAAAH,CAAY,CAChF,CClFO,IAAMO,GAAmB,MAqDzB,SAASC,EAAWC,EAA4C,CACrE,IAAMC,EAAOC,EAAUF,CAAK,EACtBG,EAA0B,CAAC,EAE3BC,EAAgBH,EAAK,cACrBI,EAAOJ,EAAK,MAAM,IAAIG,CAAa,EACzC,GAAI,CAACC,EACH,MAAM,IAAIC,EAAe,gBAAgBF,CAAa,4BAA6B,CACjF,MAAOH,EAAK,WACZ,OAAQG,CACV,CAAC,EAGH,IAAMG,EAASF,EAAK,WAAa,OAKjC,GAAI,CAACE,GAAUF,EAAK,WAAa,QAAUA,EAAK,WAAa,OAC3D,MAAM,IAAIG,EACR,sBAAsBH,EAAK,QAAQ,kCACnC,CAAC,EACD,CAAE,MAAOJ,EAAK,WAAY,SAAUI,EAAK,SAAU,OAAQD,CAAc,CAC3E,EAGF,IAAMK,EAAeC,EAAkBT,EAAMG,CAAa,EAEpDO,EAAuB,CAAC,EAC1BC,EACAC,EAEJ,GAAIN,EAAQ,CACV,IAAMO,EAAOC,EAASd,EAAMG,EAAeD,CAAQ,EACnDS,EAAaE,EAAK,YAClBD,EAAcC,EAAK,aAEnB,IAAME,EAAiBN,EAAkBT,EAAMa,EAAK,YAAY,CAAC,CAAE,EAC7DG,EAAYC,EAAaF,EAAgB,MAAM,EACrD,GAAI,CAACC,EACH,MAAM,IAAIX,EAAe,aAAaQ,EAAK,YAAY,CAAC,CAAC,eAAgB,CACvE,OAAQA,EAAK,YAAY,CAAC,CAC5B,CAAC,EAGH,OAAW,CAACK,EAAOC,CAAM,IAAKN,EAAK,YAAY,QAAQ,EAAG,CAGxD,IAAMO,EAAOH,EAAaR,EAAkBT,EAAMmB,CAAM,EAAG,MAAM,GAAKH,EACtEN,EAAM,KAAK,CACT,OAAAS,EACA,EAAID,EAAQL,EAAK,QAAWG,EAAU,MACtC,EAAG,KAAK,MAAME,EAAQL,EAAK,OAAO,EAAIG,EAAU,OAChD,MAAOI,EAAK,MACZ,OAAQA,EAAK,MACf,CAAC,CACH,CACF,KAAO,CACL,IAAMA,EAAOH,EAAaT,EAAc,MAAM,EAC9C,GAAI,CAACY,EACH,MAAM,IAAIf,EAAe,gBAAgBF,CAAa,eAAgB,CACpE,OAAQA,CACV,CAAC,EAEHQ,EAAaS,EAAK,MAClBR,EAAcQ,EAAK,OACnBV,EAAM,KAAK,CAAE,OAAQP,EAAe,EAAG,EAAG,EAAG,EAAG,MAAOiB,EAAK,MAAO,OAAQA,EAAK,MAAO,CAAC,CAC1F,CAEA,GAAIT,GAAc,GAAKC,GAAe,EACpC,MAAM,IAAIP,EAAe,gCAAgCM,CAAU,IAAIC,CAAW,GAAI,CACpF,OAAQT,CACV,CAAC,EAEH,GAAIQ,EAAaC,EAAcf,GAC7B,MAAM,IAAIU,EACR,YAAYI,CAAU,IAAIC,CAAW,eAAef,EAAgB,eACpE,CAAC,EACD,CAAE,OAAQM,CAAc,CAC1B,EAGF,IAAMkB,EAAaC,GAAmBtB,EAAMU,EAAOR,CAAQ,EACrDqB,EAAaC,GAAehB,EAAcG,EAAYC,CAAW,EACjE,CAAE,aAAAa,EAAc,cAAAC,CAAc,EAAIC,GACtChB,EACAC,EACAW,CACF,EAGMK,EADOX,EAAaT,EAAc,MAAM,GAEtC,eAAe,CAAC,GAAKqB,GAAaR,EAAW,CAAC,EAAG,IAAI,EAE7D,OAAAS,GAAuB9B,EAAMG,EAAeD,CAAQ,EAE7C,CACL,KAAAF,EACA,cAAAG,EACA,OAAAG,EACA,WAAAK,EACA,YAAAC,EACA,aAAAa,EACA,cAAAC,EACA,MAAAhB,EACA,WAAAW,EACA,WAAAE,EACA,SAAAK,EACA,YAAaG,GAAgBvB,EAAcC,EAAkBT,EAAMU,EAAM,CAAC,EAAG,MAAM,CAAC,EACpF,SAAAR,CACF,CACF,CAUA,SAASoB,GACPtB,EACAU,EACAR,EACa,CACb,IAAM8B,EAAS,IAAI,IAEnB,OAAW,CAACd,EAAOe,CAAI,IAAKvB,EAAM,QAAQ,EAAG,CAE3C,IAAMwB,GADelC,EAAK,eAAe,aAAa,IAAIiC,EAAK,MAAM,GAAK,CAAC,GAC1C,KAC9BE,GAAMnC,EAAK,eAAe,WAAWmC,EAAE,MAAQ,CAAC,GAAG,OAAS,MAC/D,EACA,GAAI,CAACD,EACH,MAAM,IAAI7B,EAAe,QAAQ4B,EAAK,MAAM,wBAAyB,CAAE,OAAQA,EAAK,MAAO,CAAC,EAG9F,IAAIG,EAAQJ,EAAO,IAAIE,EAAY,KAAK,EACxC,GAAI,CAACE,EAAO,CACV,IAAMC,EAAWrC,EAAK,eAAe,WAAWkC,EAAY,MAAQ,CAAC,EACrE,GAAIG,GAAU,OAAS,OACrB,MAAM,IAAIhC,EAAe,YAAY6B,EAAY,KAAK,kBAAmB,CACvE,OAAQD,EAAK,MACf,CAAC,EAEHG,EAAQ,CACN,YAAaF,EAAY,MACzB,KAAMG,EAAS,KACf,MAAOC,EAAkBD,EAAS,IAAI,EACtC,YAAa,CAAC,CAChB,EACAL,EAAO,IAAIE,EAAY,MAAOE,CAAK,CACrC,CACAA,EAAM,YAAY,KAAKlB,CAAK,CAC9B,CAEA,IAAMqB,EAAS,CAAC,GAAGP,EAAO,OAAO,CAAC,EAClC,GAAIO,EAAO,SAAW,EACpB,MAAM,IAAIlC,EAAe,8CAA+C,CAAC,CAAC,EAE5E,OAAIkC,EAAO,OAAS,GAClBrC,EAAS,KAAK,CACZ,KAAM,qBACN,QAAS,aAAaqC,EAAO,MAAM,kDAAkDA,EAAO,MAAM,SACpG,CAAC,EAEIA,CACT,CAUA,SAASf,GACPgB,EACAC,EACAC,EACe,CACf,IAAMC,EAAqB,CAAC,EACxBC,EAAeH,EACfI,EAAgBH,EAEpB,QAAWL,KAAYG,EACrB,OAAQH,EAAS,KAAM,CACrB,IAAK,OAAQ,CACX,IAAMS,EAAOC,GAAqBV,EAAUO,EAAcC,CAAa,EACnEC,IACFH,EAAI,KAAKG,CAAI,EACbF,EAAeE,EAAK,MACpBD,EAAgBC,EAAK,QAEvB,KACF,CACA,IAAK,OACCT,EAAS,QAAU,IACrBM,EAAI,KAAK,CAAE,KAAM,SAAU,MAAON,EAAS,KAAM,CAAC,GAC9CA,EAAS,QAAU,IAAMA,EAAS,QAAU,OAC9C,CAACO,EAAcC,CAAa,EAAI,CAACA,EAAeD,CAAY,IAGhE,MACF,IAAK,OACHD,EAAI,KAAK,CAAE,KAAM,SAAU,KAAMN,EAAS,IAAK,CAAC,EAChD,MACF,QACE,KACJ,CAEF,OAAOM,CACT,CAQA,SAASI,GACPC,EACAP,EACAC,EACoD,CACpD,GAAIM,EAAK,SAAW,GAAKA,EAAK,UAAY,GAAKA,EAAK,YAAc,GAAKA,EAAK,WAAa,EACvF,OAEF,IAAMC,EAAY,KAAK,MAAMD,EAAK,OAASA,EAAK,MAAM,EAChDE,EAAa,KAAK,MAAMF,EAAK,QAAUA,EAAK,OAAO,EACnDG,EAAgBH,EAAK,UAAYA,EAAK,UACtCI,EAAgBJ,EAAK,SAAWA,EAAK,SAErCK,EAAU,KAAK,OAAOZ,EAAQQ,GAAa,EAAIE,CAAa,EAC5DG,EAAU,KAAK,OAAOZ,EAASQ,GAAc,EAAIE,CAAa,EAIpE,GAAI,EAAAH,GAAa,GAAKC,GAAc,IAChC,EAAAD,IAAcR,GAASS,IAAeR,GAAUW,IAAY,GAAKC,IAAY,IAG7E,EAAAD,EAAU,GAAKC,EAAU,GAAKD,EAAUJ,EAAYR,GAASa,EAAUJ,EAAaR,GAGxF,MAAO,CAAE,KAAM,OAAQ,MAAOO,EAAW,OAAQC,EAAY,QAAAG,EAAS,QAAAC,CAAQ,CAChF,CAEA,SAAS3B,GACPc,EACAC,EACAnB,EACiD,CACjD,IAAIgC,EAAId,EACJe,EAAId,EACR,QAAWe,KAAMlC,EACXkC,EAAG,OAAS,QACdF,EAAIE,EAAG,MACPD,EAAIC,EAAG,QACEA,EAAG,OAAS,WAAaA,EAAG,QAAU,IAAMA,EAAG,QAAU,OAClE,CAACF,EAAGC,CAAC,EAAI,CAACA,EAAGD,CAAC,GAGlB,MAAO,CAAE,aAAcA,EAAG,cAAeC,CAAE,CAC7C,CAGA,SAASzB,GACPvB,EACAkD,EACa,CACb,IAAMC,EAAO1C,EAAaT,EAAc,MAAM,GAAKS,EAAayC,EAAW,MAAM,EACjF,OAAKC,EACEA,EAAK,YAAc,OACtB,CACE,KAAM,OACN,UAAWA,EAAK,UAChB,SAAUA,EAAK,SACf,OAAQA,EAAK,OACb,UAAWA,EAAK,SAClB,EACA,CAAE,KAAM,MAAO,QAASA,EAAK,OAAQ,EATvB,IAUpB,CASA,SAAS7B,GACP9B,EACAG,EACAD,EACM,CACN,IAAM0D,EAAO,IAAI,IACXC,EAAOC,GAA+B,CAGtCF,EAAK,IAAIE,EAAQ,IAAI,IACzBF,EAAK,IAAIE,EAAQ,IAAI,EACrB5D,EAAS,KAAK4D,CAAO,EACvB,EAEMC,EAAa/D,EAAK,WAAW,IAAI,MAAM,EAC7C,GAAI+D,EACF,OAAW,CAACC,EAAWC,CAAO,IAAKF,EAAY,CAC7C,GAAI,CAACE,EAAQ,SAAS9D,CAAa,EAAG,SACtC,IAAM+D,EAAUjD,EAAaR,EAAkBT,EAAMgE,CAAS,EAAG,MAAM,GAAG,SAAW,GACjF,SAAS,KAAKE,CAAO,EACvBL,EAAI,CAAE,KAAM,gBAAiB,QAAS,mBAAmBG,CAAS,UAAW,CAAC,EACrE,mBAAmB,KAAKE,CAAO,EACxCL,EAAI,CAAE,KAAM,gBAAiB,QAAS,mBAAmBG,CAAS,UAAW,CAAC,EACrE,sBAAsB,KAAKE,CAAO,GAC3CL,EAAI,CACF,KAAM,mBACN,QAAS,gBAAgBG,CAAS,oCACpC,CAAC,CAEL,CAKF,QAAWG,KAAQnE,EAAK,MAAM,OAAO,EACnC,GAAImE,EAAK,WAAa,OAAQ,CAC5BN,EAAI,CACF,KAAM,mBACN,QAAS,iBAAiBM,EAAK,MAAM,oCACvC,CAAC,EACD,KACF,CAEJ,CAGO,SAASC,GAASC,EAAiBpC,EAA+B,CACvE,OAAOqC,EAAaD,EAAK,KAAMpC,EAAK,MAAM,CAC5C,CCrYO,SAASsC,GAAgC,CAC9C,OAAO,OAAO,aAAiB,KAAe,OAAO,kBAAsB,GAC7E,CAMA,eAAeC,GACbC,EACAC,EACAC,EACyB,CACzB,IAAMC,EAAaH,EAAM,KAAK,mBAAqB,EAC7CI,EAAmD,CAAC,EAEpDC,EAA2B,CAC/B,MAAOL,EAAM,MAGb,YAAa,IAAI,WAAWA,EAAM,KAAK,GAAG,EAC1C,WAAAC,EACA,YAAAC,EACA,mBAAoB,EACtB,EACA,GAAI,CACF,IAAMI,EAAU,MAAM,aAAa,kBAAkBD,CAAI,EACzD,GAAIC,EAAQ,UAAW,MAAO,CAAE,KAAM,OAAQ,OAAQA,EAAQ,QAAUD,EAAM,WAAAF,CAAW,EACzFC,EAAS,KAAK,CAAE,SAAU,OAAQ,OAAQ,kCAAmC,CAAC,CAChF,OAASG,EAAO,CACdH,EAAS,KAAK,CAAE,SAAU,OAAQ,OAAQ,OAAOG,CAAK,CAAE,CAAC,CAC3D,CAEA,IAAMC,EAA2B,CAC/B,MAAOC,EAAkBT,EAAM,KAAM,MAAM,EAC3C,WAAAC,EACA,YAAAC,EACA,mBAAoB,EACtB,EACA,GAAI,CACF,IAAMI,EAAU,MAAM,aAAa,kBAAkBE,CAAI,EACzD,GAAIF,EAAQ,UACV,MAAO,CACL,KAAM,OACN,OAAQA,EAAQ,QAAUE,EAC1B,SAAUE,EAAqBV,EAAM,IAAI,EACzC,WAAAG,CACF,EAEFC,EAAS,KAAK,CAAE,SAAU,OAAQ,OAAQ,kCAAmC,CAAC,CAChF,OAASG,EAAO,CACdH,EAAS,KAAK,CAAE,SAAU,OAAQ,OAAQ,OAAOG,CAAK,CAAE,CAAC,CAC3D,CAEA,MAAM,IAAII,EACR,6CACAP,EACA,CAAE,SAAU,YAAa,MAAOJ,EAAM,KAAM,CAC9C,CACF,CAGA,SAASY,GAAWC,EAAwBC,EAAiC,CAC3E,GAAID,EAAO,OAAS,OAAQ,OAAOC,EACnC,IAAMC,EAAOC,EAAuBF,EAASD,EAAO,UAAU,EACxDI,EAAWJ,EAAO,SAClBK,EAAM,IAAI,WAAWD,EAAS,WAAaF,EAAK,UAAU,EAChE,OAAAG,EAAI,IAAID,EAAU,CAAC,EACnBC,EAAI,IAAIH,EAAME,EAAS,UAAU,EAC1BC,CACT,CAkBA,eAAsBC,GACpBC,EACAC,EACAC,EAC0B,CAC1B,GAAI,CAACxB,EAAqB,EACxB,MAAM,IAAIa,EACR,8DACA,CAAC,CAAE,SAAU,YAAa,OAAQ,2BAA4B,CAAC,EAC/D,CAAE,SAAU,WAAY,CAC1B,EAEFY,EAAeD,CAAM,EAIrB,IAAME,EAASC,EAAaL,EAAK,WAAYA,EAAK,WAAW,EACvDM,EAAMF,EAAO,WAAW,KAAM,CAAE,WAAAH,EAAY,MAAO,GAAO,mBAAoB,EAAM,CAAC,EAC3F,GAAI,CAACK,EACH,MAAM,IAAIC,EAAgB,6CAA8C,CACtE,SAAU,WACZ,CAAC,EAGH,QAAW3B,KAASoB,EAAK,WACvBG,EAAeD,CAAM,EACrB,MAAMM,GAAYR,EAAMpB,EAAO0B,EAAKJ,CAAM,EAG5C,OAAOE,CACT,CAEA,eAAeI,GACbR,EACApB,EACA0B,EACAJ,EACe,CACf,IAAMO,EAAQT,EAAK,MAAMpB,EAAM,YAAY,CAAC,CAAE,EACxCa,EAAS,MAAMd,GAAcC,EAAO6B,EAAM,MAAOA,EAAM,MAAM,EACnEN,EAAeD,CAAM,EAErB,IAAIQ,EAAW,EACXC,EAAQ,EACRC,EAGEC,EAAU,IAAI,QAAe,CAACC,EAAGC,IAAW,CAChDH,EAASG,CACX,CAAC,EAEKC,EAAU,IAAI,aAAa,CAC/B,OAASC,GAAU,CACjB,GAAI,CACF,IAAMC,EAAOlB,EAAK,MAAMpB,EAAM,YAAY8B,GAAU,CAAE,EAClDQ,IACFZ,EAAI,UAAUW,EAAOC,EAAK,EAAGA,EAAK,EAAGA,EAAK,MAAOA,EAAK,MAAM,EAC5DP,IAEJ,QAAE,CAEAM,EAAM,MAAM,CACd,CACF,EACA,MAAQ9B,GAAU,CAChByB,IACE,IAAIL,EAAgB,wBAAwBpB,EAAM,OAAO,GAAI,CAC3D,SAAU,YACV,MAAOM,EAAO,OAAO,KACvB,CAAC,CACH,CACF,CACF,CAAC,EAEK0B,EAAU,IAAYP,IAAS,IAAIQ,CAAgB,EACzDlB,GAAQ,iBAAiB,QAASiB,EAAS,CAAE,KAAM,EAAK,CAAC,EAEzD,GAAI,CAKF,GAAI,CACFH,EAAQ,UAAUvB,EAAO,MAAM,EAE/B,QAAW4B,KAAazC,EAAM,YAAa,CACzC,IAAMsC,EAAOlB,EAAK,MAAMqB,CAAS,EAC3BC,EAAQ9B,GAAWC,EAAQ8B,GAASvB,EAAMkB,CAAI,CAAC,EAGrDF,EAAQ,OACN,IAAI,kBAAkB,CAAE,KAAM,MAAO,UAAWK,EAAW,SAAU,EAAG,KAAMC,CAAM,CAAC,CACvF,CACF,CACF,OAASnC,EAAO,CACd,MAAIA,aAAiBiC,GAAkBjC,aAAiBoB,EAAuBpB,EACzE,IAAIoB,EACR,qCAAqCpB,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,GAC3F,CAAE,SAAU,YAAa,MAAOM,EAAO,OAAO,KAAM,EACpD,CAAE,MAAON,CAAM,CACjB,CACF,CAMA,GAFA,MAAM,QAAQ,KAAK,CAAC6B,EAAQ,MAAM,EAAGH,CAAO,CAAC,EAEzCF,IAAU/B,EAAM,YAAY,OAC9B,MAAM,IAAI2B,EACR,mBAAmBI,CAAK,eAAe/B,EAAM,YAAY,MAAM,SAC/D,CAAE,SAAU,YAAa,MAAOa,EAAO,OAAO,KAAM,CACtD,CAEJ,QAAE,CACAS,GAAQ,oBAAoB,QAASiB,CAAO,EAG5C,GAAI,CACFH,EAAQ,MAAM,CAChB,MAAQ,CAER,CACF,CACF,CAOO,IAAMQ,GAAsB,CACjC,kBACA,kBACA,kBACF,EAGA,eAAsBC,IAA2C,CAC/D,GAAI,CAAC/C,EAAqB,EAAG,MAAO,CAAC,EACrC,IAAMgD,EAAsB,CAAC,EAC7B,QAAWC,KAASH,GAClB,GAAI,EAGc,MAAM,aAAa,kBAAkB,CACnD,MAAAG,EACA,WAAY,KACZ,YAAa,IACf,CAAC,GACW,WAAWD,EAAU,KAAKC,CAAK,CAC7C,MAAQ,CAER,CAEF,OAAOD,CACT,CC/PO,IAAME,GAAc,IAAI,IAAI,CACjC,OACA,OACA,OACA,OACA,OACA,OACA,OACA,OACA,OACA,MACF,CAAC,EAGKC,GAA0B,IAAI,IAAI,CACtC,OACA,OACA,OACA,OACA,OACA,OACA,OACA,MACF,CAAC,EAoBYC,GAAyB,MAa/B,SAASC,GAAiBC,EAAkD,CACjF,IAAMC,EAASD,aAAiB,WAAaA,EAAQ,IAAI,WAAWA,CAAK,EAErEE,EACAC,EACJ,GAAI,CACF,IAAMC,EAAQC,EAAW,IAAIC,EAAOL,CAAM,EAAG,CAAE,QAAS,EAAK,CAAC,EACxDM,EAAOC,EAAQJ,EAAO,MAAM,EAClC,GAAI,CAACG,EAAM,MAAO,CAAE,OAAQ,EAAM,EAIlC,IAHAJ,EAAQI,EAAK,KAAK,OAAO,EACzBL,EAAS,IAAI,IAAI,CAACC,CAAK,CAAC,EACxBI,EAAK,KAAK,IAAI,EACPA,EAAK,KAAK,WAAa,GAAGL,EAAO,IAAIK,EAAK,KAAK,OAAO,CAAC,CAChE,MAAQ,CACN,MAAO,CAAE,OAAQ,EAAM,CACzB,CAEA,GAAI,CAAC,CAAC,GAAGL,CAAM,EAAE,KAAMO,GAAMb,GAAY,IAAIa,CAAC,CAAC,EAAG,MAAO,CAAE,OAAQ,GAAO,MAAAN,CAAM,EAEhF,IAAIO,EACJ,GAAI,CACFA,EAAOC,EAAUV,EAAQ,CAAE,UAAW,EAAK,CAAC,CAC9C,MAAQ,CACNS,EAAO,MACT,CAEA,IAAME,EAAkBF,GAAM,MAAM,IAAIA,EAAK,aAAa,GAAG,SACvDG,EAASH,EAAOI,GAASJ,EAAME,CAAe,EAAI,UAExD,GAAIC,IAAW,MAAO,MAAO,CAAE,OAAQ,GAAO,MAAAV,EAAO,gBAAAS,EAAiB,OAAAC,CAAO,EAC7E,GAAIA,IAAW,OAAQ,MAAO,CAAE,OAAQ,GAAM,MAAAV,EAAO,gBAAAS,EAAiB,OAAAC,CAAO,EAI7E,IAAME,EAA0B,CAC9B,OAAQ,CAAC,GAAGb,CAAM,EAAE,KAAMO,GAAMZ,GAAwB,IAAIY,CAAC,CAAC,EAC9D,MAAAN,EACA,OAAQ,SACV,EACA,OAAIS,IAAoB,SAAWG,EAAO,gBAAkBH,GACrDG,CACT,CAGA,SAASD,GAASJ,EAAgBM,EAA8BC,EAAQ,EAAmB,CACzF,GAAID,IAAa,QAAUA,IAAa,OAAQ,MAAO,OACvD,GAAIA,IAAa,OAAQ,MAAO,MAChC,GAAIC,EAAQ,IAAMD,IAAa,QAAUA,IAAa,QAAUA,IAAa,QAAS,CACpF,IAAME,EAAQR,EAAK,WAAW,IAAI,MAAM,GAAG,IAAIA,EAAK,aAAa,IAAI,CAAC,EACtE,GAAIQ,IAAU,OAAW,OAAOJ,GAASJ,EAAMA,EAAK,MAAM,IAAIQ,CAAK,GAAG,SAAUD,EAAQ,CAAC,CAC3F,CACA,MAAO,SACT,CC1GO,SAASE,EACdC,EACAC,EACAC,EACyD,CACzD,IAAIC,EAAUH,EAEd,QAAWI,KAAMH,EACf,OAAQG,EAAG,KAAM,CACf,IAAK,OACHD,EAAUE,GAAQF,EAASG,GAAKH,EAASC,EAAIF,CAAU,EAAGF,CAAM,EAChE,MACF,IAAK,SACHG,EAAUE,GAAQF,EAASI,GAAOJ,EAASC,EAAG,MAAOF,CAAU,EAAGF,CAAM,EACxE,MACF,IAAK,SACHG,EAAUE,GAAQF,EAASK,GAAOL,EAASC,EAAG,KAAMF,CAAU,EAAGF,CAAM,EACvE,KACJ,CAGF,MAAO,CAAE,OAAQG,EAAS,QAASM,EAAoBR,CAAU,CAAE,CACrE,CASO,SAASQ,EAAoBR,EAAuD,CACzF,IAAMS,EAA6B,CAAE,SAAU,EAAG,SAAU,OAAQ,QAAS,EAAM,EACnF,QAAWN,KAAMH,EACf,OAAQG,EAAG,KAAM,CACf,IAAK,OACHM,EAAQ,QAAU,GAClB,MACF,IAAK,SACHA,EAAQ,UAAaA,EAAQ,SAAWN,EAAG,OAAS,IACpD,MACF,IAAK,SAAU,CACb,IAAMO,EAAYC,GAAgBR,EAAG,IAAI,EAGrCM,EAAQ,WAAa,OAAQA,EAAQ,SAAWC,EAC3CD,EAAQ,WAAaC,EAAWD,EAAQ,SAAW,QAE1DA,EAAQ,SAAW,OACnBA,EAAQ,UAAaA,EAAQ,SAAW,KAAO,KAEjD,KACF,CACF,CAEF,OAAOA,CACT,CAmCA,SAASE,GAAgBC,EAAwC,CAC/D,OAAOA,IAAS,EAAI,WAAa,YACnC,CAEA,SAASP,GACPN,EACAI,EACAF,EACiB,CACjB,IAAMY,EAASC,EAAaX,EAAG,MAAOA,EAAG,MAAM,EAE/C,OADYY,GAAQF,EAAQZ,CAAU,EAClC,UACFF,EACAI,EAAG,QACHA,EAAG,QACHA,EAAG,MACHA,EAAG,OACH,EACA,EACAA,EAAG,MACHA,EAAG,MACL,EACOU,CACT,CAGA,SAASP,GACPP,EACAiB,EACAf,EACiB,CACjB,IAAMgB,EAAOD,IAAU,IAAMA,IAAU,IACjCH,EAASC,EACbG,EAAOlB,EAAO,OAASA,EAAO,MAC9BkB,EAAOlB,EAAO,MAAQA,EAAO,MAC/B,EACMmB,EAAMH,GAAQF,EAAQZ,CAAU,EAItC,OAAAiB,EAAI,UAAUL,EAAO,MAAQ,EAAGA,EAAO,OAAS,CAAC,EACjDK,EAAI,OAAQ,CAACF,EAAQ,KAAK,GAAM,GAAG,EACnCE,EAAI,UAAUnB,EAAQ,CAACA,EAAO,MAAQ,EAAG,CAACA,EAAO,OAAS,CAAC,EACpDc,CACT,CAEA,SAASN,GACPR,EACAa,EACAX,EACiB,CACjB,IAAMY,EAASC,EAAaf,EAAO,MAAOA,EAAO,MAAM,EACjDmB,EAAMH,GAAQF,EAAQZ,CAAU,EACtC,OAAIU,GAAgBC,CAAI,IAAM,cAC5BM,EAAI,UAAUnB,EAAO,MAAO,CAAC,EAC7BmB,EAAI,MAAM,GAAI,CAAC,IAEfA,EAAI,UAAU,EAAGnB,EAAO,MAAM,EAC9BmB,EAAI,MAAM,EAAG,EAAE,GAEjBA,EAAI,UAAUnB,EAAQ,EAAG,CAAC,EACnBc,CACT,CAEA,SAASE,GACPI,EACAlB,EACmC,CACnC,IAAMiB,EAAMC,EAAO,WAAW,KAAM,CAAE,WAAAlB,EAAY,MAAO,EAAM,CAAC,EAChE,GAAI,CAACiB,EAAK,MAAM,IAAI,MAAM,4BAA4B,EACtD,OAAOA,CACT,CAQA,SAASd,GACPgB,EACAC,EACAC,EACiB,CACjB,OAAIF,IAAaE,IACfF,EAAS,MAAQ,EACjBA,EAAS,OAAS,GAEbC,CACT,CClLA,eAAsBE,IAAuC,CAC3D,GAAM,CAACC,EAAQC,CAAgB,EAAI,MAAM,QAAQ,IAAI,CACnDC,GAAmB,EACnBC,GAAsB,CACxB,CAAC,EAEKC,EAAYC,EAAqB,GAAKJ,EAAiB,OAAS,EAQtE,MAAO,CAAE,OAAAD,EAAQ,UAAAI,EAAW,iBAAAH,EAAkB,YANID,EAC9C,SACAI,EACE,YACA,MAEoD,CAC5D,CduDA,eAAsBE,GAAOC,EAA2C,CACtE,IAAMC,EAAS,MAAMC,GAAWF,EAAOG,EAAsB,EACvDC,EAAYC,GAAiBJ,CAAM,EACnCK,EAAuB,CAAE,OAAQF,EAAU,MAAO,EACxD,OAAIA,EAAU,QAAU,SAAWE,EAAO,MAAQF,EAAU,OACxDA,EAAU,kBAAoB,SAAWE,EAAO,gBAAkBF,EAAU,iBAC5EA,EAAU,SAAW,SAAWE,EAAO,OAASF,EAAU,QACvDE,CACT,CAiBA,eAAsBC,GACpBP,EACAQ,EAAyB,CAAC,EACH,CACvB,GAAM,CACJ,SAAAC,EAAW,OACX,WAAAC,EAAa,OACb,aAAAC,EACA,OAAAC,EACA,WAAAC,CACF,EAAIL,EAEJM,EAAeF,CAAM,EAGrB,IAAMG,EAAQ,MAAMC,GAAQhB,CAAK,EACjCc,EAAeF,CAAM,EAErB,IAAMK,EAAOC,EAAWH,CAAK,EAC7BD,EAAeF,CAAM,EAErB,IAAMO,EAAmD,CAAC,EACpDC,EAASC,GAAiCZ,IAAa,QAAUA,IAAaY,EAGpF,GAAID,EAAM,QAAQ,EAAG,CACnB,IAAME,EAAOtB,aAAiB,KAAOA,EAAQuB,EAAWR,CAAK,EACvDS,EAAU,MAAMC,GAAaH,EAAML,EAAML,CAAM,EACrD,GAAIY,EAAQ,SAAW,KAAM,CAG3B,IAAME,EAAc,MAAMC,GAAaH,EAAQ,OAAQb,EAAcC,CAAM,EAC3E,OAAOgB,GAASX,EAAMS,EAAa,SAAUG,EAAoBZ,EAAK,UAAU,CAAC,CACnF,CACAE,EAAS,KAAK,CAAE,SAAU,SAAU,OAAQK,EAAQ,MAAO,CAAC,CAC9D,CAGA,GAAIJ,EAAM,WAAW,EACnB,GAAI,CAACU,EAAqB,EACxBX,EAAS,KAAK,CAAE,SAAU,YAAa,OAAQ,+BAAgC,CAAC,MAEhF,IAAI,CACF,IAAMY,EAAa,MAAMC,GAAoBf,EAAMP,EAAYE,CAAM,EAC/D,CAAE,OAAAqB,EAAQ,QAAAC,CAAQ,EAAIC,EAAgBJ,EAAYd,EAAK,WAAYP,CAAU,EAC7E0B,EAAS,MAAMC,GAAeJ,EAAQtB,EAAcC,CAAM,EAChE,OAAOgB,GAASX,EAAMmB,EAAQ,YAAaF,CAAO,CACpD,OAASI,EAAO,CAEd,GADIA,aAAiBC,GACjB9B,IAAa,YAAa,MAAM6B,EACpCnB,EAAS,KAAK,CAAE,SAAU,YAAa,OAAQqB,GAAcF,CAAK,CAAE,CAAC,CACvE,CAKJ,GAAIlB,EAAM,MAAM,EAAG,CACjB,IAAMqB,EAAU,MAAMC,GAAe7B,CAAU,EAC/C,GAAI,CAAC4B,EACHtB,EAAS,KAAK,CACZ,SAAU,OACV,OAAQ,sEACV,CAAC,MAED,IAAI,CACF,IAAMb,EAAS,MAAMmC,EAAQ,OAAO,CAAE,KAAM1B,EAAO,WAAAL,EAAY,OAAAE,CAAO,CAAC,EAGjEsB,EAAUL,EAAoBZ,EAAK,UAAU,EAC/CmB,EACJ,GAAI9B,EAAO,iBAAiB,YAAa,CACvC,IAAMqC,EAASF,EAAQ,kBACnBnC,EAAO,MACP,MAAMsC,GAAgBtC,EAAO,MAAOW,EAAMP,CAAU,EACxD0B,EAAS,MAAMT,GAAagB,EAAQhC,EAAcC,CAAM,CAC1D,KAAO,CACL,IAAMqB,EAASQ,EAAQ,kBACnBnC,EAAO,MACP6B,EAAgB7B,EAAO,MAAOW,EAAK,WAAYP,CAAU,EAAE,OAC/D0B,EAAS,MAAMC,GAAeJ,EAAQtB,EAAcC,CAAM,CAC5D,CACA,OAAOgB,GAASX,EAAMmB,EAAQ,OAAQF,CAAO,CAC/C,OAASI,EAAO,CAEd,GADIA,aAAiBC,GACjB9B,IAAa,OAAQ,MAAM6B,EAC/BnB,EAAS,KAAK,CAAE,SAAU,OAAQ,OAAQqB,GAAcF,CAAK,CAAE,CAAC,CAClE,CAEJ,CAEA,MAAM,IAAIO,EAAqB,6BAA8B1B,EAAU,CACrE,MAAOF,EAAK,KAAK,WACjB,SAAUA,EAAK,KAAK,MAAM,IAAIA,EAAK,aAAa,GAAG,SACnD,OAAQA,EAAK,aACf,CAAC,CACH,CAMA,IAAI6B,GAQG,SAASC,GAAuBN,EAA2C,CAChFK,GAAoBL,CACtB,CAEO,SAASO,IAAmD,CACjE,OAAOF,EACT,CAEA,eAAeJ,GACbO,EACqC,CACrC,GAAIH,GAAmB,OAAOA,GAC9B,GAAKG,EACL,OAAOA,EAAO,CAChB,CAMA,eAAejC,GAAQhB,EAAyC,CAC9D,OAAIA,aAAiB,WAAmBA,EACpCA,aAAiB,YAAoB,IAAI,WAAWA,CAAK,EACtD,IAAI,WAAW,MAAMA,EAAM,YAAY,CAAC,CACjD,CAEA,eAAeE,GAAWF,EAAoBkD,EAAwC,CACpF,OAAIlD,aAAiB,KAGZ,IAAI,WAAW,MAAMA,EAAM,MAAM,EAAGkD,CAAS,EAAE,YAAY,CAAC,GAEvD,MAAMlC,GAAQhB,CAAK,GACpB,SAAS,EAAGkD,CAAS,CACpC,CAGA,SAASC,GAASC,EAAeC,EAAgB1C,EAA+B,CAC9E,GAAI,CAACA,GAAgBA,GAAgB,EAAG,MAAO,GAC/C,IAAM2C,EAAU,KAAK,IAAIF,EAAOC,CAAM,EACtC,OAAOC,GAAW3C,EAAe,EAAIA,EAAe2C,CACtD,CAUA,eAAejB,GACbJ,EACAtB,EACAC,EACsB,CACtBE,EAAeF,CAAM,EACrB,IAAM2C,EAAQJ,GAASlB,EAAO,MAAOA,EAAO,OAAQtB,CAAY,EAEhE,GAAI4C,IAAU,EAEZ,OAAOtB,EAAO,sBAAsB,EAGtC,IAAMuB,EAAc,KAAK,IAAI,EAAG,KAAK,MAAMvB,EAAO,MAAQsB,CAAK,CAAC,EAC1DE,EAAe,KAAK,IAAI,EAAG,KAAK,MAAMxB,EAAO,OAASsB,CAAK,CAAC,EAClE,GAAI,CACF,OAAO,MAAM,kBAAkBtB,EAAQ,CACrC,YAAAuB,EACA,aAAAC,EACA,cAAe,MACjB,CAAC,CACH,QAAE,CACAxB,EAAO,MAAQ,EACfA,EAAO,OAAS,CAClB,CACF,CAEA,eAAeN,GACbS,EACAzB,EACAC,EACsB,CACtBE,EAAeF,CAAM,EACrB,IAAM2C,EAAQJ,GAASf,EAAO,MAAOA,EAAO,OAAQzB,CAAY,EAChE,GAAI4C,IAAU,EAAG,OAAOnB,EAExB,IAAMsB,EAAU,MAAM,kBAAkBtB,EAAQ,CAC9C,YAAa,KAAK,IAAI,EAAG,KAAK,MAAMA,EAAO,MAAQmB,CAAK,CAAC,EACzD,aAAc,KAAK,IAAI,EAAG,KAAK,MAAMnB,EAAO,OAASmB,CAAK,CAAC,EAC3D,cAAe,MACjB,CAAC,EACD,OAAAnB,EAAO,MAAM,EACNsB,CACT,CAGA,eAAed,GACbR,EACAnB,EACAP,EACsB,CACtB,GAAIO,EAAK,WAAW,SAAW,EAAG,OAAOmB,EACzC,IAAMH,EAAS0B,EAAavB,EAAO,MAAOA,EAAO,MAAM,EACjDwB,EAAM3B,EAAO,WAAW,KAAM,CAAE,WAAAvB,EAAY,MAAO,EAAM,CAAC,EAChE,GAAI,CAACkD,EAAK,OAAOxB,EACjBwB,EAAI,UAAUxB,EAAQ,EAAG,CAAC,EAC1BA,EAAO,MAAM,EACb,GAAM,CAAE,OAAQyB,CAAY,EAAI1B,EAAgBF,EAAQhB,EAAK,WAAYP,CAAU,EACnF,OAAOmD,EAAY,sBAAsB,CAC3C,CAEA,SAASjC,GACPX,EACA6C,EACArD,EACAsD,EACc,CACd,MAAO,CACL,MAAAD,EACA,MAAOA,EAAM,MACb,OAAQA,EAAM,OACd,YAAa7C,EAAK,aAClB,aAAcA,EAAK,cACnB,SAAAR,EACA,SAAUQ,EAAK,SACf,OAAQA,EAAK,OACb,UAAWA,EAAK,MAAM,OACtB,YAAaA,EAAK,YAClB,kBAAA8C,EACA,SAAU9C,EAAK,QACjB,CACF,CAEA,SAASuB,GAAcF,EAAwB,CAC7C,OAAOA,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAC9D","names":["src_exports","__export","HeicAbortError","HeicDecodeError","HeicError","HeicParseError","HeicUnsupportedError","decodeHeic","findProperty","getRegisteredAdapter","hvccToAnnexBPrologue","hvccToCodecString","isHeic","lengthPrefixedToAnnexB","parseGridPayload","parseHeif","parseHvcC","planDecode","probeSupport","propertiesForItem","readGrid","readItemData","registerDecoderAdapter","toHeicBlob","bytes","HeicError","message","context","options","detail","formatContext","HeicParseError","HeicUnsupportedError","attempts","summary","a","HeicDecodeError","HeicAbortError","parts","key","value","createCanvas","width","height","HeicDecodeError","throwIfAborted","signal","HeicAbortError","nativeDecoderRejects","decodeNative","blob","plan","signal","throwIfAborted","bitmap","dimensionsMatch","got","displayWidth","displayHeight","upright","swapped","probeNativeSupport","bytes","decodeBase64","TINY_HEIC_BASE64","toHeicBlob","ok","TINY_HEIC_WIDTH","TINY_HEIC_HEIGHT","input","binary","out","i","Reader","_Reader","source","byteOffset","byteLength","u8","start","length","HeicParseError","to","count","at","value","byteCount","out","i","byte","raw","child","readFullBoxHeader","reader","version","flags","NAL_VPS","NAL_SPS","NAL_PPS","MAX_HVCC_ARRAYS","MAX_NALUS_PER_ARRAY","parseHvcC","reader","raw","configurationVersion","HeicParseError","profileByte","generalProfileSpace","generalTierFlag","generalProfileIdc","generalProfileCompatibilityFlags","generalConstraintIndicatorFlags","generalLevelIdc","minSpatialSegmentationIdc","parallelismType","chromaFormat","bitDepthLumaMinus8","bitDepthChromaMinus8","avgFrameRate","rateByte","constantFrameRate","numTemporalLayers","temporalIdNested","lengthSizeMinusOne","numOfArrays","arrays","i","head","arrayCompleteness","nalUnitType","numNalus","nalus","j","nalUnitLength","PROFILE_SPACE_PREFIX","hvccToCodecString","hvcc","fourCC","profile","compat","reverseBits32","level","constraintBytes","constraints","b","value","v","hvccBitDepth","hvccToAnnexBPrologue","selected","type","a","total","nalu","out","pos","lengthPrefixedToAnnexB","data","lengthSize","countNalUnits","read","write","naluLength","count","MAX_BOX_DEPTH","MAX_SIBLING_BOXES","walkBoxes","reader","options","depth","lenient","HeicParseError","count","offset","start","size","type","headerSize","payloadSize","body","childBoxes","findBox","boxes","box","findBoxes","MAX_ITEMS","MAX_EXTENTS_PER_ITEM","MAX_PROPERTIES","MAX_ASSOCIATIONS_PER_ITEM","MAX_REFERENCES_PER_ITEM","parseInfe","box","r","version","flags","readFullBoxHeader","hidden","itemId","protectionIndex","itemType","itemName","info","contentType","parseIinf","entryCount","HeicParseError","items","seen","child","walkBoxes","parseIloc","sizesByte","offsetSize","lengthSize","baseByte","baseOffsetSize","indexSize","itemCount","locations","i","constructionMethod","baseOffset","extentCount","extents","j","offset","length","parseProperty","box","r","readFullBoxHeader","parseHvcC","colorType","primaries","transfer","matrix","fullRange","numChannels","bitsPerChannel","i","parseIpma","into","version","flags","wideIndex","entryCount","MAX_ITEMS","HeicParseError","itemId","associationCount","MAX_ASSOCIATIONS_PER_ITEM","associations","j","value","existing","parseIprp","children","childBoxes","ipco","findBox","properties","child","walkBoxes","MAX_PROPERTIES","ipma","findBoxes","parseIref","refs","cr","fromItemId","referenceCount","MAX_REFERENCES_PER_ITEM","toItemIds","byType","parseHeif","input","options","source","root","Reader","boxes","ftyp","majorBrand","minorVersion","compatibleBrands","meta","metaChildren","hdlr","handlerType","primaryItemId","pitm","iinf","items","parseIinf","iloc","locations","parseIloc","iprp","itemProperties","iref","references","idat","itemData","id","info","propertiesForItem","file","out","association","property","findProperty","type","p","readItemData","location","context","container","total","extent","start","length","pos","MAX_TILES","parseGridPayload","payload","r","Reader","version","HeicParseError","wideFields","rows","columns","outputWidth","outputHeight","readGrid","file","itemId","warnings","readItemData","tileItemIds","expected","width","height","ispe","findProperty","propertiesForItem","MAX_TOTAL_PIXELS","planDecode","input","file","parseHeif","warnings","primaryItemId","info","HeicParseError","isGrid","HeicUnsupportedError","primaryProps","propertiesForItem","tiles","codedWidth","codedHeight","grid","readGrid","firstTileProps","firstIspe","findProperty","index","itemId","ispe","tileGroups","groupTilesByConfig","transforms","readTransforms","displayWidth","displayHeight","applyTransformsToSize","bitDepth","hvccBitDepth","collectFeatureWarnings","readSourceColor","groups","tile","association","a","group","property","hvccToCodecString","result","properties","width","height","ops","currentWidth","currentHeight","crop","resolveCleanAperture","clap","cropWidth","cropHeight","centreOffsetX","centreOffsetY","offsetX","offsetY","w","h","op","tileProps","colr","seen","add","warning","auxTargets","auxItemId","targets","auxType","item","tileData","plan","readItemData","isWebCodecsAvailable","resolveConfig","group","codedWidth","codedHeight","lengthSize","failures","hvc1","support","error","hev1","hvccToCodecString","hvccToAnnexBPrologue","HeicUnsupportedError","chunkBytes","config","payload","body","lengthPrefixedToAnnexB","prologue","out","decodeWithWebCodecs","plan","colorSpace","signal","throwIfAborted","canvas","createCanvas","ctx","HeicDecodeError","decodeGroup","first","nextTile","drawn","settle","failure","_","reject","decoder","frame","tile","onAbort","HeicAbortError","tileIndex","bytes","tileData","PROBE_CODEC_STRINGS","probeHevcCodecStrings","supported","codec","HEIF_BRANDS","UNAMBIGUOUS_HEIC_BRANDS","DETECTION_PREFIX_BYTES","detectFromBuffer","input","source","brands","brand","boxes","childBoxes","Reader","ftyp","findBox","b","file","parseHeif","primaryItemType","coding","codingOf","result","itemType","depth","first","applyTransforms","source","transforms","colorSpace","current","op","release","crop","rotate","mirror","summarizeTransforms","applied","direction","mirrorDirection","axis","target","createCanvas","context","angle","swap","ctx","canvas","previous","next","original","probeSupport","native","hevcCodecStrings","probeNativeSupport","probeHevcCodecStrings","webcodecs","isWebCodecsAvailable","isHeic","input","prefix","readPrefix","DETECTION_PREFIX_BYTES","detection","detectFromBuffer","result","decodeHeic","options","strategy","colorSpace","maxDimension","signal","wasmLoader","throwIfAborted","bytes","readAll","plan","planDecode","attempts","wants","candidate","blob","toHeicBlob","outcome","decodeNative","finalBitmap","resizeBitmap","describe","summarizeTransforms","isWebCodecsAvailable","composited","decodeWithWebCodecs","canvas","applied","applyTransforms","bitmap","canvasToBitmap","error","HeicAbortError","describeError","adapter","resolveAdapter","source","transformBitmap","HeicUnsupportedError","registeredAdapter","registerDecoderAdapter","getRegisteredAdapter","loader","byteCount","scaleFor","width","height","longest","scale","resizeWidth","resizeHeight","resized","createCanvas","ctx","transformed","image","transformsApplied"]}