import { requireNativeModule } from 'expo-modules-core'; export interface DecodeEncodeTimings { decodeMs: number; encodeWriteMs: number; totalMs: number; } export interface ColorTimings { decodeMs: number; toneMs?: number; cinemaMs?: number; colorMs: number; clarityMs?: number; grainMs?: number; frameMs?: number; sharpenMs?: number; encodeWriteMs: number; totalMs: number; } /** Rect (pixel coords) of the center-largest aspect crop, computed in JS. */ export interface CropRect { x: number; y: number; width: number; height: number; } /** ToneUniforms from toneShader.ts (0/0/0 = skip tone pass). */ export interface ToneUniforms { dr: number; hl: number; sh: number; } /** Optional pipeline params passed as a map (native Coroutine arity cap = 8). */ export interface PhotoAdjust { /** ToneUniforms from toneShader.ts; default 0/0/0 = skip tone pass. */ toneDr?: number; toneHl?: number; toneSh?: number; /** 16 flat floats from cinemaShader.ts getCinemaUniforms(season).flat; null/omitted or flat[0]=0 = skip. */ cinema?: number[] | null; /** ColorAdjustments.denoise 0..10 (0 = skip). */ denoise?: number; /** ColorAdjustments.clarity -10..10; >0 conv sharpen, <0 mist blur (0 = skip). */ clarity?: number; /** ColorAdjustments.grain 0..10 (0 = skip). */ grain?: number; /** JPEG quality 0..100; default 95. */ quality?: number; /** Final screen-sharpen amount (exportEngine #9 screenSharpenImage); >0 applies. */ sharpen?: number; /** DPI stamped into the JPEG header after encode (patchJpegDpi port); 0 = skip. */ dpi?: number; /** Composition aspect-ratio crop computed after decode (center-largest, engine #1b). */ aspect?: '4:3' | '3:2' | 'full'; /** Photo frame preset applied before encode, mirroring frameUtils.ts. Default 'none'. */ frameId?: 'none' | 'classic-white' | 'cinematic' | 'polaroid' | 'wallframe'; /** Base64 PNG art (wallframe only, 4000x3117). Decoded per call. */ frameArtB64?: string; /** Base64 TTF body font (geo stamp only). Cached after first decode. */ fontB64?: string; /** Base64 TTF emoji font (geo stamp only). Cached after first decode. */ iconB64?: string; /** Optional GPS stamp {locality, timestamp}; null/omitted = skip. */ geo?: { locality: string; timestamp: number } | null; /** Encode PNG instead of JPEG. Probe-only. */ png?: boolean; /** Probe-only: sample these photo-space pixel coords after frame pass, before encode; logs via samplePixel. */ probeSamples?: Array<{ x: number; y: number }>; /** Probe-only: log per-row stamp diff/amber/white metrics (see samplePixel) and return them in ColorTimings-adjacent logs. */ probeStampDiff?: boolean; } export interface RecipescamExportModule { /** Decode JPEG/PNG at srcPath (plain absolute path), re-encode JPEG q and write dstPath. All native, background. Returns stage timings in ms. */ decodeEncodeAsync(srcPath: string, dstPath: string, quality: number): Promise; /** * Native pipeline mirroring exportEngine.ts filter order — decode, optional * center-largest crop, optional tone pass (TONE_SKSL port), optional cinema * seasonal grade (CINEMA_SKSL port), row-major 4x5 color matrix (translate * column in 0..1 Skia space), optional denoise blur / clarity conv / mist * blur / grain Overlay, then JPEG-encode to dstPath. All native, off the * JS/main threads. Stage order mirrors exportEngine: crop -> tone -> cinema * -> matrix -> denoise/clarity -> grain -> frame (classic/cinematic/ * polaroid/wallframe) -> GPS stamp (geo, bottom of the composed output) * -> encode. Timings gain frameMs when a frame/stamp pass runs. */ processPhotoAsync(srcPath: string, dstPath: string, matrix: number[], crop: CropRect | null, adjust?: PhotoAdjust): Promise; /** P1 alias: matrix + crop, no tone/cinema/enhance passes. */ processColorAsync(srcPath: string, dstPath: string, matrix: number[], crop: CropRect | null, quality: number): Promise; /** P0 probe helpers — removed before ship. */ ping(): Promise; materializeBenchAsset(assetName: string): Promise; materializeSolidAsset(r: number, g: number, b: number): Promise; materializeRampAsset(): Promise; materializeStepAsset(): Promise; } export default requireNativeModule('RecipesCamExport') as RecipescamExportModule;