@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
package/README.md
CHANGED
|
@@ -6,8 +6,9 @@
|
|
|
6
6
|
|
|
7
7
|
A lightweight, TypeScript-first canvas image editor built on top of
|
|
8
8
|
[Fabric.js](https://fabricjs.com/) v7. `ImageEditor` wraps a Fabric canvas
|
|
9
|
-
with image loading, scale and rotation, mask creation,
|
|
10
|
-
|
|
9
|
+
with image loading, scale and rotation, mask creation, Text and Draw
|
|
10
|
+
annotations, crop, Mosaic mode, base-image flips, history (undo/redo), layer operations, and
|
|
11
|
+
base64/file export — exposed as a single canonical class
|
|
11
12
|
with a stable public surface.
|
|
12
13
|
|
|
13
14
|
## Demo
|
|
@@ -30,8 +31,13 @@ with a stable public surface.
|
|
|
30
31
|
- Crop session with mask preservation toggle and atomic apply/cancel
|
|
31
32
|
- Mosaic mode with circular brush preview, runtime brush/block controls, and
|
|
32
33
|
one undo step per successful pixelation click
|
|
34
|
+
- Unified editor-owned object model for base images, masks, annotations, and
|
|
35
|
+
session overlays
|
|
36
|
+
- Text annotations, Draw mode, annotation update/delete APIs, and layer
|
|
37
|
+
operations
|
|
33
38
|
- Base64 and `File` exports with PNG/JPEG/WebP support, configurable
|
|
34
|
-
multiplier,
|
|
39
|
+
multiplier, independent mask/annotation rendering toggles, and state-mutating
|
|
40
|
+
mask/annotation merge APIs
|
|
35
41
|
|
|
36
42
|
## Requirements
|
|
37
43
|
|
|
@@ -123,12 +129,44 @@ resolve to `undefined`.
|
|
|
123
129
|
<input id="rotateLeftDegreesInput" type="number" value="90" />
|
|
124
130
|
<button id="rotateRightButton">Rotate Right</button>
|
|
125
131
|
<input id="rotateRightDegreesInput" type="number" value="90" />
|
|
132
|
+
<button id="flipHorizontalButton">Flip Horizontal</button>
|
|
133
|
+
<button id="flipVerticalButton">Flip Vertical</button>
|
|
126
134
|
|
|
127
135
|
<button id="createMaskButton">Add Mask</button>
|
|
128
136
|
<button id="removeSelectedMaskButton">Remove Mask</button>
|
|
129
137
|
<button id="removeAllMasksButton">Remove All Masks</button>
|
|
138
|
+
<ul id="maskList"></ul>
|
|
139
|
+
|
|
140
|
+
<button id="enterTextModeButton">Text</button>
|
|
141
|
+
<button id="exitTextModeButton">Exit Text</button>
|
|
142
|
+
<input id="textColorInput" type="color" value="#ff0000" />
|
|
143
|
+
<input id="textFontSizeInput" type="number" min="8" max="160" value="32" />
|
|
144
|
+
|
|
145
|
+
<button id="enterDrawModeButton">Draw</button>
|
|
146
|
+
<button id="exitDrawModeButton">Exit Draw</button>
|
|
147
|
+
<input id="drawColorInput" type="color" value="#ff0000" />
|
|
148
|
+
<input id="drawBrushSizeInput" type="range" min="1" max="80" value="8" />
|
|
149
|
+
|
|
150
|
+
<button id="removeSelectedAnnotationButton">Remove Annotation</button>
|
|
151
|
+
<button id="removeAllAnnotationsButton">Remove All Annotations</button>
|
|
152
|
+
<button id="deleteSelectedObjectButton">Delete Selected</button>
|
|
153
|
+
<button id="bringSelectedObjectForwardButton">Forward</button>
|
|
154
|
+
<button id="sendSelectedObjectBackwardButton">Backward</button>
|
|
155
|
+
<button id="bringSelectedObjectToFrontButton">Front</button>
|
|
156
|
+
<button id="sendSelectedObjectToBackButton">Back</button>
|
|
157
|
+
<ul id="annotationList"></ul>
|
|
130
158
|
|
|
131
159
|
<button id="enterCropModeButton">Crop</button>
|
|
160
|
+
<select id="cropAspectRatioSelect">
|
|
161
|
+
<option value="free">Free</option>
|
|
162
|
+
<option value="1:1">1:1</option>
|
|
163
|
+
<option value="3:4">3:4</option>
|
|
164
|
+
<option value="4:3">4:3</option>
|
|
165
|
+
<option value="3:2">3:2</option>
|
|
166
|
+
<option value="2:3">2:3</option>
|
|
167
|
+
<option value="9:16">9:16</option>
|
|
168
|
+
<option value="16:9">16:9</option>
|
|
169
|
+
</select>
|
|
132
170
|
<button id="applyCropButton">Apply Crop</button>
|
|
133
171
|
<button id="cancelCropButton">Cancel Crop</button>
|
|
134
172
|
|
|
@@ -143,14 +181,14 @@ resolve to `undefined`.
|
|
|
143
181
|
<input id="mosaicBlockSizeInput" type="range" min="2" max="40" step="1" value="8" />
|
|
144
182
|
</label>
|
|
145
183
|
|
|
146
|
-
<button id="mergeMasksButton">Merge</button>
|
|
184
|
+
<button id="mergeMasksButton">Merge Masks</button>
|
|
185
|
+
<button id="mergeAnnotationsButton">Merge Annotations</button>
|
|
147
186
|
<button id="downloadImageButton">Download</button>
|
|
148
187
|
<button id="undoButton">Undo</button>
|
|
149
188
|
<button id="redoButton">Redo</button>
|
|
150
189
|
<button id="resetImageTransformButton">Reset</button>
|
|
151
190
|
|
|
152
191
|
<input id="imageInput" type="file" accept="image/*" />
|
|
153
|
-
<ul id="maskList"></ul>
|
|
154
192
|
```
|
|
155
193
|
|
|
156
194
|
### TypeScript / ESM
|
|
@@ -168,6 +206,14 @@ const editor = new ImageEditor(fabric, {
|
|
|
168
206
|
brushSize: 48,
|
|
169
207
|
blockSize: 8,
|
|
170
208
|
},
|
|
209
|
+
defaultTextConfig: {
|
|
210
|
+
fill: '#ff0000',
|
|
211
|
+
fontSize: 32,
|
|
212
|
+
},
|
|
213
|
+
defaultDrawConfig: {
|
|
214
|
+
color: '#ff0000',
|
|
215
|
+
brushSize: 8,
|
|
216
|
+
},
|
|
171
217
|
} satisfies ImageEditorOptions);
|
|
172
218
|
|
|
173
219
|
editor.init({
|
|
@@ -178,23 +224,43 @@ editor.init({
|
|
|
178
224
|
rotateLeftDegreesInput: 'rotateLeftDegreesInput',
|
|
179
225
|
rotateRightButton: 'rotateRightButton',
|
|
180
226
|
rotateRightDegreesInput: 'rotateRightDegreesInput',
|
|
227
|
+
flipHorizontalButton: 'flipHorizontalButton',
|
|
228
|
+
flipVerticalButton: 'flipVerticalButton',
|
|
181
229
|
createMaskButton: 'createMaskButton',
|
|
182
230
|
removeSelectedMaskButton: 'removeSelectedMaskButton',
|
|
183
231
|
removeAllMasksButton: 'removeAllMasksButton',
|
|
232
|
+
maskList: 'maskList',
|
|
184
233
|
enterCropModeButton: 'enterCropModeButton',
|
|
234
|
+
cropAspectRatioSelect: 'cropAspectRatioSelect',
|
|
185
235
|
applyCropButton: 'applyCropButton',
|
|
186
236
|
cancelCropButton: 'cancelCropButton',
|
|
187
237
|
enterMosaicModeButton: 'enterMosaicModeButton',
|
|
188
238
|
exitMosaicModeButton: 'exitMosaicModeButton',
|
|
189
239
|
mosaicBrushSizeInput: 'mosaicBrushSizeInput',
|
|
190
240
|
mosaicBlockSizeInput: 'mosaicBlockSizeInput',
|
|
241
|
+
enterTextModeButton: 'enterTextModeButton',
|
|
242
|
+
exitTextModeButton: 'exitTextModeButton',
|
|
243
|
+
textColorInput: 'textColorInput',
|
|
244
|
+
textFontSizeInput: 'textFontSizeInput',
|
|
245
|
+
enterDrawModeButton: 'enterDrawModeButton',
|
|
246
|
+
exitDrawModeButton: 'exitDrawModeButton',
|
|
247
|
+
drawColorInput: 'drawColorInput',
|
|
248
|
+
drawBrushSizeInput: 'drawBrushSizeInput',
|
|
249
|
+
removeSelectedAnnotationButton: 'removeSelectedAnnotationButton',
|
|
250
|
+
removeAllAnnotationsButton: 'removeAllAnnotationsButton',
|
|
251
|
+
deleteSelectedObjectButton: 'deleteSelectedObjectButton',
|
|
252
|
+
mergeAnnotationsButton: 'mergeAnnotationsButton',
|
|
253
|
+
bringSelectedObjectForwardButton: 'bringSelectedObjectForwardButton',
|
|
254
|
+
sendSelectedObjectBackwardButton: 'sendSelectedObjectBackwardButton',
|
|
255
|
+
bringSelectedObjectToFrontButton: 'bringSelectedObjectToFrontButton',
|
|
256
|
+
sendSelectedObjectToBackButton: 'sendSelectedObjectToBackButton',
|
|
257
|
+
annotationList: 'annotationList',
|
|
191
258
|
mergeMasksButton: 'mergeMasksButton',
|
|
192
259
|
downloadImageButton: 'downloadImageButton',
|
|
193
260
|
undoButton: 'undoButton',
|
|
194
261
|
redoButton: 'redoButton',
|
|
195
262
|
resetImageTransformButton: 'resetImageTransformButton',
|
|
196
263
|
imageInput: 'imageInput',
|
|
197
|
-
maskList: 'maskList',
|
|
198
264
|
});
|
|
199
265
|
|
|
200
266
|
// Load an image programmatically (base64 data URL).
|
|
@@ -203,6 +269,9 @@ await editor.loadImage('data:image/jpeg;base64,...');
|
|
|
203
269
|
// Add a rectangular mask, then export the result as base64.
|
|
204
270
|
const mask: MaskConfig = { shape: 'rect', width: 120, height: 80, left: '25%', top: '25%' };
|
|
205
271
|
editor.createMask(mask);
|
|
272
|
+
editor.createTextAnnotation({ text: 'Label', left: 120, top: 80 });
|
|
273
|
+
editor.enterDrawMode();
|
|
274
|
+
editor.setDrawConfig({ color: '#00aaff', brushSize: 10 });
|
|
206
275
|
|
|
207
276
|
const dataUrl = await editor.exportImageBase64({ fileType: 'png' });
|
|
208
277
|
```
|
|
@@ -217,17 +286,33 @@ const editor = new ImageEditor(fabric, { canvasWidth: 800, canvasHeight: 600 });
|
|
|
217
286
|
```
|
|
218
287
|
|
|
219
288
|
In v2, `require('@bensitu/image-editor')` returns a namespace object with
|
|
220
|
-
`ImageEditor`, `default`, and
|
|
221
|
-
|
|
289
|
+
`ImageEditor`, `default`, and the editor object guards
|
|
290
|
+
(`isBaseImageObject`, `isMaskObject`, `isAnnotationObject`,
|
|
291
|
+
`isTextAnnotationObject`, `isDrawAnnotationObject`, `isSessionObject`, and
|
|
292
|
+
`isEditableOverlayObject`); it does not return the constructor directly.
|
|
222
293
|
|
|
223
294
|
## Public API
|
|
224
295
|
|
|
225
296
|
`ImageEditor` is the only public class. The package barrel re-exports it as
|
|
226
|
-
both the default export and a named export, alongside
|
|
227
|
-
documented public types. Internal helpers (animation queue, command, history
|
|
297
|
+
both the default export and a named export, alongside the editor object guards
|
|
298
|
+
and the documented public types. Internal helpers (animation queue, command, history
|
|
228
299
|
manager, controllers, services, managers, utility modules) are intentionally
|
|
229
300
|
not exported and may change without notice.
|
|
230
301
|
|
|
302
|
+
### Object model
|
|
303
|
+
|
|
304
|
+
Every editor-owned Fabric object carries strict `editorObjectKind` metadata:
|
|
305
|
+
|
|
306
|
+
| Kind | Meaning |
|
|
307
|
+
| ------------ | ------------------------------------------------------------------------ |
|
|
308
|
+
| `baseImage` | The committed image at the bottom of the stack. |
|
|
309
|
+
| `mask` | Editable mask overlay with required `maskId`, `maskUid`, and `maskName`. |
|
|
310
|
+
| `annotation` | Editable Text or Draw overlay. Masks are not annotations. |
|
|
311
|
+
| `session` | Internal crop labels, mask labels, Mosaic previews, and tool previews. |
|
|
312
|
+
|
|
313
|
+
Session objects are never persisted, exported, or user-deletable. Strict type
|
|
314
|
+
guards reject legacy mask-like objects that do not carry `editorObjectKind`.
|
|
315
|
+
|
|
231
316
|
### Constructor
|
|
232
317
|
|
|
233
318
|
```ts
|
|
@@ -244,12 +329,12 @@ new ImageEditor(options?: ImageEditorOptions) // UMD: reads globalThis.fabric
|
|
|
244
329
|
|
|
245
330
|
### Image loading
|
|
246
331
|
|
|
247
|
-
| Method | Description
|
|
248
|
-
| ----------------------------- |
|
|
249
|
-
| `loadImage(base64, options?)` | Load
|
|
250
|
-
| `isImageLoaded()` | Returns `true` if a valid image is currently loaded on the canvas.
|
|
251
|
-
| `isBusy()` | Returns `true` while the editor is loading, animating, in
|
|
252
|
-
| `setLayoutMode(mode)` | Select the layout strategy for future image loads. `mode` is `'fit'`, `'cover'`, or `'expand'`.
|
|
332
|
+
| Method | Description |
|
|
333
|
+
| ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
334
|
+
| `loadImage(base64, options?)` | Load a supported raster image data URL (`png`, `jpeg`, `webp`, `gif`, or `bmp`). Returns `Promise<void>`. Transactional: any failure restores the prior canvas, scroll, overflow, and snapshot state. |
|
|
335
|
+
| `isImageLoaded()` | Returns `true` if a valid image is currently loaded on the canvas. |
|
|
336
|
+
| `isBusy()` | Returns `true` while the editor is loading, animating, or in Crop, Mosaic, Text, or Draw mode. |
|
|
337
|
+
| `setLayoutMode(mode)` | Select the layout strategy for future image loads. `mode` is `'fit'`, `'cover'`, or `'expand'`. |
|
|
253
338
|
|
|
254
339
|
`LoadImageOptions` currently includes `preserveScroll?: boolean` for
|
|
255
340
|
preserving the container's scroll position across both successful loads and
|
|
@@ -280,11 +365,18 @@ the JPEG, PNG, or WebP export options.
|
|
|
280
365
|
|
|
281
366
|
### Transforms
|
|
282
367
|
|
|
283
|
-
| Method | Description
|
|
284
|
-
| ----------------------- |
|
|
285
|
-
| `scaleImage(factor)` | Scale to `factor` (clamped to `[minScale, maxScale]`). Non-finite values are no-ops. Animated.
|
|
286
|
-
| `rotateImage(degrees)` | Rotate to `degrees`. Non-finite values resolve without changing canvas state. Animated.
|
|
287
|
-
| `
|
|
368
|
+
| Method | Description |
|
|
369
|
+
| ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
|
|
370
|
+
| `scaleImage(factor)` | Scale to `factor` (clamped to `[minScale, maxScale]`). Non-finite values are no-ops. Animated. |
|
|
371
|
+
| `rotateImage(degrees)` | Rotate to `degrees`. Non-finite values resolve without changing canvas state. Animated. |
|
|
372
|
+
| `flipHorizontal()` | Toggle horizontal flip on the base image only. Masks, annotations, and session overlays are not mirrored. Returns `Promise<void>`. |
|
|
373
|
+
| `flipVertical()` | Toggle vertical flip on the base image only. Masks, annotations, and session overlays are not mirrored. Returns `Promise<void>`. |
|
|
374
|
+
| `resetImageTransform()` | Animate to scale 1, rotation 0, and an unflipped state. Records exactly one history entry covering the entire transform. |
|
|
375
|
+
|
|
376
|
+
```ts
|
|
377
|
+
await editor.flipHorizontal();
|
|
378
|
+
await editor.flipVertical();
|
|
379
|
+
```
|
|
288
380
|
|
|
289
381
|
### Masks
|
|
290
382
|
|
|
@@ -297,6 +389,8 @@ the JPEG, PNG, or WebP export options.
|
|
|
297
389
|
`MaskConfig` supports rect, circle, ellipse, polygon, and a custom
|
|
298
390
|
`fabricGenerator`. Falsy values in `styles` (`0`, `false`, `null`, `''`,
|
|
299
391
|
`NaN`) are applied verbatim.
|
|
392
|
+
Every mask is marked as `editorObjectKind: 'mask'` and includes required
|
|
393
|
+
`maskId`, `maskUid`, and `maskName` metadata.
|
|
300
394
|
|
|
301
395
|
Use `defaultMaskConfig` to define constructor-level defaults for masks created
|
|
302
396
|
through either `createMask()` or the built-in `createMaskButton`. Per-call
|
|
@@ -321,11 +415,29 @@ editor.createMask({ color: 'rgba(0, 128, 255, 0.35)' }); // Per-call override.
|
|
|
321
415
|
|
|
322
416
|
### Crop
|
|
323
417
|
|
|
324
|
-
| Method
|
|
325
|
-
|
|
|
326
|
-
| `enterCropMode()`
|
|
327
|
-
| `
|
|
328
|
-
| `
|
|
418
|
+
| Method | Description |
|
|
419
|
+
| --------------------------- | ------------------------------------------------------------------------------------ |
|
|
420
|
+
| `enterCropMode(options?)` | Add an interactive crop rectangle on top of the image. |
|
|
421
|
+
| `setCropAspectRatio(ratio)` | Update the active crop rectangle ratio while crop mode is open. |
|
|
422
|
+
| `applyCrop()` | Apply the current crop region. Atomic: failure rolls back to the pre-crop snapshot. |
|
|
423
|
+
| `cancelCrop()` | Cancel crop mode and restore the prior canvas state without pushing a history entry. |
|
|
424
|
+
|
|
425
|
+
`enterCropMode({ aspectRatio })` locks the crop rectangle to a preset or custom
|
|
426
|
+
ratio. Supported preset strings are `'free'`, `'1:1'`, `'3:4'`, `'4:3'`,
|
|
427
|
+
`'3:2'`, `'2:3'`, `'16:9'`, and `'9:16'`. Custom ratios use
|
|
428
|
+
`{ width, height }`. Per-call options override `crop.aspectRatio` from the
|
|
429
|
+
constructor.
|
|
430
|
+
|
|
431
|
+
When `cropAspectRatioSelect` is bound through `init(idMap)`, the built-in Crop
|
|
432
|
+
button uses the select's current value and changing the select while crop mode
|
|
433
|
+
is open calls `setCropAspectRatio()` to resize the active crop rectangle.
|
|
434
|
+
|
|
435
|
+
```ts
|
|
436
|
+
editor.enterCropMode({ aspectRatio: '1:1' });
|
|
437
|
+
editor.enterCropMode({ aspectRatio: '16:9' });
|
|
438
|
+
editor.setCropAspectRatio('4:3');
|
|
439
|
+
editor.enterCropMode({ aspectRatio: { width: 2, height: 1 } });
|
|
440
|
+
```
|
|
329
441
|
|
|
330
442
|
### Mosaic mode
|
|
331
443
|
|
|
@@ -374,35 +486,108 @@ Mosaic edits replace base image pixels rather than adding Fabric overlay
|
|
|
374
486
|
objects, exported images include the Mosaic naturally while the preview circle
|
|
375
487
|
is never exported or saved in history.
|
|
376
488
|
|
|
489
|
+
### Text and Draw annotations
|
|
490
|
+
|
|
491
|
+
Tool modes are mutually exclusive: Crop, Mosaic, Text, and Draw cannot be
|
|
492
|
+
active at the same time. `getEditorState()` reports `activeToolMode` plus
|
|
493
|
+
`isCropMode`, `isMosaicMode`, `isTextMode`, and `isDrawMode`.
|
|
494
|
+
|
|
495
|
+
| Method | Description |
|
|
496
|
+
| ------------------------------------ | -------------------------------------------------------------------------- |
|
|
497
|
+
| `getAnnotations()` | Return current annotation objects in canvas order. Masks are not included. |
|
|
498
|
+
| `enterTextMode()` / `exitTextMode()` | Click empty canvas space to create editable text annotations. |
|
|
499
|
+
| `createTextAnnotation(config?)` | Create a text annotation directly and return it. |
|
|
500
|
+
| `getTextConfig()` | Return a defensive copy of the current Text config. |
|
|
501
|
+
| `setTextConfig(config)` | Patch current Text config without history. |
|
|
502
|
+
| `resetTextConfig()` | Restore Text config from constructor defaults. |
|
|
503
|
+
| `setTextColor(color)` | Convenience setter for text fill color. |
|
|
504
|
+
| `setTextFontSize(size)` | Convenience setter for text font size. |
|
|
505
|
+
| `enterDrawMode()` / `exitDrawMode()` | Use Fabric free drawing; each stroke becomes a Draw annotation. |
|
|
506
|
+
| `getDrawConfig()` | Return a defensive copy of the current Draw config. |
|
|
507
|
+
| `setDrawConfig(config)` | Patch current Draw config without history. |
|
|
508
|
+
| `resetDrawConfig()` | Restore Draw config from constructor defaults. |
|
|
509
|
+
| `setDrawColor(color)` | Convenience setter for brush color. |
|
|
510
|
+
| `setDrawBrushSize(size)` | Convenience setter for brush size. |
|
|
511
|
+
| `updateAnnotation(id, config)` | Update an annotation by id. |
|
|
512
|
+
| `updateSelectedAnnotation(config)` | Update selected annotation objects. |
|
|
513
|
+
| `removeSelectedAnnotation()` | Remove selected unlocked annotations. |
|
|
514
|
+
| `removeAllAnnotations(options?)` | Remove annotations only. Masks are preserved. |
|
|
515
|
+
| `deleteSelectedObject()` | Convenience deletion for selected masks and unlocked annotations. |
|
|
516
|
+
|
|
517
|
+
```ts
|
|
518
|
+
editor.enterTextMode();
|
|
519
|
+
editor.setTextConfig({ fill: '#ff0000', fontSize: 32 });
|
|
520
|
+
editor.updateSelectedAnnotation({ fill: '#00aaff' });
|
|
521
|
+
|
|
522
|
+
editor.enterDrawMode();
|
|
523
|
+
editor.setDrawConfig({ color: '#00aaff', brushSize: 10 });
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
Annotations carry `annotationHidden` and `annotationLocked` metadata. Hidden
|
|
527
|
+
annotations are not rendered during export. Locked annotations are not
|
|
528
|
+
selectable/editable and are skipped by selected-annotation update/delete
|
|
529
|
+
operations unless an API explicitly opts into forced removal.
|
|
530
|
+
|
|
531
|
+
### Layer operations
|
|
532
|
+
|
|
533
|
+
Editable overlays include masks and annotations. Layer operations keep the
|
|
534
|
+
base image below overlays and session objects above overlays.
|
|
535
|
+
|
|
536
|
+
| Method | Description |
|
|
537
|
+
| ------------------------------ | ------------------------------------------------- |
|
|
538
|
+
| `bringSelectedObjectForward()` | Move selected editable overlays one step up. |
|
|
539
|
+
| `sendSelectedObjectBackward()` | Move selected editable overlays one step down. |
|
|
540
|
+
| `bringSelectedObjectToFront()` | Move selected editable overlays to overlay front. |
|
|
541
|
+
| `sendSelectedObjectToBack()` | Move selected editable overlays to overlay back. |
|
|
542
|
+
|
|
377
543
|
### Merge and export
|
|
378
544
|
|
|
379
545
|
| Method | Description |
|
|
380
546
|
| ----------------------------- | ---------------------------------------------------------------------------------------------- |
|
|
381
547
|
| `mergeMasks()` | Bake masks into the base image atomically. Returns `Promise<void>`. |
|
|
548
|
+
| `mergeAnnotations()` | Bake annotations into the base image atomically. Returns `Promise<void>`. |
|
|
382
549
|
| `exportImageBase64(options?)` | Returns `Promise<string>` (data URL). Resolves to `''` with a warning when no image is loaded. |
|
|
383
550
|
| `exportImageFile(options?)` | Returns `Promise<File>`. Rejects when no image is loaded. |
|
|
384
|
-
| `downloadImage(
|
|
551
|
+
| `downloadImage(options?)` | Returns `Promise<void>` and triggers a browser download. No-op when no image is loaded. |
|
|
385
552
|
|
|
386
|
-
|
|
387
|
-
from export region selection:
|
|
553
|
+
All export APIs use the same `ImageExportOptions` shape:
|
|
388
554
|
|
|
389
|
-
| Option
|
|
390
|
-
|
|
|
391
|
-
| `
|
|
392
|
-
| `
|
|
393
|
-
| `
|
|
394
|
-
| `
|
|
395
|
-
| `
|
|
396
|
-
| `
|
|
397
|
-
| `
|
|
555
|
+
| Option | Default | Description |
|
|
556
|
+
| ------------------ | --------- | --------------------------------------------------------------------------------- |
|
|
557
|
+
| `mergeMasks` | `true` | Render masks into exported pixels. Mask labels are never exported. |
|
|
558
|
+
| `mergeAnnotations` | `true` | Render non-hidden annotations into exported pixels. |
|
|
559
|
+
| `exportArea` | `'image'` | `'image'` clips to the image bounding box; `'canvas'` exports the canvas. |
|
|
560
|
+
| `fileType` | `'jpeg'` | `'png'`, `'jpeg'`, `'jpg'`, `'webp'`, or matching full MIME strings. |
|
|
561
|
+
| `format` | `'jpeg'` | Alias for `fileType` on all export APIs; `fileType` wins when both set. |
|
|
562
|
+
| `quality` | `0.92` | Lossy quality clamped to `[0, 1]`; ignored for PNG. |
|
|
563
|
+
| `multiplier` | `1` | Output resolution multiplier. |
|
|
564
|
+
| `fileName` | option | `exportImageFile()` and `downloadImage()`. Defaults to `defaultDownloadFileName`. |
|
|
398
565
|
|
|
399
566
|
```ts
|
|
400
|
-
await editor.exportImageBase64({
|
|
401
|
-
await editor.exportImageBase64({
|
|
402
|
-
await editor.exportImageBase64({
|
|
403
|
-
await editor.exportImageBase64({
|
|
567
|
+
await editor.exportImageBase64({ mergeMasks: true, mergeAnnotations: true });
|
|
568
|
+
await editor.exportImageBase64({ mergeMasks: false, mergeAnnotations: true });
|
|
569
|
+
await editor.exportImageBase64({ mergeMasks: true, mergeAnnotations: false });
|
|
570
|
+
await editor.exportImageBase64({ mergeMasks: false, mergeAnnotations: false });
|
|
571
|
+
|
|
572
|
+
const dataUrl = await editor.exportImageBase64({ fileType: 'png', exportArea: 'image' });
|
|
573
|
+
const file = await editor.exportImageFile({
|
|
574
|
+
fileType: 'webp',
|
|
575
|
+
quality: 0.85,
|
|
576
|
+
fileName: 'edited',
|
|
577
|
+
});
|
|
578
|
+
await editor.downloadImage({
|
|
579
|
+
fileType: 'png',
|
|
580
|
+
fileName: 'edited',
|
|
581
|
+
mergeMasks: false,
|
|
582
|
+
mergeAnnotations: false,
|
|
583
|
+
});
|
|
404
584
|
```
|
|
405
585
|
|
|
586
|
+
`mergeMasks` and `mergeAnnotations` in export options affect the rendered output
|
|
587
|
+
only. They do not mutate editor state, remove objects, or push history entries.
|
|
588
|
+
State-mutating merge APIs are `mergeMasks()` and `mergeAnnotations()`.
|
|
589
|
+
`mergeMasks()` preserves annotations; `mergeAnnotations()` preserves masks.
|
|
590
|
+
|
|
406
591
|
### State and history
|
|
407
592
|
|
|
408
593
|
| Method | Description |
|
|
@@ -418,53 +603,59 @@ Pass an `ImageEditorOptions` object as the second constructor argument
|
|
|
418
603
|
(or as the only argument when using the UMD global form). Unknown keys are
|
|
419
604
|
ignored; nested `label` and `crop` objects are deep-merged with the defaults.
|
|
420
605
|
|
|
421
|
-
| Option
|
|
422
|
-
|
|
|
423
|
-
| `canvasWidth`
|
|
424
|
-
| `canvasHeight`
|
|
425
|
-
| `backgroundColor`
|
|
426
|
-
| `animationDuration`
|
|
427
|
-
| `minScale`
|
|
428
|
-
| `maxScale`
|
|
429
|
-
| `scaleStep`
|
|
430
|
-
| `rotationStep`
|
|
431
|
-
| `defaultLayoutMode`
|
|
432
|
-
| `downsampleOnLoad`
|
|
433
|
-
| `downsampleMaxWidth`
|
|
434
|
-
| `downsampleMaxHeight`
|
|
435
|
-
| `downsampleQuality`
|
|
436
|
-
| `preserveSourceFormat`
|
|
437
|
-
| `downsampleMimeType`
|
|
438
|
-
| `imageLoadTimeoutMs`
|
|
439
|
-
| `exportMultiplier`
|
|
440
|
-
| `maxExportPixels`
|
|
441
|
-
| `maxHistorySize`
|
|
442
|
-
| `exportAreaByDefault`
|
|
443
|
-
| `
|
|
444
|
-
| `
|
|
445
|
-
| `
|
|
446
|
-
| `
|
|
447
|
-
| `
|
|
448
|
-
| `
|
|
449
|
-
| `
|
|
450
|
-
| `
|
|
451
|
-
| `
|
|
452
|
-
| `
|
|
453
|
-
| `
|
|
454
|
-
| `
|
|
455
|
-
| `
|
|
456
|
-
| `
|
|
457
|
-
| `
|
|
458
|
-
| `
|
|
459
|
-
| `
|
|
460
|
-
| `
|
|
461
|
-
| `
|
|
462
|
-
| `
|
|
463
|
-
| `
|
|
464
|
-
| `
|
|
465
|
-
| `
|
|
466
|
-
| `
|
|
467
|
-
| `
|
|
606
|
+
| Option | Default | Description |
|
|
607
|
+
| --------------------------- | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
608
|
+
| `canvasWidth` | `800` | Initial and hidden-container fallback canvas width in pixels. |
|
|
609
|
+
| `canvasHeight` | `600` | Initial and hidden-container fallback canvas height in pixels. |
|
|
610
|
+
| `backgroundColor` | `'transparent'` | Fabric canvas background color. |
|
|
611
|
+
| `animationDuration` | `300` | Duration of scale and rotate animations (ms). |
|
|
612
|
+
| `minScale` | `0.1` | Minimum scale factor. |
|
|
613
|
+
| `maxScale` | `5.0` | Maximum scale factor. |
|
|
614
|
+
| `scaleStep` | `0.05` | Scale delta per zoom step. |
|
|
615
|
+
| `rotationStep` | `90` | Rotation step in degrees. |
|
|
616
|
+
| `defaultLayoutMode` | `'expand'` | Initial layout mode for image loads until changed by `setLayoutMode()`. Use `'fit'`, `'cover'`, or `'expand'`. Invalid runtime values fall back to `'expand'`. |
|
|
617
|
+
| `downsampleOnLoad` | `true` | Downsample large images on load. |
|
|
618
|
+
| `downsampleMaxWidth` | `4000` | Max width before downsampling kicks in. |
|
|
619
|
+
| `downsampleMaxHeight` | `3000` | Max height before downsampling kicks in. |
|
|
620
|
+
| `downsampleQuality` | `0.92` | Lossy quality used when downsampling and exporting. |
|
|
621
|
+
| `preserveSourceFormat` | `true` | Preserve PNG/WebP MIME through downsampling unless `downsampleMimeType` is set. |
|
|
622
|
+
| `downsampleMimeType` | `null` | Explicit downsample MIME type. Overrides `preserveSourceFormat`. |
|
|
623
|
+
| `imageLoadTimeoutMs` | `30000` | Maximum duration for both decode and Fabric image creation during `loadImage`. |
|
|
624
|
+
| `exportMultiplier` | `1` | Output resolution multiplier. |
|
|
625
|
+
| `maxExportPixels` | `50000000` | Maximum output pixel count after applying the export multiplier. Invalid values fall back to this default. |
|
|
626
|
+
| `maxHistorySize` | `50` | Maximum undo-history entries. Snapshots may include full image data URLs, so large images can duplicate memory across history entries. Lower this for memory-constrained pages. |
|
|
627
|
+
| `exportAreaByDefault` | `'image'` | Default export region for `exportImageBase64`, `exportImageFile`, and `downloadImage`. |
|
|
628
|
+
| `mergeMasksByDefault` | `true` | Default mask rendering behavior for `exportImageBase64`, `exportImageFile`, and `downloadImage`. |
|
|
629
|
+
| `mergeAnnotationsByDefault` | `true` | Default annotation rendering behavior for `exportImageBase64`, `exportImageFile`, and `downloadImage`. |
|
|
630
|
+
| `defaultMaskWidth` | `50` | Default mask width. |
|
|
631
|
+
| `defaultMaskHeight` | `80` | Default mask height. |
|
|
632
|
+
| `defaultMaskConfig` | `{}` | Defaults applied by `createMask()` after `defaultMaskWidth` / `defaultMaskHeight` and before per-call config. Supports `MaskConfig` fields except `onCreate` and `fabricGenerator`. |
|
|
633
|
+
| `defaultMosaicConfig` | see source | Defaults used to initialize the current Mosaic tool config. Supports `brushSize`, `blockSize`, preview circle styling, `outputFileType`, and `outputQuality`. Runtime Mosaic setters update the current config only. |
|
|
634
|
+
| `defaultTextConfig` | see source | Defaults used to initialize the current Text annotation config. Runtime Text setters update the current config only. |
|
|
635
|
+
| `defaultDrawConfig` | see source | Defaults used to initialize the current Draw mode config. Runtime Draw setters update the current config only. |
|
|
636
|
+
| `maskRotatable` | `false` | Allow masks to be rotated by the user. |
|
|
637
|
+
| `maskLabelOnSelect` | `true` | Show a label above a selected mask. |
|
|
638
|
+
| `maskLabelOffset` | `3` | Pixel offset of the label from the mask's top-left corner. |
|
|
639
|
+
| `maskName` | `'mask'` | Prefix used for auto-generated mask names. |
|
|
640
|
+
| `textAnnotationName` | `'text'` | Prefix used for auto-generated text annotation names. |
|
|
641
|
+
| `drawAnnotationName` | `'draw'` | Prefix used for auto-generated draw annotation names. |
|
|
642
|
+
| `groupSelection` | `false` | Allow Fabric multi-object group selection on the canvas. |
|
|
643
|
+
| `showPlaceholder` | `true` | Show a placeholder element while no image is loaded. |
|
|
644
|
+
| `initialImageBase64` | `null` | Base64 data URL auto-loaded after construction. |
|
|
645
|
+
| `defaultDownloadFileName` | `'edited_image'` | Default filename base used by `exportImageFile()` and `downloadImage()`. The resolved export format supplies or corrects the extension. |
|
|
646
|
+
| `onImageLoadStart` | `null` | Called before a valid image load begins. |
|
|
647
|
+
| `onImageLoaded` | `null` | Called as `(info, context)` once after a successful `loadImage`. Extra arguments are ignored by existing zero-argument JavaScript handlers. |
|
|
648
|
+
| `onImageCleared` | `null` | Called when a committed image is replaced or cleared. |
|
|
649
|
+
| `onImageChanged` | `null` | Called with a safe editor state snapshot after visible editor state changes. |
|
|
650
|
+
| `onBusyChange` | `null` | Called only when the public busy state changes. |
|
|
651
|
+
| `onEditorDisposed` | `null` | Called once when `dispose()` performs teardown. |
|
|
652
|
+
| `onMasksChanged` | `null` | Called with a shallow copy of current mask objects after the mask collection changes. |
|
|
653
|
+
| `onAnnotationsChanged` | `null` | Called with a shallow copy of current annotation objects after the annotation collection changes. |
|
|
654
|
+
| `onSelectionChange` | `null` | Called with selected object payload after selection changes. |
|
|
655
|
+
| `onError` | `null` | Called as `(error, message)` when the editor reports an error. |
|
|
656
|
+
| `onWarning` | `null` | Called as `(error, message)` when the editor reports a recoverable warning. |
|
|
657
|
+
| `label` | see source | `LabelConfig` for selected-mask labels (`getText`, `textOptions`, `create`). |
|
|
658
|
+
| `crop` | see source | `CropConfig` (`minWidth`, `minHeight`, `padding`, `aspectRatio`, `hideMasksDuringCrop`, `preserveMasksAfterCrop`, `allowRotationOfCropRect`, `exportFileType`, `exportQuality`). `applyCrop()` preserves the current image format by default (`'source'`) and falls back to PNG when unknown. |
|
|
468
659
|
|
|
469
660
|
`crop.exportFileType` defaults to `'source'`. Supported explicit values are
|
|
470
661
|
`'png'`, `'jpeg'`, `'jpg'`, `'webp'`, and full image MIME strings. PNG is
|
|
@@ -477,14 +668,31 @@ preserve the current image MIME type when known and fall back to PNG when the
|
|
|
477
668
|
source format cannot be determined. JPEG/WebP commits use
|
|
478
669
|
`defaultMosaicConfig.outputQuality` when finite, otherwise `downsampleQuality`.
|
|
479
670
|
|
|
671
|
+
## Breaking changes in v2
|
|
672
|
+
|
|
673
|
+
- `Base64ExportOptions`, `ImageFileExportOptions`, and `DownloadImageOptions`
|
|
674
|
+
were replaced by `ImageExportOptions`.
|
|
675
|
+
- `downloadImage(fileName: string)` was removed. Use
|
|
676
|
+
`downloadImage({ fileName })`.
|
|
677
|
+
- `downloadImage()` now returns `Promise<void>`.
|
|
678
|
+
- `defaultDownloadFileName` now defaults to `'edited_image'`; export format
|
|
679
|
+
resolution supplies or corrects the final extension.
|
|
680
|
+
- All editor-owned Fabric objects now require `editorObjectKind`.
|
|
681
|
+
- `isMaskObject()` is strict and rejects legacy objects with only `maskId`.
|
|
682
|
+
- `MaskObject.maskUid` is required.
|
|
683
|
+
- Serialized states without `editorObjectKind` are not migrated.
|
|
684
|
+
- Export option mergeMask was removed; use `mergeMasks`.
|
|
685
|
+
- Constructor option mergeMaskByDefault was removed; use `mergeMasksByDefault`.
|
|
686
|
+
|
|
480
687
|
## Example workflow
|
|
481
688
|
|
|
482
689
|
1. Construct `ImageEditor` with options and call `init(idMap)` to wire it up.
|
|
483
690
|
2. Load an image via `loadImage(base64)` or the bound file input.
|
|
484
|
-
3. Adjust with `scaleImage`, `rotateImage`, `
|
|
485
|
-
|
|
486
|
-
4. Add `createMask` calls
|
|
487
|
-
|
|
691
|
+
3. Adjust with `scaleImage`, `rotateImage`, `flipHorizontal`, `flipVertical`,
|
|
692
|
+
`resetImageTransform`, Crop mode, Mosaic mode, Text mode, or Draw mode.
|
|
693
|
+
4. Add `createMask` and annotation calls, then inspect via `maskList` and
|
|
694
|
+
`annotationList`.
|
|
695
|
+
5. Use `mergeMasks()` or `mergeAnnotations()` to bake overlays into the image, then
|
|
488
696
|
`exportImageBase64`, `exportImageFile`, or `downloadImage` to produce
|
|
489
697
|
the final output.
|
|
490
698
|
6. Call `dispose()` when the editor is unmounted.
|
|
@@ -560,8 +768,10 @@ import type {
|
|
|
560
768
|
ExportArea,
|
|
561
769
|
CropExportFileType,
|
|
562
770
|
MosaicOutputFileType,
|
|
563
|
-
|
|
564
|
-
|
|
771
|
+
ImageExportOptions,
|
|
772
|
+
CropAspectRatioPreset,
|
|
773
|
+
CropAspectRatio,
|
|
774
|
+
CropModeOptions,
|
|
565
775
|
ImageInfo,
|
|
566
776
|
ImageEditorState,
|
|
567
777
|
ImageEditorSelection,
|