@bensitu/image-editor 1.5.2 → 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 +460 -509
- package/dist/cjs/index.cjs +6892 -0
- package/dist/cjs/index.cjs.map +1 -0
- package/dist/esm/animation/animation-queue.js +74 -0
- package/dist/esm/animation/animation-queue.js.map +1 -0
- package/dist/esm/core/callback-reporter.js +23 -0
- package/dist/esm/core/callback-reporter.js.map +1 -0
- package/dist/esm/core/default-options.js +529 -0
- package/dist/esm/core/default-options.js.map +1 -0
- package/dist/esm/core/errors.js +156 -0
- package/dist/esm/core/errors.js.map +1 -0
- package/dist/esm/core/operation-guard.js +157 -0
- package/dist/esm/core/operation-guard.js.map +1 -0
- package/dist/esm/core/public-types.js +4 -0
- package/dist/esm/core/public-types.js.map +1 -0
- package/dist/esm/core/state-serializer.js +252 -0
- package/dist/esm/core/state-serializer.js.map +1 -0
- package/dist/esm/crop/crop-controller.js +405 -0
- package/dist/esm/crop/crop-controller.js.map +1 -0
- package/dist/esm/export/export-format.js +53 -0
- package/dist/esm/export/export-format.js.map +1 -0
- package/dist/esm/export/export-service.js +607 -0
- package/dist/esm/export/export-service.js.map +1 -0
- package/dist/esm/fabric/fabric-adapter.js +37 -0
- package/dist/esm/fabric/fabric-adapter.js.map +1 -0
- package/dist/esm/fabric/fabric-animation.js +89 -0
- package/dist/esm/fabric/fabric-animation.js.map +1 -0
- package/dist/esm/history/command.js +2 -0
- package/dist/esm/history/command.js.map +1 -0
- package/dist/esm/history/history-manager.js +103 -0
- package/dist/esm/history/history-manager.js.map +1 -0
- package/dist/esm/image/image-loader.js +238 -0
- package/dist/esm/image/image-loader.js.map +1 -0
- package/dist/esm/image/image-resampler.js +60 -0
- package/dist/esm/image/image-resampler.js.map +1 -0
- package/dist/esm/image/layout-manager.js +206 -0
- package/dist/esm/image/layout-manager.js.map +1 -0
- package/dist/esm/image/transform-controller.js +132 -0
- package/dist/esm/image/transform-controller.js.map +1 -0
- package/dist/esm/image-editor.js +2076 -0
- package/dist/esm/image-editor.js.map +1 -0
- package/dist/esm/index.js +5 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/mask/mask-factory.js +356 -0
- package/dist/esm/mask/mask-factory.js.map +1 -0
- package/dist/esm/mask/mask-label-manager.js +120 -0
- package/dist/esm/mask/mask-label-manager.js.map +1 -0
- package/dist/esm/mask/mask-list.js +53 -0
- package/dist/esm/mask/mask-list.js.map +1 -0
- package/dist/esm/mask/mask-style.js +182 -0
- package/dist/esm/mask/mask-style.js.map +1 -0
- 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 +67 -0
- package/dist/esm/ui/dom-bindings.js.map +1 -0
- package/dist/esm/ui/ui-state.js +25 -0
- package/dist/esm/ui/ui-state.js.map +1 -0
- package/dist/esm/ui/visibility-state.js +11 -0
- package/dist/esm/ui/visibility-state.js.map +1 -0
- package/dist/esm/utils/canvas-region.js +100 -0
- package/dist/esm/utils/canvas-region.js.map +1 -0
- package/dist/esm/utils/dom.js +6 -0
- package/dist/esm/utils/dom.js.map +1 -0
- package/dist/esm/utils/file.js +53 -0
- package/dist/esm/utils/file.js.map +1 -0
- package/dist/esm/utils/number.js +24 -0
- package/dist/esm/utils/number.js.map +1 -0
- package/dist/esm/utils/timeout.js +17 -0
- package/dist/esm/utils/timeout.js.map +1 -0
- package/dist/types/animation/animation-queue.d.ts +111 -0
- package/dist/types/animation/animation-queue.d.ts.map +1 -0
- package/dist/types/core/callback-reporter.d.ts +125 -0
- package/dist/types/core/callback-reporter.d.ts.map +1 -0
- package/dist/types/core/default-options.d.ts +84 -0
- package/dist/types/core/default-options.d.ts.map +1 -0
- package/dist/types/core/errors.d.ts +142 -0
- package/dist/types/core/errors.d.ts.map +1 -0
- package/dist/types/core/operation-guard.d.ts +194 -0
- package/dist/types/core/operation-guard.d.ts.map +1 -0
- package/dist/types/core/public-types.d.ts +788 -0
- package/dist/types/core/public-types.d.ts.map +1 -0
- package/dist/types/core/state-serializer.d.ts +303 -0
- package/dist/types/core/state-serializer.d.ts.map +1 -0
- package/dist/types/crop/crop-controller.d.ts +407 -0
- package/dist/types/crop/crop-controller.d.ts.map +1 -0
- package/dist/types/export/export-format.d.ts +136 -0
- package/dist/types/export/export-format.d.ts.map +1 -0
- package/dist/types/export/export-service.d.ts +333 -0
- package/dist/types/export/export-service.d.ts.map +1 -0
- package/dist/types/fabric/fabric-adapter.d.ts +74 -0
- package/dist/types/fabric/fabric-adapter.d.ts.map +1 -0
- package/dist/types/fabric/fabric-animation.d.ts +141 -0
- package/dist/types/fabric/fabric-animation.d.ts.map +1 -0
- package/dist/types/history/command.d.ts +16 -0
- package/dist/types/history/command.d.ts.map +1 -0
- package/dist/types/history/history-manager.d.ts +129 -0
- package/dist/types/history/history-manager.d.ts.map +1 -0
- package/dist/types/image/image-loader.d.ts +263 -0
- package/dist/types/image/image-loader.d.ts.map +1 -0
- package/dist/types/image/image-resampler.d.ts +139 -0
- package/dist/types/image/image-resampler.d.ts.map +1 -0
- package/dist/types/image/layout-manager.d.ts +211 -0
- package/dist/types/image/layout-manager.d.ts.map +1 -0
- package/dist/types/image/transform-controller.d.ts +286 -0
- package/dist/types/image/transform-controller.d.ts.map +1 -0
- package/dist/types/image-editor.d.ts +661 -0
- package/dist/types/image-editor.d.ts.map +1 -0
- package/dist/types/index.d.cts +31 -0
- package/dist/types/index.d.cts.map +1 -0
- package/dist/types/index.d.ts +31 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/mask/mask-factory.d.ts +212 -0
- package/dist/types/mask/mask-factory.d.ts.map +1 -0
- package/dist/types/mask/mask-label-manager.d.ts +171 -0
- package/dist/types/mask/mask-label-manager.d.ts.map +1 -0
- package/dist/types/mask/mask-list.d.ts +144 -0
- package/dist/types/mask/mask-list.d.ts.map +1 -0
- package/dist/types/mask/mask-style.d.ts +338 -0
- package/dist/types/mask/mask-style.d.ts.map +1 -0
- 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 +105 -0
- package/dist/types/ui/dom-bindings.d.ts.map +1 -0
- package/dist/types/ui/ui-state.d.ts +112 -0
- package/dist/types/ui/ui-state.d.ts.map +1 -0
- package/dist/types/ui/visibility-state.d.ts +77 -0
- package/dist/types/ui/visibility-state.d.ts.map +1 -0
- package/dist/types/utils/canvas-region.d.ts +177 -0
- package/dist/types/utils/canvas-region.d.ts.map +1 -0
- package/dist/types/utils/dom.d.ts +26 -0
- package/dist/types/utils/dom.d.ts.map +1 -0
- package/dist/types/utils/file.d.ts +80 -0
- package/dist/types/utils/file.d.ts.map +1 -0
- package/dist/types/utils/number.d.ts +131 -0
- package/dist/types/utils/number.d.ts.map +1 -0
- package/dist/types/utils/timeout.d.ts +84 -0
- package/dist/types/utils/timeout.d.ts.map +1 -0
- package/dist/umd/image-editor.umd.js +2 -0
- package/dist/umd/image-editor.umd.js.map +1 -0
- package/package.json +72 -66
- package/dist/image-editor.cjs +0 -4407
- package/dist/image-editor.cjs.map +0 -7
- package/dist/image-editor.esm.js +0 -4376
- package/dist/image-editor.esm.js.map +0 -7
- package/dist/image-editor.esm.min.js +0 -9
- package/dist/image-editor.esm.min.js.map +0 -7
- package/dist/image-editor.esm.min.mjs +0 -9
- package/dist/image-editor.esm.min.mjs.map +0 -7
- package/dist/image-editor.esm.mjs +0 -4376
- package/dist/image-editor.esm.mjs.map +0 -7
- package/dist/image-editor.js +0 -4373
- package/dist/image-editor.js.map +0 -7
- package/dist/image-editor.min.js +0 -9
- package/dist/image-editor.min.js.map +0 -7
- package/image-editor.d.ts +0 -271
- package/src/browser.js +0 -11
- package/src/esm.js +0 -9
- package/src/image-editor.js +0 -5013
package/README.md
CHANGED
|
@@ -1,28 +1,14 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @bensitu/image-editor
|
|
2
2
|
|
|
3
|
-
[](https://github.com/bensitu/image-editor)
|
|
3
|
+
[](https://github.com/bensitu/image-editor)
|
|
4
4
|
[](https://www.npmjs.com/package/@bensitu/image-editor)
|
|
5
5
|
[](https://www.jsdelivr.com/package/npm/@bensitu/image-editor)
|
|
6
6
|
|
|
7
|
-
A lightweight
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
- Image loading from base64 data URLs or file input
|
|
14
|
-
- Zoom in/out and reset transform helpers
|
|
15
|
-
- Rotation with custom degrees or step-based controls
|
|
16
|
-
- Crop mode with optional mask preservation
|
|
17
|
-
- Mask creation, selection, removal, and label support
|
|
18
|
-
- Undo/redo history helpers
|
|
19
|
-
- Merge, download, base64 export, and `File` export helpers
|
|
20
|
-
- Optional DOM/UI binding for common editor controls
|
|
21
|
-
- Large-image downsampling to reduce browser memory pressure
|
|
22
|
-
- Configurable history bounds for large image sessions
|
|
23
|
-
- Centralized error and warning callbacks
|
|
24
|
-
|
|
25
|
-
**Note:** This library uses **fabric.js v5.x**. Bundler and CommonJS entries load Fabric through the peer dependency. Browser global usage needs `window.fabric` available by the time `init()` runs; constructing the editor before Fabric is available is tolerated as long as Fabric is registered before initialization.
|
|
7
|
+
A lightweight, TypeScript-first canvas image editor built on top of
|
|
8
|
+
[Fabric.js](https://fabricjs.com/) v7. `ImageEditor` wraps a Fabric canvas
|
|
9
|
+
with image loading, scale and rotation, mask creation, crop, Mosaic mode, history
|
|
10
|
+
(undo/redo), and base64/file export — exposed as a single canonical class
|
|
11
|
+
with a stable public surface.
|
|
26
12
|
|
|
27
13
|
## Demo
|
|
28
14
|
|
|
@@ -30,77 +16,111 @@ ImageEditor offers:
|
|
|
30
16
|
|
|
31
17
|
## Features
|
|
32
18
|
|
|
33
|
-
-
|
|
34
|
-
-
|
|
35
|
-
-
|
|
36
|
-
-
|
|
37
|
-
|
|
38
|
-
-
|
|
39
|
-
|
|
40
|
-
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
-
|
|
19
|
+
- TypeScript source with `.d.ts` declarations published alongside the runtime
|
|
20
|
+
- Single canonical class `ImageEditor` exported as both default and named
|
|
21
|
+
- Fabric.js v7 declared as a peer dependency (no bundled Fabric copy)
|
|
22
|
+
- Multi-format publish: ESM (`import`), CommonJS (`require`), UMD (`<script>`),
|
|
23
|
+
TypeScript declarations (`types`)
|
|
24
|
+
- Transactional `loadImage` with rollback on decode, Fabric, downsample, or
|
|
25
|
+
timeout failures
|
|
26
|
+
- Animation queue serializes `scaleImage`, `rotateImage`,
|
|
27
|
+
`resetImageTransform`, `undo`, and `redo` so concurrent clicks never
|
|
28
|
+
interleave
|
|
29
|
+
- Bounded history stack with idempotent dispose
|
|
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
|
|
33
|
+
- Base64 and `File` exports with PNG/JPEG/WebP support, configurable
|
|
34
|
+
multiplier, and mask compositing
|
|
35
|
+
|
|
36
|
+
## Requirements
|
|
37
|
+
|
|
38
|
+
- **Node.js**: `>= 20` for development / building from source
|
|
39
|
+
- **Fabric.js**: peer dependency `^7.0.0` (must be installed by the consumer)
|
|
40
|
+
- **Browsers**: modern evergreen (Chrome, Firefox, Safari, Edge). The library
|
|
41
|
+
uses ES2022 features and the Fabric v7 promise-based API.
|
|
42
|
+
- **TypeScript**: strict consumers that compile dependencies with
|
|
43
|
+
`skipLibCheck: false` should include the ES2022 library in `tsconfig.json`.
|
|
44
|
+
Fabric v7.4 declarations also reference `jsdom` types, so install
|
|
45
|
+
`@types/jsdom` when your project type-checks Fabric's declaration files.
|
|
44
46
|
|
|
45
47
|
## Installation
|
|
46
48
|
|
|
47
|
-
### npm / pnpm / yarn
|
|
48
|
-
|
|
49
49
|
```bash
|
|
50
|
-
npm
|
|
50
|
+
npm install @bensitu/image-editor fabric
|
|
51
51
|
# or
|
|
52
52
|
pnpm add @bensitu/image-editor fabric
|
|
53
53
|
# or
|
|
54
54
|
yarn add @bensitu/image-editor fabric
|
|
55
55
|
```
|
|
56
56
|
|
|
57
|
-
|
|
57
|
+
`fabric@^7.0.0` is a peer dependency: install it explicitly so the editor
|
|
58
|
+
resolves the exact version your application uses.
|
|
58
59
|
|
|
59
|
-
|
|
60
|
-
import ImageEditor, {
|
|
61
|
-
ImageEditor as NamedImageEditor,
|
|
62
|
-
} from "@bensitu/image-editor";
|
|
63
|
-
```
|
|
60
|
+
## Module formats and entry points
|
|
64
61
|
|
|
65
|
-
|
|
62
|
+
The package ships a single public entry, resolved by tooling via the
|
|
63
|
+
`exports` map in `package.json`:
|
|
66
64
|
|
|
67
|
-
|
|
68
|
-
|
|
65
|
+
| Consumer | Resolves to |
|
|
66
|
+
| ------------------------------------- | ------------------------------ |
|
|
67
|
+
| ESM (`import`) | `dist/esm/index.js` |
|
|
68
|
+
| CommonJS (`require`) | `dist/cjs/index.cjs` |
|
|
69
|
+
| TypeScript (`types`) | `dist/types/index.d.ts` |
|
|
70
|
+
| UMD (`<script>`, `unpkg`, `jsdelivr`) | `dist/umd/image-editor.umd.js` |
|
|
71
|
+
| `default` fallback | `dist/esm/index.js` |
|
|
69
72
|
|
|
70
|
-
|
|
71
|
-
|
|
73
|
+
The UMD bundle exposes a global named `ImageEditor` and treats `fabric` as an
|
|
74
|
+
external global named `fabric`.
|
|
72
75
|
|
|
73
|
-
|
|
76
|
+
## Dual entry-point convention
|
|
74
77
|
|
|
75
|
-
|
|
78
|
+
`ImageEditor`'s constructor accepts the Fabric module either explicitly (ESM
|
|
79
|
+
consumers) or via `globalThis.fabric` (UMD consumers). The same source ships
|
|
80
|
+
in all four formats:
|
|
76
81
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
<script src="https://cdn.jsdelivr.net/npm/fabric@5.5.2/dist/fabric.min.js"></script>
|
|
82
|
+
- **Explicit module form** (recommended for bundled apps): pass the Fabric
|
|
83
|
+
module as the first argument.
|
|
80
84
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
85
|
+
```ts
|
|
86
|
+
import * as fabric from 'fabric';
|
|
87
|
+
import { ImageEditor } from '@bensitu/image-editor';
|
|
88
|
+
|
|
89
|
+
const editor = new ImageEditor(fabric, {
|
|
90
|
+
canvasWidth: 800,
|
|
91
|
+
canvasHeight: 600,
|
|
92
|
+
});
|
|
93
|
+
```
|
|
86
94
|
|
|
87
|
-
|
|
95
|
+
- **Global form** (UMD `<script>` consumers): omit the first argument; the
|
|
96
|
+
constructor reads `globalThis.fabric`.
|
|
88
97
|
|
|
89
|
-
|
|
98
|
+
```html
|
|
99
|
+
<script src="https://cdn.jsdelivr.net/npm/fabric@7/dist/index.min.js"></script>
|
|
100
|
+
<script src="https://cdn.jsdelivr.net/npm/@bensitu/image-editor/dist/umd/image-editor.umd.js"></script>
|
|
101
|
+
<script>
|
|
102
|
+
const editor = new ImageEditor({
|
|
103
|
+
canvasWidth: 800,
|
|
104
|
+
canvasHeight: 600,
|
|
105
|
+
});
|
|
106
|
+
</script>
|
|
107
|
+
```
|
|
90
108
|
|
|
91
|
-
|
|
109
|
+
If neither form yields a usable Fabric module, the constructor logs a single
|
|
110
|
+
descriptive `console.error` and `init()` and `loadImage()` become no-ops that
|
|
111
|
+
resolve to `undefined`.
|
|
112
|
+
|
|
113
|
+
## Quick start
|
|
114
|
+
|
|
115
|
+
### HTML
|
|
92
116
|
|
|
93
117
|
```html
|
|
94
|
-
|
|
95
|
-
<canvas id="fabricCanvas"></canvas>
|
|
118
|
+
<canvas id="canvas"></canvas>
|
|
96
119
|
|
|
97
|
-
<!-- Optional Controls -->
|
|
98
120
|
<button id="zoomInButton">Zoom In</button>
|
|
99
121
|
<button id="zoomOutButton">Zoom Out</button>
|
|
100
|
-
|
|
101
122
|
<button id="rotateLeftButton">Rotate Left</button>
|
|
102
123
|
<input id="rotateLeftDegreesInput" type="number" value="90" />
|
|
103
|
-
|
|
104
124
|
<button id="rotateRightButton">Rotate Right</button>
|
|
105
125
|
<input id="rotateRightDegreesInput" type="number" value="90" />
|
|
106
126
|
|
|
@@ -112,517 +132,448 @@ Use `dist/image-editor.js` or `dist/image-editor.min.js` for browser global scri
|
|
|
112
132
|
<button id="applyCropButton">Apply Crop</button>
|
|
113
133
|
<button id="cancelCropButton">Cancel Crop</button>
|
|
114
134
|
|
|
115
|
-
<button id="
|
|
116
|
-
<button id="
|
|
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>
|
|
117
145
|
|
|
118
146
|
<button id="mergeMasksButton">Merge</button>
|
|
119
|
-
<button id="resetImageTransformButton">Reset</button>
|
|
120
147
|
<button id="downloadImageButton">Download</button>
|
|
148
|
+
<button id="undoButton">Undo</button>
|
|
149
|
+
<button id="redoButton">Redo</button>
|
|
150
|
+
<button id="resetImageTransformButton">Reset</button>
|
|
121
151
|
|
|
122
152
|
<input id="imageInput" type="file" accept="image/*" />
|
|
153
|
+
<ul id="maskList"></ul>
|
|
123
154
|
```
|
|
124
155
|
|
|
125
|
-
###
|
|
156
|
+
### TypeScript / ESM
|
|
126
157
|
|
|
127
|
-
|
|
158
|
+
```ts
|
|
159
|
+
import * as fabric from 'fabric';
|
|
160
|
+
import { ImageEditor } from '@bensitu/image-editor';
|
|
161
|
+
import type { ImageEditorOptions, MaskConfig } from '@bensitu/image-editor';
|
|
128
162
|
|
|
129
|
-
|
|
130
|
-
|
|
163
|
+
const editor = new ImageEditor(fabric, {
|
|
164
|
+
canvasWidth: 800,
|
|
165
|
+
canvasHeight: 600,
|
|
166
|
+
backgroundColor: '#ffffff',
|
|
167
|
+
defaultMosaicConfig: {
|
|
168
|
+
brushSize: 48,
|
|
169
|
+
blockSize: 8,
|
|
170
|
+
},
|
|
171
|
+
} satisfies ImageEditorOptions);
|
|
131
172
|
|
|
132
173
|
editor.init({
|
|
133
|
-
|
|
174
|
+
canvas: 'canvas',
|
|
175
|
+
zoomInButton: 'zoomInButton',
|
|
176
|
+
zoomOutButton: 'zoomOutButton',
|
|
177
|
+
rotateLeftButton: 'rotateLeftButton',
|
|
178
|
+
rotateLeftDegreesInput: 'rotateLeftDegreesInput',
|
|
179
|
+
rotateRightButton: 'rotateRightButton',
|
|
180
|
+
rotateRightDegreesInput: 'rotateRightDegreesInput',
|
|
181
|
+
createMaskButton: 'createMaskButton',
|
|
182
|
+
removeSelectedMaskButton: 'removeSelectedMaskButton',
|
|
183
|
+
removeAllMasksButton: 'removeAllMasksButton',
|
|
184
|
+
enterCropModeButton: 'enterCropModeButton',
|
|
185
|
+
applyCropButton: 'applyCropButton',
|
|
186
|
+
cancelCropButton: 'cancelCropButton',
|
|
187
|
+
enterMosaicModeButton: 'enterMosaicModeButton',
|
|
188
|
+
exitMosaicModeButton: 'exitMosaicModeButton',
|
|
189
|
+
mosaicBrushSizeInput: 'mosaicBrushSizeInput',
|
|
190
|
+
mosaicBlockSizeInput: 'mosaicBlockSizeInput',
|
|
191
|
+
mergeMasksButton: 'mergeMasksButton',
|
|
192
|
+
downloadImageButton: 'downloadImageButton',
|
|
193
|
+
undoButton: 'undoButton',
|
|
194
|
+
redoButton: 'redoButton',
|
|
195
|
+
resetImageTransformButton: 'resetImageTransformButton',
|
|
196
|
+
imageInput: 'imageInput',
|
|
197
|
+
maskList: 'maskList',
|
|
134
198
|
});
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
`canvas` is the only required DOM binding when your canvas element does not use the default ID `fabricCanvas`. All other DOM bindings are optional.
|
|
138
199
|
|
|
139
|
-
|
|
200
|
+
// Load an image programmatically (base64 data URL).
|
|
201
|
+
await editor.loadImage('data:image/jpeg;base64,...');
|
|
140
202
|
|
|
141
|
-
|
|
203
|
+
// Add a rectangular mask, then export the result as base64.
|
|
204
|
+
const mask: MaskConfig = { shape: 'rect', width: 120, height: 80, left: '25%', top: '25%' };
|
|
205
|
+
editor.createMask(mask);
|
|
142
206
|
|
|
143
|
-
|
|
144
|
-
const editor = new ImageEditor({
|
|
145
|
-
canvasWidth: 800,
|
|
146
|
-
canvasHeight: 600,
|
|
147
|
-
backgroundColor: "#ffffff",
|
|
148
|
-
initialImageBase64: null
|
|
149
|
-
});
|
|
207
|
+
const dataUrl = await editor.exportImageBase64({ fileType: 'png' });
|
|
150
208
|
```
|
|
151
209
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
#### Demo-style Configuration
|
|
155
|
-
|
|
156
|
-
The docs demo uses an explicit configuration so the demo behavior is predictable. These options are not required for normal usage.
|
|
210
|
+
### CommonJS
|
|
157
211
|
|
|
158
|
-
```
|
|
159
|
-
const
|
|
160
|
-
|
|
161
|
-
expandCanvasToImage: false,
|
|
162
|
-
fitImageToCanvas: true,
|
|
163
|
-
coverImageToCanvas: false,
|
|
164
|
-
|
|
165
|
-
// Image loading / performance.
|
|
166
|
-
downsampleOnLoad: true,
|
|
167
|
-
initialImageBase64: null,
|
|
168
|
-
|
|
169
|
-
// Mask behavior.
|
|
170
|
-
maskRotatable: true,
|
|
171
|
-
maskLabelOnSelect: true,
|
|
172
|
-
maskLabelOffset: 5,
|
|
173
|
-
|
|
174
|
-
// UI behavior.
|
|
175
|
-
backgroundColor: "transparent",
|
|
176
|
-
showPlaceholder: true,
|
|
177
|
-
animationDuration: 100,
|
|
178
|
-
|
|
179
|
-
// Export behavior.
|
|
180
|
-
exportImageAreaByDefault: true
|
|
181
|
-
});
|
|
212
|
+
```js
|
|
213
|
+
const fabric = require('fabric');
|
|
214
|
+
const { ImageEditor } = require('@bensitu/image-editor');
|
|
182
215
|
|
|
183
|
-
editor
|
|
184
|
-
canvas: "fabricCanvas",
|
|
185
|
-
canvasContainer: null,
|
|
186
|
-
imagePlaceholder: "imagePlaceholder",
|
|
187
|
-
scalePercentageInput: "scalePercentageInput",
|
|
188
|
-
rotateLeftButton: "rotateLeftButton",
|
|
189
|
-
rotateRightButton: "rotateRightButton",
|
|
190
|
-
rotateLeftDegreesInput: "rotateLeftDegreesInput",
|
|
191
|
-
rotateRightDegreesInput: "rotateRightDegreesInput",
|
|
192
|
-
createMaskButton: null,
|
|
193
|
-
removeSelectedMaskButton: "removeSelectedMaskButton",
|
|
194
|
-
removeAllMasksButton: "removeAllMasksButton",
|
|
195
|
-
mergeMasksButton: "mergeMasksButton",
|
|
196
|
-
downloadImageButton: "downloadImageButton",
|
|
197
|
-
maskList: "maskList",
|
|
198
|
-
enterCropModeButton: "enterCropModeButton",
|
|
199
|
-
applyCropButton: "applyCropButton",
|
|
200
|
-
cancelCropButton: "cancelCropButton",
|
|
201
|
-
resetImageTransformButton: "resetImageTransformButton",
|
|
202
|
-
imageInput: null,
|
|
203
|
-
uploadArea: null
|
|
204
|
-
});
|
|
216
|
+
const editor = new ImageEditor(fabric, { canvasWidth: 800, canvasHeight: 600 });
|
|
205
217
|
```
|
|
206
218
|
|
|
207
|
-
|
|
219
|
+
In v2, `require('@bensitu/image-editor')` returns a namespace object with
|
|
220
|
+
`ImageEditor`, `default`, and `isMaskObject`; it does not return the
|
|
221
|
+
constructor directly.
|
|
208
222
|
|
|
223
|
+
## Public API
|
|
209
224
|
|
|
210
|
-
|
|
225
|
+
`ImageEditor` is the only public class. The package barrel re-exports it as
|
|
226
|
+
both the default export and a named export, alongside `isMaskObject` and the
|
|
227
|
+
documented public types. Internal helpers (animation queue, command, history
|
|
228
|
+
manager, controllers, services, managers, utility modules) are intentionally
|
|
229
|
+
not exported and may change without notice.
|
|
211
230
|
|
|
212
|
-
|
|
213
|
-
async function loadImageDataUrl(imageBase64) {
|
|
214
|
-
try {
|
|
215
|
-
await editor.loadImage(imageBase64);
|
|
216
|
-
} catch (error) {
|
|
217
|
-
console.error("Image could not be loaded:", error);
|
|
218
|
-
}
|
|
219
|
-
}
|
|
231
|
+
### Constructor
|
|
220
232
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
## Configuration Options
|
|
225
|
-
|
|
226
|
-
All options are optional. If an option is not provided, the editor uses the default value listed below.
|
|
227
|
-
|
|
228
|
-
When creating the editor instance, pass an options object to override defaults.
|
|
229
|
-
|
|
230
|
-
| Option | Default | Description |
|
|
231
|
-
| ----------------------------- | ------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
232
|
-
| `canvasWidth` | `800` | Initial canvas width in pixels. |
|
|
233
|
-
| `canvasHeight` | `600` | Initial canvas height in pixels. |
|
|
234
|
-
| `backgroundColor` | `transparent` | Canvas background color. |
|
|
235
|
-
| `animationDuration` | `300` | Animation duration for scale and rotation operations, in milliseconds. |
|
|
236
|
-
| `minScale` | `0.1` | Minimum image scale factor. |
|
|
237
|
-
| `maxScale` | `5.0` | Maximum image scale factor. |
|
|
238
|
-
| `scaleStep` | `0.05` | Scale increment/decrement used by zoom controls. |
|
|
239
|
-
| `rotationStep` | `90` | Default rotation step in degrees. |
|
|
240
|
-
| `expandCanvasToImage` | `true` | Expand the canvas to the loaded image size. |
|
|
241
|
-
| `fitImageToCanvas` | `false` | Fit the loaded image inside the visible canvas viewport. |
|
|
242
|
-
| `coverImageToCanvas` | `false` | Scale the image to cover the visible canvas viewport, allowing overflow when needed. |
|
|
243
|
-
| `downsampleOnLoad` | `true` | Downsample large images before rendering. |
|
|
244
|
-
| `downsampleMaxWidth` | `4000` | Maximum source image width before downsampling. |
|
|
245
|
-
| `downsampleMaxHeight` | `3000` | Maximum source image height before downsampling. |
|
|
246
|
-
| `downsampleQuality` | `0.92` | JPEG/WebP quality used when downsampling. `0` is valid and is preserved. |
|
|
247
|
-
| `preserveSourceFormat` | `true` | Preserve the source image format where possible during downsampling. |
|
|
248
|
-
| `downsampleMimeType` | `null` | Optional output MIME type for downsampled images. Supported values include `jpeg`, `jpg`, `png`, `webp`, `image/jpeg`, `image/png`, and `image/webp`. |
|
|
249
|
-
| `imageLoadTimeoutMs` | `30000` | Timeout for image decode/load operations. |
|
|
250
|
-
| `exportMultiplier` | `1` | Default scale multiplier for export. |
|
|
251
|
-
| `maxExportPixels` | `50000000` | Maximum output pixel count allowed per export after applying the multiplier. |
|
|
252
|
-
| `maxHistorySize` | `50` | Maximum undo/redo history entries to retain. Large base64 source images can make each history snapshot expensive. |
|
|
253
|
-
| `exportImageAreaByDefault` | `true` | Export only the image area by default instead of the full canvas. |
|
|
254
|
-
| `defaultMaskWidth` | `50` | Default mask width in pixels. |
|
|
255
|
-
| `defaultMaskHeight` | `80` | Default mask height in pixels. |
|
|
256
|
-
| `maskRotatable` | `false` | Whether masks can be rotated. |
|
|
257
|
-
| `maskLabelOnSelect` | `true` | Show the mask label when a mask is selected. |
|
|
258
|
-
| `maskLabelOffset` | `3` | Offset for mask labels from the mask's top-left corner. |
|
|
259
|
-
| `maskName` | `mask` | Prefix for mask names and labels. |
|
|
260
|
-
| `groupSelection` | `false` | Whether Fabric can select multiple masks as an active selection. |
|
|
261
|
-
| `label.getText` | `(mask) => mask.maskName` | Callback for custom label text. The second argument is the mask's stable zero-based creation index (`mask.maskId - 1`). |
|
|
262
|
-
| `label.create` | `undefined` | Optional callback that returns a custom Fabric label object for the selected mask. Invalid or throwing callbacks fall back to the default label. |
|
|
263
|
-
| `label.textOptions` | see defaults | Fabric text options merged into the default label when `label.create` is not used or falls back. |
|
|
264
|
-
| `showPlaceholder` | `true` | Show a placeholder when no image is loaded. When `false`, internal load, rollback, and status paths keep the placeholder hidden. |
|
|
265
|
-
| `initialImageBase64` | `null` | Base64 data URL to auto-load during initialization. |
|
|
266
|
-
| `defaultDownloadFileName` | `edited_image.jpg` | Default file name for downloads. |
|
|
267
|
-
| `crop.minWidth` | `100` | Minimum crop rectangle width, clamped to the current image bounds. |
|
|
268
|
-
| `crop.minHeight` | `100` | Minimum crop rectangle height, clamped to the current image bounds. |
|
|
269
|
-
| `crop.padding` | `10` | Initial inset from the image bounds when entering crop mode. |
|
|
270
|
-
| `crop.hideMasksDuringCrop` | `true` | Hide editable masks while crop mode is active. |
|
|
271
|
-
| `crop.preserveMasksAfterCrop` | `false` | Keep masks that intersect the crop area, shifted into the cropped canvas. Merge masks first if they should be baked into the image pixels. |
|
|
272
|
-
| `crop.allowRotationOfCropRect` | `false` | Reserved for future rotated crop support. In v1.x, crop rectangles stay axis-aligned; setting this to `true` reports a warning and rotation remains disabled. |
|
|
273
|
-
| `onImageLoaded` | `null` | Callback invoked after an image load is committed. Callback errors are reported as warnings and do not roll back the loaded image. |
|
|
274
|
-
| `onError` | `null` | Callback invoked for recoverable internal errors. |
|
|
275
|
-
| `onWarning` | `null` | Callback invoked for recoverable internal warnings. |
|
|
276
|
-
|
|
277
|
-
`expandCanvasToImage`, `fitImageToCanvas`, and `coverImageToCanvas` are mutually exclusive layout modes. If more than one is enabled, the editor reports a warning and uses this precedence: `fitImageToCanvas`, then `coverImageToCanvas`, then `expandCanvasToImage`.
|
|
278
|
-
|
|
279
|
-
Numeric runtime options are normalized during construction. Non-finite or invalid dimensions, scale limits, export limits, crop sizes, label offsets, and history sizes fall back to safe defaults. `animationDuration: 0` and `downsampleQuality: 0` remain valid.
|
|
280
|
-
|
|
281
|
-
## DOM Binding Keys
|
|
282
|
-
|
|
283
|
-
`init(idMap)` binds editor behavior to DOM elements by ID. All keys are optional when the default IDs are present. Optional bindings can also be set to `null` to disable the built-in listener for that element.
|
|
284
|
-
|
|
285
|
-
| Key | Description |
|
|
286
|
-
| --------------------------- | -------------------------------------------------------------- |
|
|
287
|
-
| `canvas` | Required canvas element ID. |
|
|
288
|
-
| `canvasContainer` | Optional scrollable viewport/container element ID. |
|
|
289
|
-
| `imagePlaceholder` | Optional placeholder element shown when no image is loaded. |
|
|
290
|
-
| `scalePercentageInput` | Optional element used to display the current scale percentage. |
|
|
291
|
-
| `rotateLeftDegreesInput` | Optional input used by the rotate-left button. |
|
|
292
|
-
| `rotateRightDegreesInput` | Optional input used by the rotate-right button. |
|
|
293
|
-
| `rotateLeftButton` | Rotate image left. |
|
|
294
|
-
| `rotateRightButton` | Rotate image right. |
|
|
295
|
-
| `createMaskButton` | Create a new mask. |
|
|
296
|
-
| `removeSelectedMaskButton` | Remove the currently selected mask. |
|
|
297
|
-
| `removeAllMasksButton` | Remove all masks. |
|
|
298
|
-
| `mergeMasksButton` | Merge masks into the base image. |
|
|
299
|
-
| `downloadImageButton` | Download the edited image. |
|
|
300
|
-
| `maskList` | Optional mask list container. |
|
|
301
|
-
| `zoomInButton` | Zoom in. |
|
|
302
|
-
| `zoomOutButton` | Zoom out. |
|
|
303
|
-
| `resetImageTransformButton` | Reset scale and rotation. |
|
|
304
|
-
| `undoButton` | Undo the last state change. |
|
|
305
|
-
| `redoButton` | Redo the next state change. |
|
|
306
|
-
| `imageInput` | File input used to load images. |
|
|
307
|
-
| `uploadArea` | Optional clickable upload area that triggers the file input. |
|
|
308
|
-
| `enterCropModeButton` | Enter crop mode. |
|
|
309
|
-
| `applyCropButton` | Apply the current crop rectangle. |
|
|
310
|
-
| `cancelCropButton` | Cancel crop mode. |
|
|
311
|
-
|
|
312
|
-
### Legacy DOM Binding Keys
|
|
313
|
-
|
|
314
|
-
The following DOM binding keys remain supported in `1.x` for compatibility, but are deprecated and will be removed in `v2.0.0`.
|
|
315
|
-
|
|
316
|
-
| Deprecated key | Use instead |
|
|
317
|
-
| -------------------- | --------------------------- |
|
|
318
|
-
| `imgPlaceholder` | `imagePlaceholder` |
|
|
319
|
-
| `scaleRate` | `scalePercentageInput` |
|
|
320
|
-
| `rotationLeftInput` | `rotateLeftDegreesInput` |
|
|
321
|
-
| `rotationRightInput` | `rotateRightDegreesInput` |
|
|
322
|
-
| `rotateLeftBtn` | `rotateLeftButton` |
|
|
323
|
-
| `rotateRightBtn` | `rotateRightButton` |
|
|
324
|
-
| `addMaskBtn` | `createMaskButton` |
|
|
325
|
-
| `removeMaskBtn` | `removeSelectedMaskButton` |
|
|
326
|
-
| `removeAllMasksBtn` | `removeAllMasksButton` |
|
|
327
|
-
| `mergeBtn` | `mergeMasksButton` |
|
|
328
|
-
| `downloadBtn` | `downloadImageButton` |
|
|
329
|
-
| `zoomInBtn` | `zoomInButton` |
|
|
330
|
-
| `zoomOutBtn` | `zoomOutButton` |
|
|
331
|
-
| `resetBtn` | `resetImageTransformButton` |
|
|
332
|
-
| `undoBtn` | `undoButton` |
|
|
333
|
-
| `redoBtn` | `redoButton` |
|
|
334
|
-
| `cropBtn` | `enterCropModeButton` |
|
|
335
|
-
| `applyCropBtn` | `applyCropButton` |
|
|
336
|
-
| `cancelCropBtn` | `cancelCropButton` |
|
|
337
|
-
|
|
338
|
-
## API Methods
|
|
339
|
-
|
|
340
|
-
| Method | Returns | Description |
|
|
341
|
-
| --------------------------------- | ----------------------- | --------------------------------------------------------------------------------------------------------------------- |
|
|
342
|
-
| `init(idMap)` | `void` | Bind the editor to DOM elements. Pass IDs in an object. |
|
|
343
|
-
| `dispose()` | `void` | Cleans up the canvas, listeners, crop state, animations, and captured DOM visibility/disabled/pointer-events state. |
|
|
344
|
-
| `loadImage(imageBase64, options)` | `Promise<void>` | Load an image from a base64 data URL. Resolves after the Fabric image is on the canvas. |
|
|
345
|
-
| `isImageLoaded()` | `boolean` | Return whether a valid image is loaded on the canvas. |
|
|
346
|
-
| `isBusy()` | `boolean` | Return whether the editor is loading, animating, cropping, applying crop, or running another compound operation. |
|
|
347
|
-
| `scaleImage(factor)` | `Promise<void>` | Scale the image to the given finite factor relative to the base scale. Non-finite values are ignored. |
|
|
348
|
-
| `rotateImage(degrees)` | `Promise<void>` | Rotate the image to the given finite angle in degrees. Non-finite values are ignored. |
|
|
349
|
-
| `resetImageTransform()` | `Promise<void>` | Reset scale to `1` and rotation to `0`. |
|
|
350
|
-
| `undo()` | `Promise<void>` | Undo the last state change. Resolves after the canvas state is restored. |
|
|
351
|
-
| `redo()` | `Promise<void>` | Redo the next state change. Resolves after the canvas state is restored. |
|
|
352
|
-
| `createMask(config)` | `fabric.Object \| null` | Create a mask on the canvas. Config can include shape, width, height, color, opacity, position, style, and callbacks. |
|
|
353
|
-
| `removeSelectedMask()` | `void` | Remove the currently selected mask or selected masks. |
|
|
354
|
-
| `removeAllMasks(options)` | `void` | Remove all masks from the canvas. |
|
|
355
|
-
| `enterCropMode()` | `void` | Create a resizable/movable selection rectangle on top of the image. |
|
|
356
|
-
| `cancelCrop()` | `void` | Cancel crop mode and remove the temporary selection rectangle. No-ops while `applyCrop()` is already running. |
|
|
357
|
-
| `applyCrop()` | `Promise<void>` | Apply the current valid crop rectangle to the canvas. Invalid crop regions warn and keep crop mode active. |
|
|
358
|
-
| `mergeMasks()` | `Promise<void>` | Merge masks into the base image on the canvas. |
|
|
359
|
-
| `downloadImage(fileName)` | `void` | Download the edited image as a file. |
|
|
360
|
-
| `exportImageBase64(options)` | `Promise<string>` | Export an image data URL. `fileType` can be `jpeg`, `jpg`, `png`, `webp`, or a supported image MIME type. |
|
|
361
|
-
| `exportImageFile(options)` | `Promise<File>` | Export the current canvas as a `File` object. |
|
|
362
|
-
| `saveState()` | `void` | Save the current editor state to history. Usually called internally after supported edits. |
|
|
363
|
-
| `loadFromState(serializedState)` | `Promise<void>` | Restore the editor from a serialized canvas/editor state. |
|
|
364
|
-
|
|
365
|
-
Deprecated method aliases are still available for compatibility and will be removed in `v2.0.0`.
|
|
366
|
-
|
|
367
|
-
| Deprecated method | Use instead |
|
|
368
|
-
| ------------------------- | ---------------------------- |
|
|
369
|
-
| `reset()` | `resetImageTransform()` |
|
|
370
|
-
| `addMask(config)` | `createMask(config)` |
|
|
371
|
-
| `merge()` | `mergeMasks()` |
|
|
372
|
-
| `getImageBase64(options)` | `exportImageBase64(options)` |
|
|
373
|
-
|
|
374
|
-
## Mask Configuration
|
|
375
|
-
|
|
376
|
-
`createMask(config)` accepts an optional configuration object.
|
|
377
|
-
|
|
378
|
-
Invalid mask configuration, such as non-finite numeric values, non-positive dimensions/radii, duplicate or zero-area polygon points, malformed polygon points, throwing custom generators, or custom generators that do not return a Fabric object, is rejected with a warning and returns `null` without mutating the canvas or history.
|
|
379
|
-
|
|
380
|
-
| Option | Description |
|
|
381
|
-
| ------------------ | ------------------------------------------------------------------------------------------ |
|
|
382
|
-
| `shape` | Mask shape. Built-in values include `rect`, `circle`, `ellipse`, and `polygon`. |
|
|
383
|
-
| `width` / `height` | Mask size in pixels, percentage string, or resolver callback. |
|
|
384
|
-
| `radius` | Circle radius in pixels, percentage string, or resolver callback. |
|
|
385
|
-
| `rx` / `ry` | Ellipse radius or rectangle corner radius. |
|
|
386
|
-
| `points` | Polygon points as `{ x, y }` objects or `[x, y]` tuples. |
|
|
387
|
-
| `left` / `top` | Mask position in pixels, percentage string, or resolver callback. |
|
|
388
|
-
| `angle` | Initial rotation angle in degrees. |
|
|
389
|
-
| `color` | Fill color. |
|
|
390
|
-
| `alpha` | Opacity from `0` to `1`. |
|
|
391
|
-
| `selectable` | Whether the mask can be selected. |
|
|
392
|
-
| `hasControls` | Whether Fabric transform controls are shown. |
|
|
393
|
-
| `styles` | Additional Fabric style properties, such as `stroke`, `strokeWidth`, or `strokeDashArray`. |
|
|
394
|
-
| `fabricGenerator` | Factory callback for creating a custom Fabric object. |
|
|
395
|
-
| `onCreate` | Callback invoked after the mask is added to the canvas. |
|
|
396
|
-
|
|
397
|
-
`fabricGenerator` runs before the mask is committed. If it throws or returns an invalid object, `createMask()` reports a warning and returns `null`. `onCreate` runs after the mask and history entry are committed; if it throws, the mask remains on the canvas and the error is reported as a warning.
|
|
398
|
-
|
|
399
|
-
Label callbacks are also isolated. If `label.create` throws or returns an invalid object, the editor uses the default Fabric text label. If `label.getText` throws, the editor uses `mask.maskName`.
|
|
400
|
-
|
|
401
|
-
Example:
|
|
402
|
-
|
|
403
|
-
```javascript
|
|
404
|
-
const mask = editor.createMask({
|
|
405
|
-
shape: "rect",
|
|
406
|
-
width: 120,
|
|
407
|
-
height: 80,
|
|
408
|
-
left: 20,
|
|
409
|
-
top: 20,
|
|
410
|
-
color: "rgba(0, 0, 0, 0.5)",
|
|
411
|
-
alpha: 0.5,
|
|
412
|
-
});
|
|
233
|
+
```ts
|
|
234
|
+
new ImageEditor(fabric: FabricModule, options?: ImageEditorOptions)
|
|
235
|
+
new ImageEditor(options?: ImageEditorOptions) // UMD: reads globalThis.fabric
|
|
413
236
|
```
|
|
414
237
|
|
|
415
|
-
|
|
238
|
+
### Lifecycle
|
|
416
239
|
|
|
417
|
-
|
|
240
|
+
| Method | Description |
|
|
241
|
+
| -------------- | ------------------------------------------------------------------------------------ |
|
|
242
|
+
| `init(idMap?)` | Bind the editor to DOM elements. Pass an `ElementIdMap`; any key may be omitted. |
|
|
243
|
+
| `dispose()` | Tear down the editor, drain DOM bindings, and dispose the Fabric canvas. Idempotent. |
|
|
418
244
|
|
|
419
|
-
|
|
245
|
+
### Image loading
|
|
420
246
|
|
|
421
|
-
|
|
247
|
+
| Method | Description |
|
|
248
|
+
| ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
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. |
|
|
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 crop mode, or in Mosaic mode. |
|
|
252
|
+
| `setLayoutMode(mode)` | Select the layout strategy for future image loads. `mode` is `'fit'`, `'cover'`, or `'expand'`. |
|
|
422
253
|
|
|
423
|
-
|
|
254
|
+
`LoadImageOptions` currently includes `preserveScroll?: boolean` for
|
|
255
|
+
preserving the container's scroll position across both successful loads and
|
|
256
|
+
rollback paths.
|
|
424
257
|
|
|
425
|
-
|
|
258
|
+
Use `defaultLayoutMode` to choose the initial image-load strategy, then call
|
|
259
|
+
`setLayoutMode()` when a UI should change how future images are placed:
|
|
426
260
|
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
- **Keep the default `crop.preserveMasksAfterCrop: false`** when unmerged masks should be discarded by crop.
|
|
431
|
-
|
|
432
|
-
### Preserve editable masks after crop
|
|
433
|
-
|
|
434
|
-
```javascript
|
|
435
|
-
const editor = new ImageEditor({
|
|
436
|
-
crop: {
|
|
437
|
-
preserveMasksAfterCrop: true,
|
|
438
|
-
},
|
|
261
|
+
```ts
|
|
262
|
+
const editor = new ImageEditor(fabric, {
|
|
263
|
+
defaultLayoutMode: 'fit',
|
|
439
264
|
});
|
|
440
|
-
```
|
|
441
|
-
|
|
442
|
-
### Bake masks into the image before crop
|
|
443
265
|
|
|
444
|
-
|
|
445
|
-
try {
|
|
446
|
-
await editor.mergeMasks();
|
|
447
|
-
editor.enterCropMode();
|
|
448
|
-
await editor.applyCrop();
|
|
449
|
-
} catch (error) {
|
|
450
|
-
console.error("Crop workflow failed:", error);
|
|
451
|
-
}
|
|
452
|
-
```
|
|
453
|
-
|
|
454
|
-
## Export Examples
|
|
455
|
-
|
|
456
|
-
### Export as Base64
|
|
457
|
-
|
|
458
|
-
```javascript
|
|
459
|
-
try {
|
|
460
|
-
const dataUrl = await editor.exportImageBase64({
|
|
461
|
-
fileType: "jpeg",
|
|
462
|
-
quality: 0.92,
|
|
463
|
-
multiplier: 1,
|
|
464
|
-
});
|
|
465
|
-
|
|
466
|
-
console.log(dataUrl);
|
|
467
|
-
} catch (error) {
|
|
468
|
-
console.error("Export failed:", error);
|
|
469
|
-
}
|
|
470
|
-
```
|
|
266
|
+
await editor.loadImage(imageA);
|
|
471
267
|
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
try {
|
|
476
|
-
const file = await editor.exportImageFile({
|
|
477
|
-
fileName: "edited_image.jpg",
|
|
478
|
-
fileType: "jpeg",
|
|
479
|
-
quality: 0.92,
|
|
480
|
-
mergeMask: true,
|
|
481
|
-
});
|
|
482
|
-
|
|
483
|
-
console.log(file);
|
|
484
|
-
} catch (error) {
|
|
485
|
-
console.error("File export failed:", error);
|
|
486
|
-
}
|
|
268
|
+
// Future loads use cover. The current image is not re-laid out immediately.
|
|
269
|
+
editor.setLayoutMode('cover');
|
|
270
|
+
await editor.loadImage(imageB);
|
|
487
271
|
```
|
|
488
272
|
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
273
|
+
Invalid JavaScript `defaultLayoutMode` values fall back to `'expand'`.
|
|
274
|
+
Invalid `setLayoutMode()` calls are ignored and preserve the current mode.
|
|
275
|
+
|
|
276
|
+
File-input helpers accept JPG, PNG, WebP, GIF, and BMP files. GIF and BMP are
|
|
277
|
+
decoded as static raster input for canvas editing; GIF animation and BMP/GIF
|
|
278
|
+
source-format preservation are not retained. Export output remains controlled by
|
|
279
|
+
the JPEG, PNG, or WebP export options.
|
|
280
|
+
|
|
281
|
+
### Transforms
|
|
282
|
+
|
|
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
|
+
| `resetImageTransform()` | Animate to scale 1 and rotation 0. Records exactly one history entry covering the entire transform. |
|
|
288
|
+
|
|
289
|
+
### Masks
|
|
290
|
+
|
|
291
|
+
| Method | Description |
|
|
292
|
+
| -------------------------- | ----------------------------------------------------------------------------- |
|
|
293
|
+
| `createMask(config?)` | The single mask-creation entry point. Returns the new `MaskObject` or `null`. |
|
|
294
|
+
| `removeSelectedMask()` | Remove the currently selected mask and push one history entry. |
|
|
295
|
+
| `removeAllMasks(options?)` | Remove every mask. `options.saveHistory` defaults to `true`. |
|
|
296
|
+
|
|
297
|
+
`MaskConfig` supports rect, circle, ellipse, polygon, and a custom
|
|
298
|
+
`fabricGenerator`. Falsy values in `styles` (`0`, `false`, `null`, `''`,
|
|
299
|
+
`NaN`) are applied verbatim.
|
|
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
|
+
},
|
|
494
316
|
});
|
|
495
|
-
```
|
|
496
|
-
|
|
497
|
-
JPEG exports cannot preserve transparency. Transparent, zero-alpha, empty, or invalid `backgroundColor` values are flattened against white; valid opaque CSS colors are preserved.
|
|
498
|
-
|
|
499
|
-
Undo/redo history is limited by `maxHistorySize`. The default is `50`; lower it for workflows that load large base64 images and perform many edits.
|
|
500
317
|
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
maxHistorySize: 20,
|
|
504
|
-
});
|
|
318
|
+
editor.createMask(); // Uses defaultMaskConfig.
|
|
319
|
+
editor.createMask({ color: 'rgba(0, 128, 255, 0.35)' }); // Per-call override.
|
|
505
320
|
```
|
|
506
321
|
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
322
|
+
### Crop
|
|
323
|
+
|
|
324
|
+
| Method | Description |
|
|
325
|
+
| ----------------- | ------------------------------------------------------------------------------------ |
|
|
326
|
+
| `enterCropMode()` | Add an interactive crop rectangle on top of the image. |
|
|
327
|
+
| `applyCrop()` | Apply the current crop region. Atomic: failure rolls back to the pre-crop snapshot. |
|
|
328
|
+
| `cancelCrop()` | Cancel crop mode and restore the prior canvas state without pushing a history entry. |
|
|
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
|
+
});
|
|
528
355
|
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
356
|
+
editor.init({
|
|
357
|
+
canvas: 'canvas',
|
|
358
|
+
enterMosaicModeButton: 'enterMosaicModeButton',
|
|
359
|
+
exitMosaicModeButton: 'exitMosaicModeButton',
|
|
360
|
+
mosaicBrushSizeInput: 'mosaicBrushSizeInput',
|
|
361
|
+
mosaicBlockSizeInput: 'mosaicBlockSizeInput',
|
|
532
362
|
});
|
|
533
363
|
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
try {
|
|
540
|
-
await editor.rotateImage(degrees);
|
|
541
|
-
} catch (error) {
|
|
542
|
-
console.error("Rotate failed:", error);
|
|
543
|
-
showEditorMessage("Rotation failed. Please try again.");
|
|
544
|
-
}
|
|
545
|
-
}
|
|
546
|
-
|
|
547
|
-
function showEditorMessage(message) {
|
|
548
|
-
// Replace this with your own toast, alert, or inline message UI.
|
|
549
|
-
console.log(message);
|
|
550
|
-
}
|
|
364
|
+
editor.enterMosaicMode();
|
|
365
|
+
editor.setMosaicConfig({ brushSize: 64, blockSize: 12 });
|
|
366
|
+
editor.resetMosaicConfig();
|
|
551
367
|
```
|
|
552
368
|
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
Example:
|
|
589
|
-
|
|
590
|
-
```javascript
|
|
591
|
-
// Masks become part of the image pixels before crop.
|
|
592
|
-
await editor.mergeMasks();
|
|
593
|
-
editor.enterCropMode();
|
|
594
|
-
await editor.applyCrop();
|
|
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
|
+
|
|
377
|
+
### Merge and export
|
|
378
|
+
|
|
379
|
+
| Method | Description |
|
|
380
|
+
| ----------------------------- | ---------------------------------------------------------------------------------------------- |
|
|
381
|
+
| `mergeMasks()` | Bake masks into the base image atomically. Returns `Promise<void>`. |
|
|
382
|
+
| `exportImageBase64(options?)` | Returns `Promise<string>` (data URL). Resolves to `''` with a warning when no image is loaded. |
|
|
383
|
+
| `exportImageFile(options?)` | Returns `Promise<File>`. Rejects when no image is loaded. |
|
|
384
|
+
| `downloadImage(fileName?)` | Triggers a browser download. No-op when no image is loaded. |
|
|
385
|
+
|
|
386
|
+
`Base64ExportOptions` and `ImageFileExportOptions` separate mask compositing
|
|
387
|
+
from export region selection:
|
|
388
|
+
|
|
389
|
+
| Option | Default | Description |
|
|
390
|
+
| ------------ | --------- | --------------------------------------------------------------------------- |
|
|
391
|
+
| `mergeMask` | `true` | Flatten masks into exported pixels. Mask labels are never exported. |
|
|
392
|
+
| `exportArea` | `'image'` | `'image'` clips to the image bounding box; `'canvas'` exports the canvas. |
|
|
393
|
+
| `fileType` | `'jpeg'` | `'png'`, `'jpeg'`, `'jpg'`, `'webp'`, or matching full MIME strings. |
|
|
394
|
+
| `format` | `'jpeg'` | Alias for `fileType` on `exportImageBase64`; `fileType` wins when both set. |
|
|
395
|
+
| `quality` | `0.92` | Lossy quality clamped to `[0, 1]`; ignored for PNG. |
|
|
396
|
+
| `multiplier` | `1` | Output resolution multiplier. |
|
|
397
|
+
| `fileName` | option | `ImageFileExportOptions` only. Defaults to `defaultDownloadFileName`. |
|
|
398
|
+
|
|
399
|
+
```ts
|
|
400
|
+
await editor.exportImageBase64({ exportArea: 'image', mergeMask: true });
|
|
401
|
+
await editor.exportImageBase64({ exportArea: 'image', mergeMask: false });
|
|
402
|
+
await editor.exportImageBase64({ exportArea: 'canvas', mergeMask: true });
|
|
403
|
+
await editor.exportImageBase64({ exportArea: 'canvas', mergeMask: false });
|
|
595
404
|
```
|
|
596
405
|
|
|
597
|
-
|
|
406
|
+
### State and history
|
|
407
|
+
|
|
408
|
+
| Method | Description |
|
|
409
|
+
| ------------------------- | ------------------------------------------------------------------------------------- |
|
|
410
|
+
| `saveState()` | Capture a snapshot of the canvas plus editor metadata into the history stack. |
|
|
411
|
+
| `loadFromState(snapshot)` | Restore canvas, masks, and editor metadata from a snapshot. Returns `Promise<void>`. |
|
|
412
|
+
| `undo()` | Undo the last state change. Routed through the animation queue. No-op while disposed. |
|
|
413
|
+
| `redo()` | Redo the next state change. Routed through the animation queue. No-op while disposed. |
|
|
414
|
+
|
|
415
|
+
## Configuration options
|
|
416
|
+
|
|
417
|
+
Pass an `ImageEditorOptions` object as the second constructor argument
|
|
418
|
+
(or as the only argument when using the UMD global form). Unknown keys are
|
|
419
|
+
ignored; nested `label` and `crop` objects are deep-merged with the defaults.
|
|
420
|
+
|
|
421
|
+
| Option | Default | Description |
|
|
422
|
+
| ------------------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
423
|
+
| `canvasWidth` | `800` | Initial and hidden-container fallback canvas width in pixels. |
|
|
424
|
+
| `canvasHeight` | `600` | Initial and hidden-container fallback canvas height in pixels. |
|
|
425
|
+
| `backgroundColor` | `'transparent'` | Fabric canvas background color. |
|
|
426
|
+
| `animationDuration` | `300` | Duration of scale and rotate animations (ms). |
|
|
427
|
+
| `minScale` | `0.1` | Minimum scale factor. |
|
|
428
|
+
| `maxScale` | `5.0` | Maximum scale factor. |
|
|
429
|
+
| `scaleStep` | `0.05` | Scale delta per zoom step. |
|
|
430
|
+
| `rotationStep` | `90` | Rotation step in degrees. |
|
|
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'`. |
|
|
432
|
+
| `downsampleOnLoad` | `true` | Downsample large images on load. |
|
|
433
|
+
| `downsampleMaxWidth` | `4000` | Max width before downsampling kicks in. |
|
|
434
|
+
| `downsampleMaxHeight` | `3000` | Max height before downsampling kicks in. |
|
|
435
|
+
| `downsampleQuality` | `0.92` | Lossy quality used when downsampling and exporting. |
|
|
436
|
+
| `preserveSourceFormat` | `true` | Preserve PNG/WebP MIME through downsampling unless `downsampleMimeType` is set. |
|
|
437
|
+
| `downsampleMimeType` | `null` | Explicit downsample MIME type. Overrides `preserveSourceFormat`. |
|
|
438
|
+
| `imageLoadTimeoutMs` | `30000` | Maximum duration for both decode and Fabric image creation during `loadImage`. |
|
|
439
|
+
| `exportMultiplier` | `1` | Output resolution multiplier. |
|
|
440
|
+
| `maxExportPixels` | `50000000` | Maximum output pixel count after applying the export multiplier. Invalid values fall back to this default. |
|
|
441
|
+
| `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. |
|
|
442
|
+
| `exportAreaByDefault` | `'image'` | Default export region for `exportImageBase64`, `exportImageFile`, and `downloadImage`. |
|
|
443
|
+
| `mergeMaskByDefault` | `true` | Default mask compositing behavior for `exportImageBase64`, `exportImageFile`, and `downloadImage`. |
|
|
444
|
+
| `defaultMaskWidth` | `50` | Default mask width. |
|
|
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. |
|
|
448
|
+
| `maskRotatable` | `false` | Allow masks to be rotated by the user. |
|
|
449
|
+
| `maskLabelOnSelect` | `true` | Show a label above a selected mask. |
|
|
450
|
+
| `maskLabelOffset` | `3` | Pixel offset of the label from the mask's top-left corner. |
|
|
451
|
+
| `maskName` | `'mask'` | Prefix used for auto-generated mask names. |
|
|
452
|
+
| `groupSelection` | `false` | Allow Fabric multi-object group selection on the canvas. |
|
|
453
|
+
| `showPlaceholder` | `true` | Show a placeholder element while no image is loaded. |
|
|
454
|
+
| `initialImageBase64` | `null` | Base64 data URL auto-loaded after construction. |
|
|
455
|
+
| `defaultDownloadFileName` | `'edited_image.jpg'` | Default file name used by `downloadImage()`. |
|
|
456
|
+
| `onImageLoadStart` | `null` | Called before a valid image load begins. |
|
|
457
|
+
| `onImageLoaded` | `null` | Called as `(info, context)` once after a successful `loadImage`. Extra arguments are ignored by existing zero-argument JavaScript handlers. |
|
|
458
|
+
| `onImageCleared` | `null` | Called when a committed image is replaced or cleared. |
|
|
459
|
+
| `onImageChanged` | `null` | Called with a safe editor state snapshot after visible editor state changes. |
|
|
460
|
+
| `onBusyChange` | `null` | Called only when the public busy state changes. |
|
|
461
|
+
| `onEditorDisposed` | `null` | Called once when `dispose()` performs teardown. |
|
|
462
|
+
| `onMasksChanged` | `null` | Called with a shallow copy of current mask objects after the mask collection changes. |
|
|
463
|
+
| `onSelectionChange` | `null` | Called with selected mask payload after mask selection changes. |
|
|
464
|
+
| `onError` | `null` | Called as `(error, message)` when the editor reports an error. |
|
|
465
|
+
| `onWarning` | `null` | Called as `(error, message)` when the editor reports a recoverable warning. |
|
|
466
|
+
| `label` | see source | `LabelConfig` for selected-mask labels (`getText`, `textOptions`, `create`). |
|
|
467
|
+
| `crop` | see source | `CropConfig` (`minWidth`, `minHeight`, `padding`, `hideMasksDuringCrop`, `preserveMasksAfterCrop`, `allowRotationOfCropRect`, `exportFileType`, `exportQuality`). `applyCrop()` preserves the current image format by default (`'source'`) and falls back to PNG when unknown. |
|
|
468
|
+
|
|
469
|
+
`crop.exportFileType` defaults to `'source'`. Supported explicit values are
|
|
470
|
+
`'png'`, `'jpeg'`, `'jpg'`, `'webp'`, and full image MIME strings. PNG is
|
|
471
|
+
lossless and ignores `crop.exportQuality`; JPEG/WebP use `crop.exportQuality`
|
|
472
|
+
when finite, otherwise `downsampleQuality`, otherwise `0.92`. Choose JPEG/WebP
|
|
473
|
+
only when smaller intermediate crop output is preferred.
|
|
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
|
+
|
|
480
|
+
## Example workflow
|
|
481
|
+
|
|
482
|
+
1. Construct `ImageEditor` with options and call `init(idMap)` to wire it up.
|
|
483
|
+
2. Load an image via `loadImage(base64)` or the bound file input.
|
|
484
|
+
3. Adjust with `scaleImage`, `rotateImage`, `resetImageTransform`, the crop
|
|
485
|
+
session, or Mosaic mode.
|
|
486
|
+
4. Add `createMask` calls and inspect via the `maskList` element.
|
|
487
|
+
5. Use `mergeMasks` to bake masks into the image, then
|
|
488
|
+
`exportImageBase64`, `exportImageFile`, or `downloadImage` to produce
|
|
489
|
+
the final output.
|
|
490
|
+
6. Call `dispose()` when the editor is unmounted.
|
|
491
|
+
|
|
492
|
+
## Building from source
|
|
598
493
|
|
|
599
494
|
```bash
|
|
495
|
+
npm install
|
|
600
496
|
npm run build
|
|
601
497
|
```
|
|
602
498
|
|
|
603
|
-
|
|
499
|
+
`npm run build` runs `clean → build:esm → build:cjs → build:types →
|
|
500
|
+
build:umd` in order, emitting:
|
|
501
|
+
|
|
502
|
+
- `dist/esm/index.js` (and the rest of the decomposed source tree)
|
|
503
|
+
- `dist/cjs/index.cjs`
|
|
504
|
+
- `dist/types/index.d.ts`
|
|
505
|
+
- `dist/umd/image-editor.umd.js`
|
|
506
|
+
|
|
507
|
+
`npm test` runs the Node-based unit and property tests under `tests/`.
|
|
508
|
+
|
|
509
|
+
For the full local release gate, run:
|
|
604
510
|
|
|
605
511
|
```bash
|
|
512
|
+
npm run format:check
|
|
513
|
+
npm run lint
|
|
514
|
+
npm run typecheck
|
|
606
515
|
npm test
|
|
516
|
+
npm run build
|
|
517
|
+
npm run package:check
|
|
518
|
+
npm audit --audit-level=high
|
|
519
|
+
npm pack --dry-run
|
|
607
520
|
```
|
|
608
521
|
|
|
609
|
-
|
|
522
|
+
`npm run ci` combines format, lint, typecheck, tests, build, and package
|
|
523
|
+
linting. The test suite also supports a clean checkout where `dist/` has not
|
|
524
|
+
been built yet; integration helpers use source modules until build artifacts
|
|
525
|
+
exist, while partial `dist/` trees still fail the artifact checks.
|
|
526
|
+
|
|
527
|
+
## Browser support
|
|
610
528
|
|
|
611
529
|
- Chrome 100+
|
|
612
530
|
- Firefox 100+
|
|
613
531
|
- Safari 15+
|
|
614
532
|
- Edge 100+
|
|
615
533
|
|
|
616
|
-
The
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
##
|
|
621
|
-
|
|
622
|
-
|
|
534
|
+
The library uses modern DOM and ES2022 features (optional chaining, classes,
|
|
535
|
+
`async`/`await`, native promises). Older targets must be transpiled by the
|
|
536
|
+
consumer.
|
|
537
|
+
|
|
538
|
+
## Type declarations
|
|
539
|
+
|
|
540
|
+
Public types are re-exported from the package root:
|
|
541
|
+
|
|
542
|
+
```ts
|
|
543
|
+
import type {
|
|
544
|
+
ImageEditorOptions,
|
|
545
|
+
ResolvedOptions,
|
|
546
|
+
LabelConfig,
|
|
547
|
+
CropConfig,
|
|
548
|
+
MosaicConfig,
|
|
549
|
+
ResolvedMosaicConfig,
|
|
550
|
+
LoadImageOptions,
|
|
551
|
+
RemoveAllMasksOptions,
|
|
552
|
+
DefaultMaskConfig,
|
|
553
|
+
MaskConfig,
|
|
554
|
+
MaskObject,
|
|
555
|
+
MaskNumericProp,
|
|
556
|
+
ResolvedMaskConfig,
|
|
557
|
+
ImageMimeType,
|
|
558
|
+
ImageFileType,
|
|
559
|
+
NormalizedImageFormat,
|
|
560
|
+
ExportArea,
|
|
561
|
+
CropExportFileType,
|
|
562
|
+
MosaicOutputFileType,
|
|
563
|
+
Base64ExportOptions,
|
|
564
|
+
ImageFileExportOptions,
|
|
565
|
+
ImageInfo,
|
|
566
|
+
ImageEditorState,
|
|
567
|
+
ImageEditorSelection,
|
|
568
|
+
ImageEditorCallbackContext,
|
|
569
|
+
ImageEditorOperation,
|
|
570
|
+
ElementIdMap,
|
|
571
|
+
FabricModule,
|
|
572
|
+
} from '@bensitu/image-editor';
|
|
573
|
+
```
|
|
623
574
|
|
|
624
575
|
## License
|
|
625
576
|
|
|
626
|
-
MIT ©
|
|
577
|
+
MIT © Ben Situ.
|
|
627
578
|
|
|
628
|
-
Fabric.js is
|
|
579
|
+
Fabric.js is distributed under its own MIT license.
|