-
Notifications
You must be signed in to change notification settings - Fork 4.8k
Expand file tree
/
Copy pathcrop-pixels.ts
More file actions
103 lines (98 loc) · 3.61 KB
/
crop-pixels.ts
File metadata and controls
103 lines (98 loc) · 3.61 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
/**
* Internal dependencies
*/
import type { CropperState, NormalizedRect, Size } from '../image-editor';
import { getRotatedBBox } from '../image-editor/core/camera';
/**
* The crop rectangle expressed as pixel dimensions in the snap-rotation
* bounding-box frame. This is the frame the stencil lives in — the same
* one `buildModifiers` uses to construct the server crop payload.
*
* For 0° (and 180°) rotation the snap-AABB equals the source image, so
* these values are source pixels. For 90°/270° the axes swap. For
* non-snap rotations (e.g. 45°) the snap-AABB is the nearest 90° AABB,
* which is how the stencil is positioned.
*/
export interface CropPixels {
/** X offset of the crop in the snap-rotation bounding box, in pixels. */
x: number;
/** Y offset of the crop in the snap-rotation bounding box, in pixels. */
y: number;
/** Width of the crop, in pixels. */
width: number;
/** Height of the crop, in pixels. */
height: number;
/** Width of the snap-rotation bounding box, in pixels. */
snapBBoxWidth: number;
/** Height of the snap-rotation bounding box, in pixels. */
snapBBoxHeight: number;
}
/**
* Convert the cropper's normalized cropRect to pixel dimensions in the
* snap-rotation bounding-box frame.
*
* This is the shared math used by `buildModifiers` (to construct the server
* crop payload) and by the Advanced crop panel (to display and accept
* pixel-value input). Both callers must stay in sync: if the conversion
* changes, the server payload and the UI inputs change together.
*
* @param state The current cropper state.
* @param imageSize Natural dimensions of the source image.
* @return Pixel dimensions of the crop in the snap-rotation frame.
*/
export function getCropPixels(
state: CropperState,
imageSize: Size
): CropPixels {
const { cropRect, pan, zoom, rotation } = state;
const snapRotation = Math.round( rotation / 90 ) * 90;
const { width: snapBBoxWidth, height: snapBBoxHeight } = getRotatedBBox(
imageSize.width,
imageSize.height,
snapRotation
);
const imgLeft = 0.5 + pan.x - zoom / 2;
const imgTop = 0.5 + pan.y - zoom / 2;
return {
x: ( ( cropRect.x - imgLeft ) / zoom ) * snapBBoxWidth,
y: ( ( cropRect.y - imgTop ) / zoom ) * snapBBoxHeight,
width: ( cropRect.width / zoom ) * snapBBoxWidth,
height: ( cropRect.height / zoom ) * snapBBoxHeight,
snapBBoxWidth,
snapBBoxHeight,
};
}
/**
* Convert pixel dimensions in the snap-rotation bounding-box frame back to
* a normalized `NormalizedRect`. Exact inverse of `getCropPixels`.
*
* @param pixels Crop position and size in snap-rotation pixels.
* @param pixels.x X offset of the crop.
* @param pixels.y Y offset of the crop.
* @param pixels.width Width of the crop.
* @param pixels.height Height of the crop.
* @param state The current cropper state (provides zoom, pan, rotation).
* @param imageSize Natural dimensions of the source image.
* @return The normalized crop rectangle.
*/
export function pixelsToCropRect(
pixels: { x: number; y: number; width: number; height: number },
state: CropperState,
imageSize: Size
): NormalizedRect {
const { pan, zoom, rotation } = state;
const snapRotation = Math.round( rotation / 90 ) * 90;
const { width: snapBBoxWidth, height: snapBBoxHeight } = getRotatedBBox(
imageSize.width,
imageSize.height,
snapRotation
);
const imgLeft = 0.5 + pan.x - zoom / 2;
const imgTop = 0.5 + pan.y - zoom / 2;
return {
x: ( pixels.x / snapBBoxWidth ) * zoom + imgLeft,
y: ( pixels.y / snapBBoxHeight ) * zoom + imgTop,
width: ( pixels.width / snapBBoxWidth ) * zoom,
height: ( pixels.height / snapBBoxHeight ) * zoom,
};
}