@bensitu/image-editor 2.0.0 → 2.1.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 +118 -16
- package/dist/cjs/index.cjs +1800 -330
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/esm/animation/animation-queue.js +16 -9
- package/dist/esm/animation/animation-queue.js.map +1 -1
- package/dist/esm/core/default-options.js +216 -9
- package/dist/esm/core/default-options.js.map +1 -1
- package/dist/esm/core/operation-guard.js +28 -0
- package/dist/esm/core/operation-guard.js.map +1 -1
- package/dist/esm/core/public-types.js.map +1 -1
- package/dist/esm/core/state-serializer.js +5 -4
- package/dist/esm/core/state-serializer.js.map +1 -1
- package/dist/esm/crop/crop-controller.js +4 -2
- package/dist/esm/crop/crop-controller.js.map +1 -1
- package/dist/esm/export/export-service.js +21 -10
- package/dist/esm/export/export-service.js.map +1 -1
- package/dist/esm/fabric/fabric-animation.js +56 -4
- package/dist/esm/fabric/fabric-animation.js.map +1 -1
- package/dist/esm/image/image-loader.js +9 -16
- package/dist/esm/image/image-loader.js.map +1 -1
- package/dist/esm/image/image-resampler.js +7 -2
- package/dist/esm/image/image-resampler.js.map +1 -1
- package/dist/esm/image/layout-manager.js +2 -20
- package/dist/esm/image/layout-manager.js.map +1 -1
- package/dist/esm/image/transform-controller.js.map +1 -1
- package/dist/esm/image-editor.js +383 -47
- package/dist/esm/image-editor.js.map +1 -1
- package/dist/esm/mask/mask-factory.js +53 -29
- package/dist/esm/mask/mask-factory.js.map +1 -1
- package/dist/esm/mask/mask-list.js +9 -3
- package/dist/esm/mask/mask-list.js.map +1 -1
- package/dist/esm/mosaic/mosaic-controller.js +670 -0
- package/dist/esm/mosaic/mosaic-controller.js.map +1 -0
- package/dist/esm/mosaic/mosaic-geometry.js +81 -0
- package/dist/esm/mosaic/mosaic-geometry.js.map +1 -0
- package/dist/esm/mosaic/mosaic-pixelate.js +71 -0
- package/dist/esm/mosaic/mosaic-pixelate.js.map +1 -0
- package/dist/esm/ui/dom-bindings.js +10 -3
- package/dist/esm/ui/dom-bindings.js.map +1 -1
- package/dist/esm/utils/number.js.map +1 -1
- package/dist/types/animation/animation-queue.d.ts.map +1 -1
- package/dist/types/core/default-options.d.ts +34 -6
- package/dist/types/core/default-options.d.ts.map +1 -1
- package/dist/types/core/errors.d.ts +1 -1
- package/dist/types/core/operation-guard.d.ts +2 -0
- package/dist/types/core/operation-guard.d.ts.map +1 -1
- package/dist/types/core/public-types.d.ts +123 -13
- package/dist/types/core/public-types.d.ts.map +1 -1
- package/dist/types/core/state-serializer.d.ts +3 -1
- package/dist/types/core/state-serializer.d.ts.map +1 -1
- package/dist/types/crop/crop-controller.d.ts.map +1 -1
- package/dist/types/export/export-service.d.ts.map +1 -1
- package/dist/types/fabric/fabric-animation.d.ts.map +1 -1
- package/dist/types/image/image-loader.d.ts +2 -4
- 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/image-resampler.d.ts.map +1 -1
- package/dist/types/image/layout-manager.d.ts +5 -49
- package/dist/types/image/layout-manager.d.ts.map +1 -1
- package/dist/types/image/transform-controller.d.ts +1 -2
- package/dist/types/image/transform-controller.d.ts.map +1 -1
- package/dist/types/image-editor.d.ts +20 -9
- package/dist/types/image-editor.d.ts.map +1 -1
- package/dist/types/index.d.cts +1 -1
- package/dist/types/index.d.cts.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/mask/mask-factory.d.ts +24 -21
- package/dist/types/mask/mask-factory.d.ts.map +1 -1
- package/dist/types/mask/mask-list.d.ts.map +1 -1
- package/dist/types/mosaic/mosaic-controller.d.ts +82 -0
- package/dist/types/mosaic/mosaic-controller.d.ts.map +1 -0
- package/dist/types/mosaic/mosaic-geometry.d.ts +29 -0
- package/dist/types/mosaic/mosaic-geometry.d.ts.map +1 -0
- package/dist/types/mosaic/mosaic-pixelate.d.ts +23 -0
- package/dist/types/mosaic/mosaic-pixelate.d.ts.map +1 -0
- package/dist/types/ui/dom-bindings.d.ts +3 -1
- package/dist/types/ui/dom-bindings.d.ts.map +1 -1
- package/dist/types/utils/number.d.ts +1 -2
- package/dist/types/utils/number.d.ts.map +1 -1
- 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,15 +6,10 @@
|
|
|
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, crop, history
|
|
9
|
+
with image loading, scale and rotation, mask creation, crop, Mosaic mode, history
|
|
10
10
|
(undo/redo), and base64/file export — exposed as a single canonical class
|
|
11
11
|
with a stable public surface.
|
|
12
12
|
|
|
13
|
-
> **v2.0.0 is a behavior-preserving migration.** The v1 deprecated method
|
|
14
|
-
> and property aliases have been removed in favor of the canonical names
|
|
15
|
-
> documented below. See [`CHANGELOG.md`](./CHANGELOG.md) for the complete
|
|
16
|
-
> rename map.
|
|
17
|
-
|
|
18
13
|
## Demo
|
|
19
14
|
|
|
20
15
|
[https://bensitu.github.io/image-editor/](https://bensitu.github.io/image-editor/)
|
|
@@ -33,6 +28,8 @@ with a stable public surface.
|
|
|
33
28
|
interleave
|
|
34
29
|
- Bounded history stack with idempotent dispose
|
|
35
30
|
- Crop session with mask preservation toggle and atomic apply/cancel
|
|
31
|
+
- Mosaic mode with circular brush preview, runtime brush/block controls, and
|
|
32
|
+
one undo step per successful pixelation click
|
|
36
33
|
- Base64 and `File` exports with PNG/JPEG/WebP support, configurable
|
|
37
34
|
multiplier, and mask compositing
|
|
38
35
|
|
|
@@ -135,6 +132,17 @@ resolve to `undefined`.
|
|
|
135
132
|
<button id="applyCropButton">Apply Crop</button>
|
|
136
133
|
<button id="cancelCropButton">Cancel Crop</button>
|
|
137
134
|
|
|
135
|
+
<button id="enterMosaicModeButton">Mosaic</button>
|
|
136
|
+
<button id="exitMosaicModeButton">Exit Mosaic</button>
|
|
137
|
+
<label>
|
|
138
|
+
Brush size
|
|
139
|
+
<input id="mosaicBrushSizeInput" type="range" min="8" max="160" step="1" value="48" />
|
|
140
|
+
</label>
|
|
141
|
+
<label>
|
|
142
|
+
Block size
|
|
143
|
+
<input id="mosaicBlockSizeInput" type="range" min="2" max="40" step="1" value="8" />
|
|
144
|
+
</label>
|
|
145
|
+
|
|
138
146
|
<button id="mergeMasksButton">Merge</button>
|
|
139
147
|
<button id="downloadImageButton">Download</button>
|
|
140
148
|
<button id="undoButton">Undo</button>
|
|
@@ -156,6 +164,10 @@ const editor = new ImageEditor(fabric, {
|
|
|
156
164
|
canvasWidth: 800,
|
|
157
165
|
canvasHeight: 600,
|
|
158
166
|
backgroundColor: '#ffffff',
|
|
167
|
+
defaultMosaicConfig: {
|
|
168
|
+
brushSize: 48,
|
|
169
|
+
blockSize: 8,
|
|
170
|
+
},
|
|
159
171
|
} satisfies ImageEditorOptions);
|
|
160
172
|
|
|
161
173
|
editor.init({
|
|
@@ -172,6 +184,10 @@ editor.init({
|
|
|
172
184
|
enterCropModeButton: 'enterCropModeButton',
|
|
173
185
|
applyCropButton: 'applyCropButton',
|
|
174
186
|
cancelCropButton: 'cancelCropButton',
|
|
187
|
+
enterMosaicModeButton: 'enterMosaicModeButton',
|
|
188
|
+
exitMosaicModeButton: 'exitMosaicModeButton',
|
|
189
|
+
mosaicBrushSizeInput: 'mosaicBrushSizeInput',
|
|
190
|
+
mosaicBlockSizeInput: 'mosaicBlockSizeInput',
|
|
175
191
|
mergeMasksButton: 'mergeMasksButton',
|
|
176
192
|
downloadImageButton: 'downloadImageButton',
|
|
177
193
|
undoButton: 'undoButton',
|
|
@@ -232,22 +248,31 @@ new ImageEditor(options?: ImageEditorOptions) // UMD: reads globalThis.fabric
|
|
|
232
248
|
| ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
233
249
|
| `loadImage(base64, options?)` | Load an image from a `data:image/...` URL. Returns `Promise<void>`. Transactional: any failure restores the prior canvas, scroll, overflow, and snapshot state. |
|
|
234
250
|
| `isImageLoaded()` | Returns `true` if a valid image is currently loaded on the canvas. |
|
|
235
|
-
| `isBusy()` | Returns `true` while the editor is loading, animating, or in
|
|
251
|
+
| `isBusy()` | Returns `true` while the editor is loading, animating, in crop mode, or in Mosaic mode. |
|
|
236
252
|
| `setLayoutMode(mode)` | Select the layout strategy for future image loads. `mode` is `'fit'`, `'cover'`, or `'expand'`. |
|
|
237
253
|
|
|
238
254
|
`LoadImageOptions` currently includes `preserveScroll?: boolean` for
|
|
239
255
|
preserving the container's scroll position across both successful loads and
|
|
240
256
|
rollback paths.
|
|
241
257
|
|
|
242
|
-
Use `
|
|
243
|
-
|
|
258
|
+
Use `defaultLayoutMode` to choose the initial image-load strategy, then call
|
|
259
|
+
`setLayoutMode()` when a UI should change how future images are placed:
|
|
244
260
|
|
|
245
261
|
```ts
|
|
246
|
-
editor
|
|
262
|
+
const editor = new ImageEditor(fabric, {
|
|
263
|
+
defaultLayoutMode: 'fit',
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
await editor.loadImage(imageA);
|
|
267
|
+
|
|
268
|
+
// Future loads use cover. The current image is not re-laid out immediately.
|
|
247
269
|
editor.setLayoutMode('cover');
|
|
248
|
-
editor.
|
|
270
|
+
await editor.loadImage(imageB);
|
|
249
271
|
```
|
|
250
272
|
|
|
273
|
+
Invalid JavaScript `defaultLayoutMode` values fall back to `'expand'`.
|
|
274
|
+
Invalid `setLayoutMode()` calls are ignored and preserve the current mode.
|
|
275
|
+
|
|
251
276
|
File-input helpers accept JPG, PNG, WebP, GIF, and BMP files. GIF and BMP are
|
|
252
277
|
decoded as static raster input for canvas editing; GIF animation and BMP/GIF
|
|
253
278
|
source-format preservation are not retained. Export output remains controlled by
|
|
@@ -273,6 +298,27 @@ the JPEG, PNG, or WebP export options.
|
|
|
273
298
|
`fabricGenerator`. Falsy values in `styles` (`0`, `false`, `null`, `''`,
|
|
274
299
|
`NaN`) are applied verbatim.
|
|
275
300
|
|
|
301
|
+
Use `defaultMaskConfig` to define constructor-level defaults for masks created
|
|
302
|
+
through either `createMask()` or the built-in `createMaskButton`. Per-call
|
|
303
|
+
`createMask(config)` values override `defaultMaskConfig`.
|
|
304
|
+
|
|
305
|
+
```ts
|
|
306
|
+
const editor = new ImageEditor(fabric, {
|
|
307
|
+
defaultMaskConfig: {
|
|
308
|
+
color: 'rgba(255, 0, 0, 0.35)',
|
|
309
|
+
alpha: 0.35,
|
|
310
|
+
styles: {
|
|
311
|
+
stroke: '#ff0000',
|
|
312
|
+
strokeWidth: 2,
|
|
313
|
+
strokeDashArray: [6, 4],
|
|
314
|
+
},
|
|
315
|
+
},
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
editor.createMask(); // Uses defaultMaskConfig.
|
|
319
|
+
editor.createMask({ color: 'rgba(0, 128, 255, 0.35)' }); // Per-call override.
|
|
320
|
+
```
|
|
321
|
+
|
|
276
322
|
### Crop
|
|
277
323
|
|
|
278
324
|
| Method | Description |
|
|
@@ -281,6 +327,53 @@ the JPEG, PNG, or WebP export options.
|
|
|
281
327
|
| `applyCrop()` | Apply the current crop region. Atomic: failure rolls back to the pre-crop snapshot. |
|
|
282
328
|
| `cancelCrop()` | Cancel crop mode and restore the prior canvas state without pushing a history entry. |
|
|
283
329
|
|
|
330
|
+
### Mosaic mode
|
|
331
|
+
|
|
332
|
+
| Method | Description |
|
|
333
|
+
| -------------------------- | ---------------------------------------------------------------------- |
|
|
334
|
+
| `enterMosaicMode()` | Enter circular-brush Mosaic mode and show the hover preview on canvas. |
|
|
335
|
+
| `exitMosaicMode()` | Leave Mosaic mode and remove preview/session handlers. |
|
|
336
|
+
| `isMosaicMode()` | Returns `true` while a Mosaic session is active. |
|
|
337
|
+
| `getMosaicConfig()` | Returns a defensive copy of the current runtime Mosaic config. |
|
|
338
|
+
| `setMosaicConfig(config)` | Patch current Mosaic config without creating a history entry. |
|
|
339
|
+
| `resetMosaicConfig()` | Restore current Mosaic config from constructor defaults. |
|
|
340
|
+
| `setMosaicBrushSize(size)` | Set brush diameter in canvas pixels. |
|
|
341
|
+
| `setMosaicBlockSize(size)` | Set source-pixel block size; values are floored to integers. |
|
|
342
|
+
|
|
343
|
+
`defaultMosaicConfig` initializes the current runtime Mosaic config. Runtime
|
|
344
|
+
setters update only the current config and never mutate constructor defaults.
|
|
345
|
+
`resetMosaicConfig()` clones the constructor defaults back into the current
|
|
346
|
+
config.
|
|
347
|
+
|
|
348
|
+
```ts
|
|
349
|
+
const editor = new ImageEditor(fabric, {
|
|
350
|
+
defaultMosaicConfig: {
|
|
351
|
+
brushSize: 48,
|
|
352
|
+
blockSize: 8,
|
|
353
|
+
},
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
editor.init({
|
|
357
|
+
canvas: 'canvas',
|
|
358
|
+
enterMosaicModeButton: 'enterMosaicModeButton',
|
|
359
|
+
exitMosaicModeButton: 'exitMosaicModeButton',
|
|
360
|
+
mosaicBrushSizeInput: 'mosaicBrushSizeInput',
|
|
361
|
+
mosaicBlockSizeInput: 'mosaicBlockSizeInput',
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
editor.enterMosaicMode();
|
|
365
|
+
editor.setMosaicConfig({ brushSize: 64, blockSize: 12 });
|
|
366
|
+
editor.resetMosaicConfig();
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
`brushSize` is the circular brush diameter in canvas pixels. `blockSize` is
|
|
370
|
+
the source-image pixel block size; larger values produce chunkier pixelation.
|
|
371
|
+
Clicking outside the image is a no-op. Each successful Mosaic click bakes the
|
|
372
|
+
pixelated region into the base image and creates exactly one undo step. Because
|
|
373
|
+
Mosaic edits replace base image pixels rather than adding Fabric overlay
|
|
374
|
+
objects, exported images include the Mosaic naturally while the preview circle
|
|
375
|
+
is never exported or saved in history.
|
|
376
|
+
|
|
284
377
|
### Merge and export
|
|
285
378
|
|
|
286
379
|
| Method | Description |
|
|
@@ -335,9 +428,7 @@ ignored; nested `label` and `crop` objects are deep-merged with the defaults.
|
|
|
335
428
|
| `maxScale` | `5.0` | Maximum scale factor. |
|
|
336
429
|
| `scaleStep` | `0.05` | Scale delta per zoom step. |
|
|
337
430
|
| `rotationStep` | `90` | Rotation step in degrees. |
|
|
338
|
-
| `
|
|
339
|
-
| `fitImageToCanvas` | `false` | Fit the image inside the visible workspace viewport (highest layout precedence). |
|
|
340
|
-
| `coverImageToCanvas` | `false` | Scale large images down to cover the visible workspace, cap at native size, and expand overflowing canvas axes so the container can scroll. |
|
|
431
|
+
| `defaultLayoutMode` | `'expand'` | Initial layout mode for image loads until changed by `setLayoutMode()`. Use `'fit'`, `'cover'`, or `'expand'`. Invalid runtime values fall back to `'expand'`. |
|
|
341
432
|
| `downsampleOnLoad` | `true` | Downsample large images on load. |
|
|
342
433
|
| `downsampleMaxWidth` | `4000` | Max width before downsampling kicks in. |
|
|
343
434
|
| `downsampleMaxHeight` | `3000` | Max height before downsampling kicks in. |
|
|
@@ -352,6 +443,8 @@ ignored; nested `label` and `crop` objects are deep-merged with the defaults.
|
|
|
352
443
|
| `mergeMaskByDefault` | `true` | Default mask compositing behavior for `exportImageBase64`, `exportImageFile`, and `downloadImage`. |
|
|
353
444
|
| `defaultMaskWidth` | `50` | Default mask width. |
|
|
354
445
|
| `defaultMaskHeight` | `80` | Default mask height. |
|
|
446
|
+
| `defaultMaskConfig` | `{}` | Defaults applied by `createMask()` after `defaultMaskWidth` / `defaultMaskHeight` and before per-call config. Supports `MaskConfig` fields except `onCreate` and `fabricGenerator`. |
|
|
447
|
+
| `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. |
|
|
355
448
|
| `maskRotatable` | `false` | Allow masks to be rotated by the user. |
|
|
356
449
|
| `maskLabelOnSelect` | `true` | Show a label above a selected mask. |
|
|
357
450
|
| `maskLabelOffset` | `3` | Pixel offset of the label from the mask's top-left corner. |
|
|
@@ -379,12 +472,17 @@ lossless and ignores `crop.exportQuality`; JPEG/WebP use `crop.exportQuality`
|
|
|
379
472
|
when finite, otherwise `downsampleQuality`, otherwise `0.92`. Choose JPEG/WebP
|
|
380
473
|
only when smaller intermediate crop output is preferred.
|
|
381
474
|
|
|
475
|
+
`defaultMosaicConfig.outputFileType` also defaults to `'source'`. Mosaic commits
|
|
476
|
+
preserve the current image MIME type when known and fall back to PNG when the
|
|
477
|
+
source format cannot be determined. JPEG/WebP commits use
|
|
478
|
+
`defaultMosaicConfig.outputQuality` when finite, otherwise `downsampleQuality`.
|
|
479
|
+
|
|
382
480
|
## Example workflow
|
|
383
481
|
|
|
384
482
|
1. Construct `ImageEditor` with options and call `init(idMap)` to wire it up.
|
|
385
483
|
2. Load an image via `loadImage(base64)` or the bound file input.
|
|
386
|
-
3. Adjust with `scaleImage`, `rotateImage`, `resetImageTransform`,
|
|
387
|
-
|
|
484
|
+
3. Adjust with `scaleImage`, `rotateImage`, `resetImageTransform`, the crop
|
|
485
|
+
session, or Mosaic mode.
|
|
388
486
|
4. Add `createMask` calls and inspect via the `maskList` element.
|
|
389
487
|
5. Use `mergeMasks` to bake masks into the image, then
|
|
390
488
|
`exportImageBase64`, `exportImageFile`, or `downloadImage` to produce
|
|
@@ -447,8 +545,11 @@ import type {
|
|
|
447
545
|
ResolvedOptions,
|
|
448
546
|
LabelConfig,
|
|
449
547
|
CropConfig,
|
|
548
|
+
MosaicConfig,
|
|
549
|
+
ResolvedMosaicConfig,
|
|
450
550
|
LoadImageOptions,
|
|
451
551
|
RemoveAllMasksOptions,
|
|
552
|
+
DefaultMaskConfig,
|
|
452
553
|
MaskConfig,
|
|
453
554
|
MaskObject,
|
|
454
555
|
MaskNumericProp,
|
|
@@ -458,6 +559,7 @@ import type {
|
|
|
458
559
|
NormalizedImageFormat,
|
|
459
560
|
ExportArea,
|
|
460
561
|
CropExportFileType,
|
|
562
|
+
MosaicOutputFileType,
|
|
461
563
|
Base64ExportOptions,
|
|
462
564
|
ImageFileExportOptions,
|
|
463
565
|
ImageInfo,
|