/** * RectCropPreview — item-7 of the first-time-user guidance flow: the * post-capture crop editor. * * Shows the full stitched result image (contain-fit, letterboxed) with a * 4-corner quad overlay. Each corner is INDEPENDENTLY draggable in * on-screen coords via RN-core `PanResponder` (deliberately NO * react-native-gesture-handler dependency — this library ships zero extra * native deps for guidance). Corner positions are mapped to image-pixel * space through the pure `cropGeometry` letterbox transform. * * ## What it surfaces (and what it does NOT do) * * This component is presentation + gesture only. On confirm it computes * the 4 image-pixel corners and hands them to `onConfirm` — it does NOT * call any native crop. The PARENT decides between the cheap axis-aligned * `cropToRect` (when the quad is ~rectangular) and the perspective * `cropToQuad`, using the `perspective` flag in the result: * * onConfirm({ quad, perspective: perspectiveCorrect && !isAxisAligned }) * * Promoted + extended from `example/InscribedRectDebug.tsx`, which already * did the image-px ↔ on-screen contain-fit mapping, a rect overlay, and * the in-place native crop. This version replaces the single computed * inscribed rect with a user-draggable free quad and the perspective * decision; the letterbox math now lives in the shared `cropGeometry` * module. Styling is carried over from InscribedRectDebug. * * ## Seeding * * The initial quad comes from `initialRect` (image-pixel coords) when the * host passes one — `` passes the panorama's MAX-INSCRIBED rectangle * (the tightest clean rectangle with no black corners; item 2) so the editor * opens on a sensible crop the user drags to taste. With no `initialRect` * (native inscribed-rect unavailable) it falls back to an 8 %-inset * rectangle. "Reset" returns to whichever seed was used. */ import React from 'react'; import { type GuidanceCopy } from './cameraGuidanceCopy'; import { type Quad } from './cropGeometry'; /** Image-pixel rectangle, used for the optional `initialRect` seed. */ export interface ImageRect { x: number; y: number; width: number; height: number; } /** What the host receives when the user taps Crop. */ export interface RectCropResult { /** * The 4 chosen corners in IMAGE-PIXEL space, canonically ordered * [TL, TR, BR, BL]. The host feeds these to the native crop. */ quad: Quad; /** * `true` → the host should perspective-rectify (`cropToQuad`): the user * picked a non-rectangular quad and `perspectiveCorrect` is enabled. * `false` → the host can use the cheap axis-aligned `cropToRect` (the * quad is ~rectangular, or perspective correction is disabled). */ perspective: boolean; } export interface RectCropPreviewProps { /** file:// URI of the full result image to crop. */ imageUri: string; /** Intrinsic pixel width of `imageUri`. */ imageWidth: number; /** Intrinsic pixel height of `imageUri`. */ imageHeight: number; /** Show / hide the editor. */ visible: boolean; /** * Tapped on "Crop". Receives the ordered image-pixel quad + the * perspective decision; the host performs the actual native crop. */ onConfirm: (result: RectCropResult) => void; /** * Tapped on "Use original" (or hardware back / dismiss) — emit the stitch * un-cropped. Also called when the user collapses the quad to something * un-warpable, so a degenerate quad never reaches the native crop. */ onUseOriginal: (uri?: string) => void; /** * Tapped on "Retake" — discard this capture entirely and return to the * camera. No result is emitted (the host clears the editor + lets the * user capture again). */ onRetake: () => void; /** * Optional non-fatal warning messages (e.g. "<70 % of frames used") shown * as a banner across the top of the editor so the user sees them before * accepting a crop. Empty / undefined → no banner. */ warnings?: string[]; /** * Crop mode vs preview-only mode. `true` (default) shows the draggable * quad + corner handles + the [Retake][Use original][Crop] bar — the full * crop editor. `false` hides the quad and all crop affordances, showing * just the stitched image with a [Retake][Confirm] bar — a plain preview * (`` without `rectCrop`). Confirm emits the image * un-cropped (same as "Use original"). */ showCropControls?: boolean; /** * Optional image-pixel seed rect for the draggable quad. Defaults to * an 8 %-inset rectangle of the full image. Ignored in preview-only mode, * and overridden by `initialQuad` when both are given. */ initialRect?: ImageRect; /** * Optional image-pixel seed QUAD (free 4-corner, any order) for the * draggable quad — e.g. detected document corners, so the editor opens on * the actual (possibly perspective) document outline rather than an * axis-aligned rectangle. Takes precedence over `initialRect`. Ignored in * preview-only mode. "Reset" returns to this quad. */ initialQuad?: Quad; /** Copy overrides (cropConfirm / cropReset). Falls back to defaults. */ copy?: Partial; /** * Safe-area insets (px). The editor is a full-screen Modal, so the host * passes `insets.top`/`insets.bottom` to keep the top toolbar (warnings) * clear of the notch/Dynamic Island and the bottom button bar clear of the * home indicator. Default 0. */ topInset?: number; bottomInset?: number; /** * 2026-06-14 (DEV overlay) — optional multi-line debug text describing how * this output was stitched (pipeline / warper / route / seam / blend / score * / frames / size). When non-empty, rendered as a small monospace pill in * the top-right corner. The host gates this on `__DEV__`; this component * just renders whatever non-empty string it's given. */ debugInfo?: string; /** * 2026-06-15 — show the live memory-footprint pill (polled native RSS, * green/amber/red) on the preview too, so the operator can watch the spike * when the on-demand high-level re-stitch fires. Host gates on settings.debug. */ showMemoryPill?: boolean; } export declare function RectCropPreview(props: RectCropPreviewProps): React.JSX.Element; //# sourceMappingURL=RectCropPreview.d.ts.map