@bensitu/image-editor 2.1.0 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +305 -95
- package/dist/cjs/index.cjs +3460 -843
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/esm/annotation/annotation-lock.js +7 -0
- package/dist/esm/annotation/annotation-lock.js.map +1 -0
- package/dist/esm/annotation/annotation-manager.js +217 -0
- package/dist/esm/annotation/annotation-manager.js.map +1 -0
- package/dist/esm/annotation/annotation-style.js +50 -0
- package/dist/esm/annotation/annotation-style.js.map +1 -0
- package/dist/esm/annotation/draw-controller.js +114 -0
- package/dist/esm/annotation/draw-controller.js.map +1 -0
- package/dist/esm/annotation/text-controller.js +234 -0
- package/dist/esm/annotation/text-controller.js.map +1 -0
- package/dist/esm/core/default-options.js +240 -9
- package/dist/esm/core/default-options.js.map +1 -1
- package/dist/esm/core/editor-object-kind.js +37 -0
- package/dist/esm/core/editor-object-kind.js.map +1 -0
- package/dist/esm/core/errors.js +19 -0
- package/dist/esm/core/errors.js.map +1 -1
- package/dist/esm/core/layer-order.js +100 -0
- package/dist/esm/core/layer-order.js.map +1 -0
- package/dist/esm/core/public-types.js +34 -1
- package/dist/esm/core/public-types.js.map +1 -1
- package/dist/esm/core/state-serializer.js +112 -24
- package/dist/esm/core/state-serializer.js.map +1 -1
- package/dist/esm/crop/crop-controller.js +220 -10
- package/dist/esm/crop/crop-controller.js.map +1 -1
- package/dist/esm/export/export-format.js.map +1 -1
- package/dist/esm/export/export-service.js +157 -168
- package/dist/esm/export/export-service.js.map +1 -1
- package/dist/esm/export/overlay-merge-service.js +75 -0
- package/dist/esm/export/overlay-merge-service.js.map +1 -0
- package/dist/esm/history/history-manager.js +2 -2
- package/dist/esm/history/history-manager.js.map +1 -1
- package/dist/esm/image/image-loader.js +20 -51
- package/dist/esm/image/image-loader.js.map +1 -1
- package/dist/esm/image/transform-controller.js +42 -0
- package/dist/esm/image/transform-controller.js.map +1 -1
- package/dist/esm/image-editor.js +1200 -72
- package/dist/esm/image-editor.js.map +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/mask/mask-factory.js +39 -14
- package/dist/esm/mask/mask-factory.js.map +1 -1
- package/dist/esm/mask/mask-label-manager.js +2 -0
- package/dist/esm/mask/mask-label-manager.js.map +1 -1
- package/dist/esm/mask/mask-list.js.map +1 -1
- package/dist/esm/mask/mask-style.js.map +1 -1
- package/dist/esm/mosaic/mosaic-controller.js +24 -28
- package/dist/esm/mosaic/mosaic-controller.js.map +1 -1
- package/dist/esm/utils/file.js +10 -0
- package/dist/esm/utils/file.js.map +1 -1
- package/dist/esm/utils/image-element-loader.js +55 -0
- package/dist/esm/utils/image-element-loader.js.map +1 -0
- package/dist/esm/utils/pointer.js +28 -0
- package/dist/esm/utils/pointer.js.map +1 -0
- package/dist/types/annotation/annotation-lock.d.ts +12 -0
- package/dist/types/annotation/annotation-lock.d.ts.map +1 -0
- package/dist/types/annotation/annotation-manager.d.ts +33 -0
- package/dist/types/annotation/annotation-manager.d.ts.map +1 -0
- package/dist/types/annotation/annotation-style.d.ts +13 -0
- package/dist/types/annotation/annotation-style.d.ts.map +1 -0
- package/dist/types/annotation/draw-controller.d.ts +43 -0
- package/dist/types/annotation/draw-controller.d.ts.map +1 -0
- package/dist/types/annotation/text-controller.d.ts +47 -0
- package/dist/types/annotation/text-controller.d.ts.map +1 -0
- package/dist/types/core/default-options.d.ts +14 -2
- package/dist/types/core/default-options.d.ts.map +1 -1
- package/dist/types/core/editor-object-kind.d.ts +29 -0
- package/dist/types/core/editor-object-kind.d.ts.map +1 -0
- package/dist/types/core/errors.d.ts +11 -1
- package/dist/types/core/errors.d.ts.map +1 -1
- package/dist/types/core/layer-order.d.ts +21 -0
- package/dist/types/core/layer-order.d.ts.map +1 -0
- package/dist/types/core/public-types.d.ts +272 -56
- package/dist/types/core/public-types.d.ts.map +1 -1
- package/dist/types/core/state-serializer.d.ts +34 -5
- package/dist/types/core/state-serializer.d.ts.map +1 -1
- package/dist/types/crop/crop-controller.d.ts +18 -14
- package/dist/types/crop/crop-controller.d.ts.map +1 -1
- package/dist/types/export/export-format.d.ts +9 -40
- package/dist/types/export/export-format.d.ts.map +1 -1
- package/dist/types/export/export-service.d.ts +45 -41
- package/dist/types/export/export-service.d.ts.map +1 -1
- package/dist/types/export/overlay-merge-service.d.ts +38 -0
- package/dist/types/export/overlay-merge-service.d.ts.map +1 -0
- package/dist/types/history/history-manager.d.ts +11 -14
- package/dist/types/history/history-manager.d.ts.map +1 -1
- package/dist/types/image/image-loader.d.ts +27 -22
- package/dist/types/image/image-loader.d.ts.map +1 -1
- package/dist/types/image/image-resampler.d.ts +1 -1
- package/dist/types/image/transform-controller.d.ts +19 -14
- package/dist/types/image/transform-controller.d.ts.map +1 -1
- package/dist/types/image-editor.d.ts +93 -15
- package/dist/types/image-editor.d.ts.map +1 -1
- package/dist/types/index.d.cts +3 -3
- package/dist/types/index.d.cts.map +1 -1
- package/dist/types/index.d.ts +3 -3
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/mask/mask-factory.d.ts.map +1 -1
- package/dist/types/mask/mask-label-manager.d.ts +10 -9
- package/dist/types/mask/mask-label-manager.d.ts.map +1 -1
- package/dist/types/mask/mask-list.d.ts +11 -12
- package/dist/types/mask/mask-list.d.ts.map +1 -1
- package/dist/types/mask/mask-style.d.ts +19 -20
- package/dist/types/mask/mask-style.d.ts.map +1 -1
- package/dist/types/mosaic/mosaic-controller.d.ts +3 -3
- package/dist/types/mosaic/mosaic-controller.d.ts.map +1 -1
- package/dist/types/ui/visibility-state.d.ts +2 -2
- package/dist/types/utils/file.d.ts +13 -0
- package/dist/types/utils/file.d.ts.map +1 -1
- package/dist/types/utils/image-element-loader.d.ts +19 -0
- package/dist/types/utils/image-element-loader.d.ts.map +1 -0
- package/dist/types/utils/pointer.d.ts +16 -0
- package/dist/types/utils/pointer.d.ts.map +1 -0
- package/dist/umd/image-editor.umd.js +1 -1
- package/dist/umd/image-editor.umd.js.map +1 -1
- package/package.json +1 -1
|
@@ -43,10 +43,9 @@
|
|
|
43
43
|
* @module
|
|
44
44
|
*/
|
|
45
45
|
import type * as FabricNS from 'fabric';
|
|
46
|
-
import type { ImageMimeType } from './public-types.js';
|
|
46
|
+
import type { AnnotationObject, BaseImageObject, ImageMimeType, MaskObject } from './public-types.js';
|
|
47
47
|
/**
|
|
48
|
-
* Per-object payload inside a {@link CanvasJson} snapshot.
|
|
49
|
-
* Pretty_Printer wire format used by the canvas serializer.
|
|
48
|
+
* Per-object payload inside a {@link CanvasJson} snapshot.
|
|
50
49
|
*
|
|
51
50
|
* The `isCropRect` and `maskLabel` markers are filtered out by
|
|
52
51
|
* {@link saveState}, so a snapshot pushed to history will never contain
|
|
@@ -57,6 +56,10 @@ import type { ImageMimeType } from './public-types.js';
|
|
|
57
56
|
export interface CanvasJsonObject {
|
|
58
57
|
/** Fabric shape type discriminator (`'rect'`, `'circle'`, `'image'`, etc.). */
|
|
59
58
|
type?: string;
|
|
59
|
+
/** Editor-owned object discriminator. */
|
|
60
|
+
editorObjectKind?: string;
|
|
61
|
+
/** Session object subtype discriminator. */
|
|
62
|
+
sessionObjectType?: string;
|
|
60
63
|
/** Left-edge pixel coordinate (Fabric serializes `originX: 'left'` masks here). */
|
|
61
64
|
left?: number;
|
|
62
65
|
/** Top-edge pixel coordinate. */
|
|
@@ -89,12 +92,26 @@ export interface CanvasJsonObject {
|
|
|
89
92
|
cornerColor?: string;
|
|
90
93
|
/** Fabric corner control size. */
|
|
91
94
|
cornerSize?: number;
|
|
95
|
+
/** Fabric horizontal flip flag. */
|
|
96
|
+
flipX?: boolean;
|
|
97
|
+
/** Fabric vertical flip flag. */
|
|
98
|
+
flipY?: boolean;
|
|
92
99
|
/** Marks the transient crop rectangle; filtered before history push. */
|
|
93
100
|
isCropRect?: boolean;
|
|
94
101
|
/** Marks a mask label text object; filtered before history push. */
|
|
95
102
|
maskLabel?: boolean;
|
|
96
103
|
/** Marks Mosaic preview objects; filtered before history push. */
|
|
97
104
|
isMosaicPreview?: boolean;
|
|
105
|
+
/** Annotation identifier. */
|
|
106
|
+
annotationId?: number;
|
|
107
|
+
/** Annotation subtype. */
|
|
108
|
+
annotationType?: string;
|
|
109
|
+
/** Annotation display name. */
|
|
110
|
+
annotationName?: string;
|
|
111
|
+
/** Business-level annotation visibility. */
|
|
112
|
+
annotationHidden?: boolean;
|
|
113
|
+
/** Business-level annotation lock state. */
|
|
114
|
+
annotationLocked?: boolean;
|
|
98
115
|
/** Pass-through for every other Fabric-serialized shape property. */
|
|
99
116
|
[key: string]: unknown;
|
|
100
117
|
}
|
|
@@ -112,8 +129,12 @@ export interface EditorStateMeta {
|
|
|
112
129
|
baseImageScale: number;
|
|
113
130
|
/** MIME type of the currently committed image, when known. */
|
|
114
131
|
currentImageMimeType?: ImageMimeType | null;
|
|
132
|
+
/** Active editor-owned object kind when the snapshot was captured, if any. */
|
|
133
|
+
activeObjectKind?: 'mask' | 'annotation' | null;
|
|
115
134
|
/** Mask selected when the snapshot was captured, if any. */
|
|
116
135
|
activeMaskId?: number;
|
|
136
|
+
/** Annotation selected when the snapshot was captured, if any. */
|
|
137
|
+
activeAnnotationId?: number;
|
|
117
138
|
}
|
|
118
139
|
/**
|
|
119
140
|
* Full snapshot envelope. Standard Fabric `toJSON` keys plus the editor
|
|
@@ -141,7 +162,7 @@ export interface CanvasJson {
|
|
|
141
162
|
* cannot mutate the shared array.
|
|
142
163
|
*
|
|
143
164
|
*/
|
|
144
|
-
export declare const SNAPSHOT_CUSTOM_KEYS: readonly ["maskId", "maskUid", "maskName", "isCropRect", "maskLabel", "originalAlpha", "originalStroke", "originalStrokeWidth", "hasControls", "selectable", "strokeUniform", "lockRotation", "transparentCorners", "borderColor", "cornerColor", "cornerSize", "isMosaicPreview"];
|
|
165
|
+
export declare const SNAPSHOT_CUSTOM_KEYS: readonly ["editorObjectKind", "sessionObjectType", "maskId", "maskUid", "maskName", "isCropRect", "maskLabel", "originalAlpha", "originalStroke", "originalStrokeWidth", "hasControls", "selectable", "strokeUniform", "lockRotation", "transparentCorners", "borderColor", "cornerColor", "cornerSize", "flipX", "flipY", "isMosaicPreview", "annotationId", "annotationType", "annotationName", "annotationHidden", "annotationLocked"];
|
|
145
166
|
/**
|
|
146
167
|
* Inputs to {@link saveState}. The editor facade passes the live canvas
|
|
147
168
|
* plus the three transform fields that make up `_editorState`.
|
|
@@ -151,6 +172,8 @@ export interface SaveStateInput {
|
|
|
151
172
|
canvas: FabricNS.Canvas;
|
|
152
173
|
/** Active mask id supplied by the facade when Fabric active state is unavailable. */
|
|
153
174
|
activeMaskId?: number | null;
|
|
175
|
+
/** Active annotation id supplied by the facade when Fabric active state is unavailable. */
|
|
176
|
+
activeAnnotationId?: number | null;
|
|
154
177
|
/** Current image zoom factor (mirrored into `_editorState.currentScale`). */
|
|
155
178
|
currentScale: number;
|
|
156
179
|
/** Current image rotation in degrees (mirrored into `_editorState.currentRotation`). */
|
|
@@ -239,19 +262,25 @@ export interface LoadFromStateResult {
|
|
|
239
262
|
* `createMask` calls do not collide with restored IDs.
|
|
240
263
|
*/
|
|
241
264
|
maxMaskId: number;
|
|
265
|
+
/** Highest `annotationId` observed on restored annotation objects. */
|
|
266
|
+
maxAnnotationId: number;
|
|
242
267
|
/**
|
|
243
268
|
* The first `'image'` object that is NOT a mask, or `null`. Used by the
|
|
244
269
|
* facade to set `selectable: false`, `evented: false`, and to send the
|
|
245
270
|
* image to the back of the stacking order. The serializer does not
|
|
246
271
|
* mutate the object itself.
|
|
247
272
|
*/
|
|
248
|
-
originalImage:
|
|
273
|
+
originalImage: BaseImageObject | null;
|
|
249
274
|
/**
|
|
250
275
|
* All canvas objects after restore, in `getObjects` order. The facade
|
|
251
276
|
* uses this list to re-attach mask hover handlers and to drive the
|
|
252
277
|
* `isImageLoadedToCanvas` flag.
|
|
253
278
|
*/
|
|
254
279
|
objects: FabricNS.FabricObject[];
|
|
280
|
+
/** Restored mask objects. */
|
|
281
|
+
masks: MaskObject[];
|
|
282
|
+
/** Restored annotation objects. */
|
|
283
|
+
annotations: AnnotationObject[];
|
|
255
284
|
/**
|
|
256
285
|
* The canonical JSON string for the snapshot — equal to the input string
|
|
257
286
|
* if a string was passed, or `JSON.stringify(input)` if a `CanvasJson`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"state-serializer.d.ts","sourceRoot":"","sources":["../../../src/core/state-serializer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAEH,OAAO,KAAK,KAAK,QAAQ,MAAM,QAAQ,CAAC;AAExC,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"state-serializer.d.ts","sourceRoot":"","sources":["../../../src/core/state-serializer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAEH,OAAO,KAAK,KAAK,QAAQ,MAAM,QAAQ,CAAC;AAExC,OAAO,KAAK,EACR,gBAAgB,EAChB,eAAe,EACf,aAAa,EACb,UAAU,EACb,MAAM,mBAAmB,CAAC;AAM3B;;;;;;;;GAQG;AACH,MAAM,WAAW,gBAAgB;IAC7B,+EAA+E;IAC/E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,yCAAyC;IACzC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,4CAA4C;IAC5C,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,mFAAmF;IACnF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,iCAAiC;IACjC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,8BAA8B;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,sEAAsE;IACtE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,yDAAyD;IACzD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,4DAA4D;IAC5D,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,mEAAmE;IACnE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,yEAAyE;IACzE,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,sCAAsC;IACtC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,6BAA6B;IAC7B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,0CAA0C;IAC1C,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,iCAAiC;IACjC,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,8CAA8C;IAC9C,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,qCAAqC;IACrC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mCAAmC;IACnC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kCAAkC;IAClC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,mCAAmC;IACnC,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,iCAAiC;IACjC,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,wEAAwE;IACxE,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,oEAAoE;IACpE,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,kEAAkE;IAClE,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,6BAA6B;IAC7B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,0BAA0B;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,+BAA+B;IAC/B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,4CAA4C;IAC5C,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,4CAA4C;IAC5C,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,qEAAqE;IACrE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CAC1B;AAED;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC5B,+CAA+C;IAC/C,YAAY,EAAE,MAAM,CAAC;IACrB,uDAAuD;IACvD,eAAe,EAAE,MAAM,CAAC;IACxB,yEAAyE;IACzE,cAAc,EAAE,MAAM,CAAC;IACvB,8DAA8D;IAC9D,oBAAoB,CAAC,EAAE,aAAa,GAAG,IAAI,CAAC;IAC5C,8EAA8E;IAC9E,gBAAgB,CAAC,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAAC;IAChD,4DAA4D;IAC5D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kEAAkE;IAClE,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED;;;GAGG;AACH,MAAM,WAAW,UAAU;IACvB,wDAAwD;IACxD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,0DAA0D;IAC1D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2DAA2D;IAC3D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,6DAA6D;IAC7D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,+CAA+C;IAC/C,OAAO,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC7B,iCAAiC;IACjC,YAAY,CAAC,EAAE,eAAe,CAAC;IAC/B,gEAAgE;IAChE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CAC1B;AAED;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,2aA2BvB,CAAC;AAoHX;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC3B,kCAAkC;IAClC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC;IACxB,qFAAqF;IACrF,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,2FAA2F;IAC3F,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,6EAA6E;IAC7E,YAAY,EAAE,MAAM,CAAC;IACrB,wFAAwF;IACxF,eAAe,EAAE,MAAM,CAAC;IACxB,oFAAoF;IACpF,cAAc,EAAE,MAAM,CAAC;IACvB,4EAA4E;IAC5E,oBAAoB,CAAC,EAAE,aAAa,GAAG,IAAI,CAAC;CAC/C;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,GAAG,MAAM,CAgEvD;AAID;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IAC/B,yCAAyC;IACzC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC;IACxB;;;;;;;OAOG;IACH,UAAU,EAAE,MAAM,GAAG,UAAU,CAAC;IAChC;;;OAGG;IACH,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CAC1D;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,mBAAmB;IAChC;;;;;OAKG;IACH,WAAW,EAAE,eAAe,GAAG,IAAI,CAAC;IACpC;;;;OAIG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB,sEAAsE;IACtE,eAAe,EAAE,MAAM,CAAC;IACxB;;;;;OAKG;IACH,aAAa,EAAE,eAAe,GAAG,IAAI,CAAC;IACtC;;;;OAIG;IACH,OAAO,EAAE,QAAQ,CAAC,YAAY,EAAE,CAAC;IACjC,6BAA6B;IAC7B,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,mCAAmC;IACnC,WAAW,EAAE,gBAAgB,EAAE,CAAC;IAChC;;;;;OAKG;IACH,UAAU,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,wBAAsB,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAmG3F"}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Crop session lifecycle owner. Implements the
|
|
3
3
|
* `enterCropMode → applyCrop` and
|
|
4
4
|
* `enterCropMode → cancelCrop` transitions atop the
|
|
5
|
-
*
|
|
5
|
+
* crop export/load pipeline, plus the dedicated crop rectangle
|
|
6
6
|
* shape, its drag/scale clamps, and the per-object
|
|
7
7
|
* `evented`/`selectable` freeze that keeps only the crop
|
|
8
8
|
* rectangle interactive while a session is open.
|
|
@@ -66,10 +66,9 @@
|
|
|
66
66
|
* `left` and `top` shifted by `-cropRegion.left, -cropRegion.top`.
|
|
67
67
|
* Per-mask `angle`, `scaleX`, and `scaleY` are restored verbatim so
|
|
68
68
|
* the visible mask shape does not change size or orientation. The
|
|
69
|
-
* cropRegion-relative shift
|
|
69
|
+
* cropRegion-relative shift preserves the historical
|
|
70
70
|
* `_translateObjectByCanvasOffset(mask, -cropRegion.sourceX,
|
|
71
|
-
* -cropRegion.sourceY)`
|
|
72
|
-
* preserve. Because shifting `left` / `top` by a constant translates
|
|
71
|
+
* -cropRegion.sourceY)` behavior. Because shifting `left` / `top` by a constant translates
|
|
73
72
|
* the entire object (including its rotated visual) by the same
|
|
74
73
|
* constant in canvas pixels, the post-crop position relative to the
|
|
75
74
|
* new image bounding box matches the pre-crop position relative to
|
|
@@ -87,7 +86,7 @@
|
|
|
87
86
|
* before export and re-adds the masks shifted by
|
|
88
87
|
* `-cropRegion.left, -cropRegion.top` after
|
|
89
88
|
* `context.loadImage(croppedBase64)` commits. The intersection filter
|
|
90
|
-
* drops masks that do not overlap the crop region, matching
|
|
89
|
+
* drops masks that do not overlap the crop region, matching the documented
|
|
91
90
|
* observable behavior: masks fully outside the cropped region are
|
|
92
91
|
* removed, while intersecting masks are preserved.
|
|
93
92
|
*
|
|
@@ -97,21 +96,21 @@
|
|
|
97
96
|
* {@link CropControllerContext}. The `ImageEditor` facade keeps
|
|
98
97
|
* ownership of the canonical session pointer (`getCropSession` /
|
|
99
98
|
* `setCropSession`) so multiple editors on the same page do not share
|
|
100
|
-
* crop state and
|
|
99
|
+
* crop state and unit tests can exercise the controller
|
|
101
100
|
* without instantiating the full facade.
|
|
102
101
|
* - The crop rectangle's drag/scale handlers clamp `scaleX` / `scaleY`
|
|
103
102
|
* so the rect cannot grow past the available image bounding box and
|
|
104
103
|
* cannot shrink below the configured `crop.minWidth` / `crop.minHeight`.
|
|
105
104
|
* This matches legacy's `handleCropRectModified`.
|
|
106
|
-
* - In Fabric v7
|
|
107
|
-
* `
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
105
|
+
* - In Fabric v7 crop rectangle controls are configured via
|
|
106
|
+
* `setControlsVisibility(...)` because `hasRotatingPoint` is silently
|
|
107
|
+
* ignored. `lockRotation: true` is also set as runtime defence so the
|
|
108
|
+
* rotation transform itself cannot fire even if the handle were somehow
|
|
109
|
+
* shown.
|
|
111
110
|
* - The pre-crop snapshot is captured once, in `enterCropMode`, and
|
|
112
111
|
* reused by `applyCrop`'s history command and rollback path. This
|
|
113
112
|
* avoids a re-serialization right before the crop, and — more
|
|
114
|
-
* importantly — avoids the
|
|
113
|
+
* importantly — avoids the historical fragility of filtering `isCropRect`
|
|
115
114
|
* objects out of a post-rect snapshot when Fabric's custom-key
|
|
116
115
|
* serializer occasionally drops the marker.
|
|
117
116
|
*
|
|
@@ -122,7 +121,7 @@
|
|
|
122
121
|
* @module
|
|
123
122
|
*/
|
|
124
123
|
import type * as FabricNS from 'fabric';
|
|
125
|
-
import type { CropHandler, CropPrevEvented, FabricModule, ImageMimeType, LoadImageOptions, MaskBackup, ResolvedOptions } from '../core/public-types.js';
|
|
124
|
+
import type { CropAspectRatio, CropHandler, CropModeOptions, CropPrevEvented, FabricModule, ImageMimeType, LoadImageOptions, MaskBackup, ResolvedOptions } from '../core/public-types.js';
|
|
126
125
|
import { type HistoryManager } from '../history/history-manager.js';
|
|
127
126
|
/**
|
|
128
127
|
* Internal state of an open crop session. Built by {@link enterCropMode},
|
|
@@ -153,6 +152,7 @@ import { type HistoryManager } from '../history/history-manager.js';
|
|
|
153
152
|
* - `cropRect` — the active crop rectangle, or `null` after the rect has
|
|
154
153
|
* been removed (so subsequent calls to {@link removeCropRect} are
|
|
155
154
|
* idempotent on the success and rollback paths).
|
|
155
|
+
* - `aspectRatio` — current crop aspect-ratio lock. `null` means free crop.
|
|
156
156
|
* - `handlers` — bound `modified` / `moving` / `scaling` handler records
|
|
157
157
|
* on the crop rectangle. Detached when the session ends.
|
|
158
158
|
*
|
|
@@ -164,6 +164,7 @@ export interface CropSession {
|
|
|
164
164
|
/** Per-mask style backups captured when masks are hidden during crop mode. */
|
|
165
165
|
maskBackups: MaskBackup[];
|
|
166
166
|
cropRect: FabricNS.Rect | null;
|
|
167
|
+
aspectRatio: NormalizedCropAspectRatio;
|
|
167
168
|
handlers: CropHandler[];
|
|
168
169
|
}
|
|
169
170
|
/**
|
|
@@ -256,6 +257,8 @@ export interface CropControllerContext {
|
|
|
256
257
|
*/
|
|
257
258
|
updateMaskList?(): void;
|
|
258
259
|
}
|
|
260
|
+
export type NormalizedCropAspectRatio = number | null;
|
|
261
|
+
export declare function normalizeCropAspectRatio(input: CropAspectRatio | null | undefined): NormalizedCropAspectRatio;
|
|
259
262
|
/**
|
|
260
263
|
* Open a crop session. Builds a {@link CropSession} that captures:
|
|
261
264
|
*
|
|
@@ -299,7 +302,8 @@ export interface CropControllerContext {
|
|
|
299
302
|
* @param context - Editor dependency bundle — see {@link CropControllerContext}.
|
|
300
303
|
*
|
|
301
304
|
*/
|
|
302
|
-
export declare function enterCropMode(context: CropControllerContext): void;
|
|
305
|
+
export declare function enterCropMode(context: CropControllerContext, cropModeOptions?: CropModeOptions): void;
|
|
306
|
+
export declare function setCropAspectRatio(context: CropControllerContext, aspectRatioInput: CropAspectRatio | null | undefined): void;
|
|
303
307
|
/**
|
|
304
308
|
* Close an open crop session WITHOUT applying the crop. Restores the
|
|
305
309
|
* pre-crop `canvas.selection`, the per-object `evented` / `selectable`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"crop-controller.d.ts","sourceRoot":"","sources":["../../../src/crop/crop-controller.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"crop-controller.d.ts","sourceRoot":"","sources":["../../../src/crop/crop-controller.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyHG;AAEH,OAAO,KAAK,KAAK,QAAQ,MAAM,QAAQ,CAAC;AAIxC,OAAO,KAAK,EACR,eAAe,EACf,WAAW,EACX,eAAe,EACf,eAAe,EACf,YAAY,EACZ,aAAa,EACb,gBAAgB,EAChB,UAAU,EAGV,eAAe,EAClB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EAAW,KAAK,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAoB7E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,MAAM,WAAW,WAAW;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,OAAO,CAAC;IACvB,WAAW,EAAE,eAAe,EAAE,CAAC;IAC/B,8EAA8E;IAC9E,WAAW,EAAE,UAAU,EAAE,CAAC;IAC1B,QAAQ,EAAE,QAAQ,CAAC,IAAI,GAAG,IAAI,CAAC;IAC/B,WAAW,EAAE,yBAAyB,CAAC;IACvC,QAAQ,EAAE,WAAW,EAAE,CAAC;CAC3B;AAID;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,qBAAqB;IAClC,6DAA6D;IAC7D,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,0BAA0B;IAC1B,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC;IACjC;;yEAEqE;IACrE,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC;IAClC,uEAAuE;IACvE,QAAQ,CAAC,cAAc,EAAE,cAAc,CAAC;IAExC;;;;;;OAMG;IACH,aAAa,IAAI,OAAO,CAAC;IAEzB;;;;OAIG;IACH,gBAAgB,IAAI,QAAQ,CAAC,WAAW,GAAG,IAAI,CAAC;IAEhD;;;OAGG;IACH,uBAAuB,CAAC,IAAI,aAAa,GAAG,IAAI,CAAC;IAEjD,8CAA8C;IAC9C,cAAc,IAAI,WAAW,GAAG,IAAI,CAAC;IACrC,uEAAuE;IACvE,cAAc,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI,GAAG,IAAI,CAAC;IAElD;;;;;OAKG;IACH,SAAS,IAAI,MAAM,CAAC;IAEpB;;;;OAIG;IACH,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE/C;;;;OAIG;IACH,SAAS,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE1E;;;;;;;;;;OAUG;IACH,cAAc,CAAC,IAAI,MAAM,CAAC;IAE1B;;;OAGG;IACH,cAAc,CAAC,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAEjC;;;;;OAKG;IACH,cAAc,CAAC,IAAI,IAAI,CAAC;CAC3B;AA4bD,MAAM,MAAM,yBAAyB,GAAG,MAAM,GAAG,IAAI,CAAC;AActD,wBAAgB,wBAAwB,CACpC,KAAK,EAAE,eAAe,GAAG,IAAI,GAAG,SAAS,GAC1C,yBAAyB,CA+B3B;AAuOD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AACH,wBAAgB,aAAa,CACzB,OAAO,EAAE,qBAAqB,EAC9B,eAAe,GAAE,eAAoB,GACtC,IAAI,CAyON;AAED,wBAAgB,kBAAkB,CAC9B,OAAO,EAAE,qBAAqB,EAC9B,gBAAgB,EAAE,eAAe,GAAG,IAAI,GAAG,SAAS,GACrD,IAAI,CAcN;AAID;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI,CAiB/D;AAID;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkFG;AACH,wBAAsB,SAAS,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CAoJ7E"}
|
|
@@ -1,41 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* The module owns three small, individually testable building blocks plus
|
|
7
|
-
* one orchestrating function, mirroring the shape of
|
|
8
|
-
* `image/image-resampler.ts`:
|
|
9
|
-
*
|
|
10
|
-
* - {@link normalizeImageFormat} — collapses `'jpg'` to `'jpeg'`, strips
|
|
11
|
-
* the `image/` MIME prefix, and falls back to `'jpeg'` for unknown or
|
|
12
|
-
* omitted input.
|
|
13
|
-
* - {@link mimeTypeFor} — derives the matching `image/...` MIME
|
|
14
|
-
* for a normalized format token.
|
|
15
|
-
* - {@link clampQuality} — coerces input to a finite number and
|
|
16
|
-
* clamps it into `[0, 1]`, falling back to a caller-supplied default
|
|
17
|
-
* when the input is not finite.
|
|
18
|
-
* - {@link resolveExportFormat} — composes the above with the documented
|
|
19
|
-
* `fileType`-wins-over-`format` precedence and drops `quality` for PNG
|
|
20
|
-
* output.
|
|
21
|
-
*
|
|
22
|
-
* legacy parity:
|
|
23
|
-
* - The format mapping table mirrors `_normalizeImageFormat` from
|
|
24
|
-
* `src/image-editor.js@legacy.4.0`, including the lowercase lookup and the
|
|
25
|
-
* `'jpeg'` default for unknown input.
|
|
26
|
-
* - The quality clamp mirrors `_normalizeQuality` from the same legacy file:
|
|
27
|
-
* non-finite input falls back to `options.downsampleQuality`, finite
|
|
28
|
-
* input is clamped to `[0, 1]`.
|
|
29
|
-
*
|
|
30
|
-
* This module is internal — it is NOT re-exported from `src/index.ts`.
|
|
31
|
-
*
|
|
32
|
-
* Fabric.
|
|
33
|
-
* lossless.
|
|
34
|
-
* `quality` defaulting to `options.downsampleQuality`.
|
|
2
|
+
* Export format normalization helpers.
|
|
3
|
+
*
|
|
4
|
+
* Converts public `ImageExportOptions` values into the normalized format,
|
|
5
|
+
* MIME type, and quality values consumed by `export/export-service.ts`.
|
|
35
6
|
*
|
|
36
7
|
* @module
|
|
37
8
|
*/
|
|
38
|
-
import type {
|
|
9
|
+
import type { ImageExportOptions, ImageMimeType, NormalizedImageFormat } from '../core/public-types.js';
|
|
39
10
|
/**
|
|
40
11
|
* Result of {@link resolveExportFormat}.
|
|
41
12
|
*
|
|
@@ -109,7 +80,7 @@ export declare function clampQuality(quality: unknown, fallback: number): number
|
|
|
109
80
|
* Resolve the user-facing export options into the canvas-/Fabric-shaped
|
|
110
81
|
* values consumed by `export/export-service.ts`.
|
|
111
82
|
*
|
|
112
|
-
* Precedence
|
|
83
|
+
* Precedence:
|
|
113
84
|
* 1. `options.fileType` wins over `options.format` when both are supplied
|
|
114
85
|
* and `options.fileType` is truthy. Falsy `fileType` falls through to
|
|
115
86
|
* `options.format`. Both omitted → `'jpeg'`.
|
|
@@ -121,16 +92,14 @@ export declare function clampQuality(quality: unknown, fallback: number): number
|
|
|
121
92
|
*
|
|
122
93
|
* Pure function — no DOM access, safe to call from property tests.
|
|
123
94
|
*
|
|
124
|
-
* @param options - Subset of `
|
|
125
|
-
* `ImageFileExportOptions` carrying `fileType`,
|
|
95
|
+
* @param options - Subset of `ImageExportOptions` carrying `fileType`,
|
|
126
96
|
* `format`, and `quality`. Other fields are
|
|
127
|
-
* ignored.
|
|
128
|
-
* that declare it (i.e. `Base64ExportOptions`).
|
|
97
|
+
* ignored.
|
|
129
98
|
* @param downsampleQuality - Default quality used when `options.quality` is
|
|
130
99
|
* omitted or non-finite. Sourced from
|
|
131
100
|
* `ResolvedOptions.downsampleQuality`.
|
|
132
101
|
* @returns The resolved `{ format, mimeType, quality}` triple.
|
|
133
102
|
*
|
|
134
103
|
*/
|
|
135
|
-
export declare function resolveExportFormat(options: Pick<
|
|
104
|
+
export declare function resolveExportFormat(options: Pick<ImageExportOptions, 'fileType' | 'format' | 'quality'> | undefined | null, downsampleQuality: number): ResolvedExportFormat;
|
|
136
105
|
//# sourceMappingURL=export-format.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"export-format.d.ts","sourceRoot":"","sources":["../../../src/export/export-format.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"export-format.d.ts","sourceRoot":"","sources":["../../../src/export/export-format.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EACR,kBAAkB,EAClB,aAAa,EACb,qBAAqB,EACxB,MAAM,yBAAyB,CAAC;AAEjC;;;;;;GAMG;AACH,MAAM,WAAW,oBAAoB;IACjC,8CAA8C;IAC9C,MAAM,EAAE,qBAAqB,CAAC;IAC9B,gEAAgE;IAChE,QAAQ,EAAE,aAAa,CAAC;IACxB,yDAAyD;IACzD,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;CAC/B;AA+BD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,qBAAqB,CAEjF;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,qBAAqB,GAAG,IAAI,CAS3F;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,qBAAqB,GAAG,aAAa,CAExE;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAIvE;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,mBAAmB,CAC/B,OAAO,EAAE,IAAI,CAAC,kBAAkB,EAAE,UAAU,GAAG,QAAQ,GAAG,SAAS,CAAC,GAAG,SAAS,GAAG,IAAI,EACvF,iBAAiB,EAAE,MAAM,GAC1B,oBAAoB,CA8BtB"}
|
|
@@ -13,17 +13,17 @@
|
|
|
13
13
|
* so it is not serialized into the output. The discard is performed
|
|
14
14
|
* unconditionally; calling `canvas.discardActiveObject` with no active
|
|
15
15
|
* selection is a documented no-op.
|
|
16
|
-
* - `exportImageBase64(options?:
|
|
17
|
-
* is the
|
|
18
|
-
* `fileType` and `format` for ergonomic interop and
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
* - `downloadImage(
|
|
25
|
-
*
|
|
26
|
-
*
|
|
16
|
+
* - `exportImageBase64(options?: ImageExportOptions)`
|
|
17
|
+
* is the canonical base64 export entry point. It accepts both
|
|
18
|
+
* `fileType` and `format` for ergonomic interop and returns a
|
|
19
|
+
* `Promise<string>` resolving to a `data:image/...;base64...` data URL.
|
|
20
|
+
* - `exportImageFile(options?: ImageExportOptions)` resolves to a `File`
|
|
21
|
+
* whose name comes from `options.fileName` or the editor's
|
|
22
|
+
* `defaultDownloadFileName`, with the final extension resolved from
|
|
23
|
+
* the output format.
|
|
24
|
+
* - `downloadImage(options?: ImageExportOptions)` triggers a browser
|
|
25
|
+
* download through a generated object URL. The bytes match the same
|
|
26
|
+
* rendering core used by `exportImageBase64` and `exportImageFile`.
|
|
27
27
|
* - When `isImageLoaded` is `false`, the three
|
|
28
28
|
* entry points exhibit the documented "no image loaded" shapes:
|
|
29
29
|
*
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
* | -------------------- | ----------------------------------- |
|
|
32
32
|
* | `exportImageBase64` | resolves to `''` |
|
|
33
33
|
* | `exportImageFile` | rejects with `ExportNotReadyError` |
|
|
34
|
-
* | `downloadImage` |
|
|
34
|
+
* | `downloadImage` | resolves without throwing |
|
|
35
35
|
*
|
|
36
36
|
* Each path emits a single `console.warn` naming the missing image so
|
|
37
37
|
* the consumer's logs identify which export attempt was skipped.
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
* No intermediate `<canvas>` element is created, and sub-pixel
|
|
43
43
|
* width/height values are floored to integer pixels through the
|
|
44
44
|
* {@link floorRegion} helper before Fabric receives the region.
|
|
45
|
-
* - When `
|
|
45
|
+
* - When `mergeMasks` is
|
|
46
46
|
* `true`, every mask's live style (`opacity`, `fill`, `stroke`,
|
|
47
47
|
* `strokeWidth`, `selectable`, `lockRotation`) is captured BEFORE the
|
|
48
48
|
* mutator forces the bake-in style (`opacity: 1, fill: '#000',
|
|
@@ -91,8 +91,9 @@
|
|
|
91
91
|
* @module
|
|
92
92
|
*/
|
|
93
93
|
import type * as FabricNS from 'fabric';
|
|
94
|
-
import type {
|
|
95
|
-
import {
|
|
94
|
+
import type { FabricModule, ImageExportOptions, LoadImageOptions, AnnotationObject, MaskObject, ResolvedOptions } from '../core/public-types.js';
|
|
95
|
+
import type { HistoryManager } from '../history/history-manager.js';
|
|
96
|
+
import { type OverlayMergeTransactionContext } from './overlay-merge-service.js';
|
|
96
97
|
/**
|
|
97
98
|
* Dependency bundle passed by the `ImageEditor` facade into every export
|
|
98
99
|
* entry point. The service has no class state of its own — every editor
|
|
@@ -150,60 +151,56 @@ export interface ExportServiceContext {
|
|
|
150
151
|
* 6. **Render** through {@link withMaskExportState} so mask styles are
|
|
151
152
|
* captured, the export bake-in (`opacity: 1, fill: '#000',
|
|
152
153
|
* strokeWidth: 0, stroke: null, selectable: false`) is applied for
|
|
153
|
-
* `
|
|
154
|
+
* `mergeMasks === true` exports, and the live styles are
|
|
154
155
|
* restored in a `finally` block whether the render resolved or
|
|
155
156
|
* threw. The inner step is a single
|
|
156
157
|
* `canvas.toDataURL` call — no intermediate `<canvas>`.
|
|
157
158
|
*
|
|
158
159
|
* @param context - Export context bundle.
|
|
159
|
-
* @param options - Optional {@link
|
|
160
|
+
* @param options - Optional {@link ImageExportOptions}. Both `fileType`
|
|
160
161
|
* and `format` are accepted; when
|
|
161
162
|
* both are supplied, `fileType` wins.
|
|
162
163
|
* @returns Resolves to a `data:image/...;base64...` URL on
|
|
163
164
|
* success, or `''` when no image is loaded.
|
|
164
165
|
*
|
|
165
166
|
*/
|
|
166
|
-
export declare function exportImageBase64(context: ExportServiceContext, options?:
|
|
167
|
+
export declare function exportImageBase64(context: ExportServiceContext, options?: ImageExportOptions): Promise<string>;
|
|
167
168
|
/**
|
|
168
169
|
* Render the live canvas to a `File`.
|
|
169
170
|
*
|
|
170
|
-
* The bytes come from
|
|
171
|
-
*
|
|
172
|
-
*
|
|
171
|
+
* The bytes come from the same private rendering core used by
|
|
172
|
+
* {@link exportImageBase64}. The resulting data URL is repainted
|
|
173
|
+
* through an offscreen `<canvas>` only
|
|
173
174
|
* when its MIME prefix does not match the requested type — some browsers
|
|
174
175
|
* silently fall back to PNG when the requested format is unsupported,
|
|
175
176
|
* and the export contract requires the output MIME to match the resolved
|
|
176
177
|
* `fileType`.
|
|
177
178
|
*
|
|
178
179
|
* @param context - Export context bundle.
|
|
179
|
-
* @param options - Optional {@link
|
|
180
|
+
* @param options - Optional {@link ImageExportOptions}.
|
|
180
181
|
* @returns Resolves with the rendered `File`.
|
|
181
182
|
* @throws {@link ExportNotReadyError} when no image is loaded.
|
|
182
183
|
*
|
|
183
184
|
*/
|
|
184
|
-
export declare function exportImageFile(context: ExportServiceContext, options?:
|
|
185
|
+
export declare function exportImageFile(context: ExportServiceContext, options?: ImageExportOptions): Promise<File>;
|
|
185
186
|
/**
|
|
186
187
|
* Trigger a browser download of the live canvas.
|
|
187
188
|
*
|
|
188
|
-
* Mirrors legacy's "anchor with `download` attribute" approach:
|
|
189
|
-
*
|
|
190
|
-
* so Firefox dispatches the click
|
|
191
|
-
* returns synchronously; the data URL is rendered
|
|
192
|
-
* asynchronously and the click is deferred until that promise resolves.
|
|
189
|
+
* Mirrors legacy's "anchor with `download` attribute" approach: a `File`
|
|
190
|
+
* is rendered, an object URL is created, and an `<a>` element is appended
|
|
191
|
+
* to the document so Firefox dispatches the click.
|
|
193
192
|
*
|
|
194
193
|
* No-image gate emits the same `console.warn` as the
|
|
195
194
|
* other entry points and returns without touching the DOM.
|
|
196
195
|
*
|
|
197
|
-
* Errors raised by the underlying
|
|
198
|
-
*
|
|
199
|
-
* `void` and there is no caller-visible promise to reject.
|
|
196
|
+
* Errors raised by the underlying export are reported with `console.error`
|
|
197
|
+
* and rethrown through the returned promise.
|
|
200
198
|
*
|
|
201
199
|
* @param context - Export context bundle.
|
|
202
|
-
* @param
|
|
203
|
-
* `options.defaultDownloadFileName`.
|
|
200
|
+
* @param options - Optional {@link ImageExportOptions}.
|
|
204
201
|
*
|
|
205
202
|
*/
|
|
206
|
-
export declare function downloadImage(context: ExportServiceContext,
|
|
203
|
+
export declare function downloadImage(context: ExportServiceContext, options?: ImageExportOptions): Promise<void>;
|
|
207
204
|
/**
|
|
208
205
|
* Dependency bundle passed by the `ImageEditor` facade into
|
|
209
206
|
* {@link mergeMasks}. Extends {@link ExportServiceContext} with the
|
|
@@ -229,7 +226,7 @@ export declare function downloadImage(context: ExportServiceContext, fileName?:
|
|
|
229
226
|
* this bundle from its own state.
|
|
230
227
|
*
|
|
231
228
|
*/
|
|
232
|
-
export interface MergeMasksContext extends ExportServiceContext {
|
|
229
|
+
export interface MergeMasksContext extends ExportServiceContext, OverlayMergeTransactionContext {
|
|
233
230
|
/** History manager that records the single merge command. */
|
|
234
231
|
readonly historyManager: HistoryManager;
|
|
235
232
|
/**
|
|
@@ -246,12 +243,6 @@ export interface MergeMasksContext extends ExportServiceContext {
|
|
|
246
243
|
* the success path.
|
|
247
244
|
*/
|
|
248
245
|
loadImage(imageBase64: string, options?: LoadImageOptions): Promise<void>;
|
|
249
|
-
/**
|
|
250
|
-
* Capture a snapshot suitable for {@link loadFromStateFn}. Reads the
|
|
251
|
-
* orchestrator's `lastSnapshot`-producing path so the merge stores
|
|
252
|
-
* exactly the same wire format used by `undo` / `redo`.
|
|
253
|
-
*/
|
|
254
|
-
saveState(): string;
|
|
255
246
|
/**
|
|
256
247
|
* Restore a snapshot produced by {@link saveStateFn}. Used both as
|
|
257
248
|
* the `undo` callback of the merge command and
|
|
@@ -265,6 +256,18 @@ export interface MergeMasksContext extends ExportServiceContext {
|
|
|
265
256
|
* of its own history push.
|
|
266
257
|
*/
|
|
267
258
|
removeAllMasksNoHistory(): void;
|
|
259
|
+
getAnnotations(): AnnotationObject[];
|
|
260
|
+
restoreAnnotations(objects: AnnotationObject[]): void | Promise<void>;
|
|
261
|
+
}
|
|
262
|
+
export interface MergeAnnotationsContext extends ExportServiceContext, OverlayMergeTransactionContext {
|
|
263
|
+
readonly historyManager: HistoryManager;
|
|
264
|
+
readonly containerElement: HTMLElement | null;
|
|
265
|
+
loadImage(imageBase64: string, options?: LoadImageOptions): Promise<void>;
|
|
266
|
+
captureSnapshot(): string;
|
|
267
|
+
loadFromState(snapshot: string): Promise<void>;
|
|
268
|
+
removeAllAnnotationsNoHistory(): void;
|
|
269
|
+
getMasks(): MaskObject[];
|
|
270
|
+
restoreMasks(objects: MaskObject[]): void | Promise<void>;
|
|
268
271
|
}
|
|
269
272
|
/**
|
|
270
273
|
* Flatten every mask into the base image and reload the flattened
|
|
@@ -330,4 +333,5 @@ export interface MergeMasksContext extends ExportServiceContext {
|
|
|
330
333
|
*
|
|
331
334
|
*/
|
|
332
335
|
export declare function mergeMasks(context: MergeMasksContext): Promise<void>;
|
|
336
|
+
export declare function mergeAnnotations(context: MergeAnnotationsContext): Promise<void>;
|
|
333
337
|
//# sourceMappingURL=export-service.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"export-service.d.ts","sourceRoot":"","sources":["../../../src/export/export-service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2FG;AAEH,OAAO,KAAK,KAAK,QAAQ,MAAM,QAAQ,CAAC;AAIxC,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"export-service.d.ts","sourceRoot":"","sources":["../../../src/export/export-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared transaction service for baking editable overlays into the base image.
|
|
3
|
+
*
|
|
4
|
+
* Mask and annotation merges use the same snapshot, export, reload, restore,
|
|
5
|
+
* history, and rollback flow while preserving the opposite overlay group.
|
|
6
|
+
*
|
|
7
|
+
* @module
|
|
8
|
+
*/
|
|
9
|
+
import type * as FabricNS from 'fabric';
|
|
10
|
+
import type { AnnotationObject, ImageExportOptions, LoadImageOptions, MaskObject, ResolvedOptions } from '../core/public-types.js';
|
|
11
|
+
import { type HistoryManager } from '../history/history-manager.js';
|
|
12
|
+
export type OverlayMergeOperation = 'mergeMasks' | 'mergeAnnotations';
|
|
13
|
+
export interface OverlayMergeTransactionContext {
|
|
14
|
+
readonly canvas: FabricNS.Canvas;
|
|
15
|
+
readonly options: ResolvedOptions;
|
|
16
|
+
readonly historyManager: HistoryManager;
|
|
17
|
+
readonly containerElement: HTMLElement | null;
|
|
18
|
+
isImageLoaded(): boolean;
|
|
19
|
+
captureSnapshot(): string;
|
|
20
|
+
loadFromState(snapshot: string): Promise<void>;
|
|
21
|
+
loadImage(imageBase64: string, options?: LoadImageOptions): Promise<void>;
|
|
22
|
+
exportImageBase64(options: ImageExportOptions): Promise<string>;
|
|
23
|
+
updateUi(): void;
|
|
24
|
+
updateInputs(): void;
|
|
25
|
+
}
|
|
26
|
+
export interface OverlayMergeGroupOptions<TTarget extends FabricNS.FabricObject, TPreserved extends FabricNS.FabricObject> {
|
|
27
|
+
operation: OverlayMergeOperation;
|
|
28
|
+
exportOptions: ImageExportOptions & {
|
|
29
|
+
exportArea: 'image';
|
|
30
|
+
fileType: 'png';
|
|
31
|
+
};
|
|
32
|
+
getTargets(): TTarget[];
|
|
33
|
+
getPreservedObjects(): TPreserved[];
|
|
34
|
+
removeTargetsNoHistory(): void;
|
|
35
|
+
restorePreservedObjects(objects: TPreserved[]): void | Promise<void>;
|
|
36
|
+
}
|
|
37
|
+
export declare function flattenOverlayGroupToBaseImage<TTarget extends MaskObject | AnnotationObject, TPreserved extends MaskObject | AnnotationObject>(context: OverlayMergeTransactionContext, options: OverlayMergeGroupOptions<TTarget, TPreserved>): Promise<void>;
|
|
38
|
+
//# sourceMappingURL=overlay-merge-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"overlay-merge-service.d.ts","sourceRoot":"","sources":["../../../src/export/overlay-merge-service.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,KAAK,QAAQ,MAAM,QAAQ,CAAC;AAIxC,OAAO,KAAK,EACR,gBAAgB,EAChB,kBAAkB,EAClB,gBAAgB,EAChB,UAAU,EACV,eAAe,EAClB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAW,KAAK,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAE7E,MAAM,MAAM,qBAAqB,GAAG,YAAY,GAAG,kBAAkB,CAAC;AAEtE,MAAM,WAAW,8BAA8B;IAC3C,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC;IACjC,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC;IAClC,QAAQ,CAAC,cAAc,EAAE,cAAc,CAAC;IACxC,QAAQ,CAAC,gBAAgB,EAAE,WAAW,GAAG,IAAI,CAAC;IAC9C,aAAa,IAAI,OAAO,CAAC;IACzB,eAAe,IAAI,MAAM,CAAC;IAC1B,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/C,SAAS,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1E,iBAAiB,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAChE,QAAQ,IAAI,IAAI,CAAC;IACjB,YAAY,IAAI,IAAI,CAAC;CACxB;AAED,MAAM,WAAW,wBAAwB,CACrC,OAAO,SAAS,QAAQ,CAAC,YAAY,EACrC,UAAU,SAAS,QAAQ,CAAC,YAAY;IAExC,SAAS,EAAE,qBAAqB,CAAC;IACjC,aAAa,EAAE,kBAAkB,GAAG;QAChC,UAAU,EAAE,OAAO,CAAC;QACpB,QAAQ,EAAE,KAAK,CAAC;KACnB,CAAC;IACF,UAAU,IAAI,OAAO,EAAE,CAAC;IACxB,mBAAmB,IAAI,UAAU,EAAE,CAAC;IACpC,sBAAsB,IAAI,IAAI,CAAC;IAC/B,uBAAuB,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACxE;AA0BD,wBAAsB,8BAA8B,CAChD,OAAO,SAAS,UAAU,GAAG,gBAAgB,EAC7C,UAAU,SAAS,UAAU,GAAG,gBAAgB,EAEhD,OAAO,EAAE,8BAA8B,EACvC,OAAO,EAAE,wBAAwB,CAAC,OAAO,EAAE,UAAU,CAAC,GACvD,OAAO,CAAC,IAAI,CAAC,CAuDf"}
|
|
@@ -4,11 +4,11 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Behavior contract:
|
|
6
6
|
*
|
|
7
|
-
* • {@link HistoryManager.
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
7
|
+
* • {@link HistoryManager.push} is **synchronous** for the history-push
|
|
8
|
+
* step so callers can immediately inspect {@link HistoryManager.canUndo} /
|
|
9
|
+
* {@link HistoryManager.canRedo} on the next line (e.g. `updateUi` calls
|
|
10
|
+
* that immediately follow `saveState`). {@link HistoryManager.execute}
|
|
11
|
+
* awaits the command before pushing it.
|
|
12
12
|
*
|
|
13
13
|
* • {@link HistoryManager.undo} and {@link HistoryManager.redo} are
|
|
14
14
|
* **async** and protected by an internal `isProcessing` lock. Overlapping
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
* await canvas.loadFromJSON(beforeJson);
|
|
51
51
|
* },
|
|
52
52
|
* );
|
|
53
|
-
* historyManager.execute(cmd);
|
|
53
|
+
* await historyManager.execute(cmd);
|
|
54
54
|
* ```
|
|
55
55
|
*/
|
|
56
56
|
export declare class Command {
|
|
@@ -76,16 +76,13 @@ export declare class HistoryManager {
|
|
|
76
76
|
*/
|
|
77
77
|
constructor(maxSize?: number);
|
|
78
78
|
/**
|
|
79
|
-
*
|
|
80
|
-
*
|
|
79
|
+
* Awaits a command's `execute` closure and records it on the history stack
|
|
80
|
+
* only after the closure succeeds.
|
|
81
81
|
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
* `saveState` pattern, `command.execute` is a no-op on its first
|
|
85
|
-
* invocation (guarded by an `executedOnce` flag inside the closure), so
|
|
86
|
-
* the fire-and-forget is safe and produces no canvas side-effect.
|
|
82
|
+
* Use {@link push} when the operation has already been performed and
|
|
83
|
+
* should become undoable synchronously.
|
|
87
84
|
*/
|
|
88
|
-
execute(command: Command): void
|
|
85
|
+
execute(command: Command): Promise<void>;
|
|
89
86
|
/**
|
|
90
87
|
* Pushes a command onto the history stack **without** calling
|
|
91
88
|
* `execute`. Use this when the operation has already been performed
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"history-manager.d.ts","sourceRoot":"","sources":["../../../src/history/history-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,OAAO;IAChB,4CAA4C;IAC5C,QAAQ,CAAC,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,0BAA0B;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;gBAEvB,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC;CAItE;AAED;;;GAGG;AACH,qBAAa,cAAc;IACvB,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,YAAY,CAAM;IAC1B,OAAO,CAAC,YAAY,CAAS;IAE7B,2CAA2C;IAC3C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAEzB;;;OAGG;gBACS,OAAO,GAAE,MAAW;IAIhC
|
|
1
|
+
{"version":3,"file":"history-manager.d.ts","sourceRoot":"","sources":["../../../src/history/history-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,OAAO;IAChB,4CAA4C;IAC5C,QAAQ,CAAC,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,0BAA0B;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;gBAEvB,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC;CAItE;AAED;;;GAGG;AACH,qBAAa,cAAc;IACvB,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,YAAY,CAAM;IAC1B,OAAO,CAAC,YAAY,CAAS;IAE7B,2CAA2C;IAC3C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAEzB;;;OAGG;gBACS,OAAO,GAAE,MAAW;IAIhC;;;;;;OAMG;IACG,OAAO,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAK9C;;;;OAIG;IACH,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAI5B,8DAA8D;IAC9D,OAAO,IAAI,OAAO;IAIlB,8DAA8D;IAC9D,OAAO,IAAI,OAAO;IAIlB;;;;;;;;;OASG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAc3B;;;;;;OAMG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAc3B;;;;;;;;OAQG;IACH,OAAO,CAAC,WAAW;CAgBtB"}
|