/** * Client-side image downscaling for the AI Pest & Disease scan flow (BOFF-2887) * and the AI Assistant composer. * * A phone photo can be several megabytes; we downscale it to a sane max dimension * and re-encode as JPEG before (a) sending the base64 to the diagnosis model and * (b) uploading it to wspace-files-svc. This keeps the GraphQL payload small, the * upload fast, and the model call cheap — without changing what the farmer sees. * * Falls back to the original file bytes if the browser can't rasterise the image * (e.g. an exotic format), so a scan is never blocked by the optimisation. That * fallback is not free — see `encodeFallback`. */ /** * The transport encode for the diagnosis mutation: it is sized against the * gateway's body cap rather than against the upload. The stored copy stays at * the primary 1280px encode — the file library should not be degraded to the * transport's budget — while `inline` produces a second, smaller encode from * the SAME decode for the wire (768px/q0.6 ≈ 92 KB of base64 fits the 256 KB * body cap; the 1280px primary measures ~360 KB and does not). */ export declare const INLINE_ENCODE: { readonly maxDim: 768; readonly quality: 0.6; }; /** * The payload the mutation should carry: the transport encode when we have one, * otherwise the primary. Returns '' when neither is usable. */ export declare function selectInlineBase64(image: DownscaledImage): string; export interface DownscaledImage { /** Re-encoded image blob, for upload to files-svc. */ blob: Blob; /** Bare base64 (no `data:` prefix), for the diagnosis mutation. '' when skipped. */ base64: string; /** `data:;base64,...` URL, for an preview. '' when skipped. */ dataUrl: string; /** * A SECOND, smaller `data:` URL for callers that must fit the image inside a * request body (see `DownscaleOptions.inline`). Absent unless asked for, and * absent when it would not actually be smaller than `dataUrl`. */ inlineDataUrl?: string; mimeType: string; filename: string; /** * Did the browser actually rasterise and re-encode the image? * * False means `blob` is the ORIGINAL file: the format could not be decoded * here (HEIC from an iPhone is the real-world case — neither Chrome nor * Firefox decodes it), so nothing was resized, `mimeType` is whatever the file * claimed, and any preview built from it cannot render either. * * NOTE this is "was it rasterised", NOT "did the dimensions shrink". An image * already smaller than `maxDim` takes `scale === 1` yet still goes through the * canvas and comes back as a perfectly good JPEG — that is a success. */ downscaled: boolean; } export interface DownscaleOptions { /** Longest-edge ceiling for the primary encode. */ maxDim?: number; /** JPEG quality for the primary encode. */ quality?: number; /** * Encode the fallback (un-rasterisable) bytes to base64 as well? * * Default true, for callers that need `base64` no matter what. Pass false when * only `blob` is used: base64 costs ~1.37x the file size in a string that is * then held in memory, and on the fallback path the file has NOT been * downscaled — so a 12 MB HEIC becomes ~16 MB of strings backing a preview the * browser cannot render anyway. */ encodeFallback?: boolean; /** * Also produce `inlineDataUrl` at these settings, reusing the bitmap that has * already been decoded (one decode, two encodes — the second is cheap). * * This exists because "small enough to upload" and "small enough to fit in a * request body" are different budgets: the upload can be a 1280px photo, but * the turn that carries the pixels to the model has to fit through a gateway * that caps bodies at 256 KB. Keeping them separate means the file the farmer * later opens from their file library is NOT degraded to the transport's size. */ inline?: { maxDim: number; quality: number; }; } export declare function downscaleImage(file: File, options?: DownscaleOptions): Promise; //# sourceMappingURL=imageDownscale.d.ts.map