/** * @file * * Fits a screenshot onto a canvas of a different aspect ratio without cropping * it or distorting it, filling the leftover margins with a blurred, enlarged * copy of the same image (the "pillarbox" treatment used by store listings). * * The motivating case is a mobile store screenshot. The Android emulator's * framebuffer is whatever the AVD's screen is — a Pixel 10 Pro XL is 1344x2992, * roughly 9:20 — while the community store asks for 900x1600 (9:16). Cropping * to 9:16 throws away a fifth of the frame, and stretching distorts the UI, so * the image is scaled to fit the HEIGHT and the two side margins are filled. * * The geometry is a pure function so it can be unit-tested; the pixel work needs * `sharp`, which is an OPTIONAL peer dependency — declared rather than bundled * because only screenshot capture needs it, and it ships platform-specific * native binaries that every other consumer would pay for. */ /** * Parameters for {@link computeFitToCanvas}. */ export interface ComputeFitToCanvasParams { /** * Height of the target canvas, in pixels. */ readonly canvasHeightInPixels: number; /** * Width of the target canvas, in pixels. */ readonly canvasWidthInPixels: number; /** * Height of the source image, in pixels. */ readonly sourceHeightInPixels: number; /** * Width of the source image, in pixels. */ readonly sourceWidthInPixels: number; } /** * Options for {@link fitScreenshotToCanvas}. */ export interface FitScreenshotToCanvasOptions { /** * Gaussian blur strength applied to the margin fill. * * @default `24` */ readonly blurSigma?: number; /** * Height of the target canvas, in pixels. */ readonly canvasHeightInPixels: number; /** * Width of the target canvas, in pixels. */ readonly canvasWidthInPixels: number; } /** * Where the scaled source image sits on the canvas. */ export interface FitToCanvasGeometry { /** * Width of each side margin, in pixels. Both sides are equal by construction. */ readonly marginInPixels: number; /** * Left offset of the scaled image on the canvas, in pixels. */ readonly offsetXInPixels: number; /** * Top offset of the scaled image on the canvas, in pixels. */ readonly offsetYInPixels: number; /** * Height the source is scaled to, in pixels. */ readonly scaledHeightInPixels: number; /** * Width the source is scaled to, in pixels. */ readonly scaledWidthInPixels: number; } /** * Computes how a source image is scaled and placed to fill a canvas's height, * with equal margins on the left and right. * * The scaled width is rounded to the nearest integer that leaves an EVEN * remainder, so the two margins are exactly equal — an asymmetric pillarbox is * visible at a glance and looks like a mistake. Where both neighbors qualify, * the one closer to the true scaled width wins, so the aspect error stays below * one part in a thousand. * * Worked example, the mobile store case: a 1344x2992 frame onto a 900x1600 * canvas scales by `1600/2992` to 718.72 wide. 719 would leave a 181px * remainder, which cannot split evenly, so 718 is chosen (margin 91) over 720 * (margin 90) because 718 is nearer 718.72. * * @param params - The source and canvas dimensions. * @returns The scaled size, the offsets, and the side margin. * @throws Error if any dimension is not a positive number. */ export declare function computeFitToCanvas(params: ComputeFitToCanvasParams): FitToCanvasGeometry; /** * Scales a screenshot to fill a canvas's height and fills the side margins with * a blurred, enlarged copy of the same image. * * Nothing is cropped and nothing is stretched: the visible screenshot keeps its * aspect ratio to within a rounding pixel, and the margins are made of the * image itself rather than a flat color, so the result reads as one frame. * * @param bytes - The source PNG. * @param options - The target canvas size and blur strength. * @returns A {@link Promise} that resolves to the composed PNG, exactly the canvas size. * @throws Error if `sharp` is not installed, or the source dimensions cannot be read. */ export declare function fitScreenshotToCanvas(bytes: Uint8Array, options: FitScreenshotToCanvasOptions): Promise;