/** * Crop Module — handles free crop, aspect-ratio locked crop, and crop application */ import { fabric } from 'fabric'; export declare class CropModule { private canvas; private cropRect; private overlay; private aspectRatio; private isActive; private imageObject; private minCropSize; constructor(canvas: fabric.Canvas); /** * Activate crop mode with an optional aspect ratio */ activate(imageObject: fabric.Image, ratio?: number | null): void; /** * Deactivate crop mode and remove overlays */ deactivate(): void; /** * Apply the crop — returns cropped image data URL plus the geometry * needed by the caller to keep annotations aligned after the base * image is replaced. * * cropRectCanvas — bounding box of the crop rect in the OLD canvas * coordinate system (post-scale). * oldDisplayScaleX/Y — the base image's display scale at crop time * (canvas-pixels per image-pixel). */ applyCrop(): { dataUrl: string; width: number; height: number; cropRectCanvas: { left: number; top: number; width: number; height: number; }; oldDisplayScaleX: number; oldDisplayScaleY: number; } | null; /** * Set the crop aspect ratio. * * Bug fix: previously this kept the current rect width and derived * `height = width / ratio` without checking whether the derived height * still fit inside the image bounds. Picking e.g. 4:3 on a 16:9 photo * produced a rect that overflowed the image vertically — `constrainCropRect` * only clamps position, not size, so the overflow stayed and `Apply Crop` * exported an image with blank strips. The result didn't look like the * chosen aspect ratio. * * Now we shrink (w, h) proportionally so BOTH dimensions fit the image * while exactly matching `ratio`, and we re-centre the rect on its * previous centre so changing the ratio feels stable. */ setAspectRatio(ratio: number | null): void; getIsActive(): boolean; private getImageBounds; private constrainCropRect; private constrainCropScale; private addGridLines; }