@gradio/imageeditor 0.12.14 → 0.14.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.
Files changed (131) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/Example.svelte +1 -1
  3. package/IMAGE_EDITOR_OVERVIEW.md +224 -0
  4. package/ImageEditor.stories.svelte +13 -5
  5. package/Index.svelte +46 -45
  6. package/{shared/InteractiveImageEditor.svelte → InteractiveImageEditor.svelte} +65 -103
  7. package/README.md +2 -0
  8. package/dist/Example.svelte.d.ts +1 -1
  9. package/dist/Index.svelte +35 -33
  10. package/dist/Index.svelte.d.ts +25 -16
  11. package/dist/{shared/InteractiveImageEditor.svelte → InteractiveImageEditor.svelte} +54 -88
  12. package/dist/{shared/InteractiveImageEditor.svelte.d.ts → InteractiveImageEditor.svelte.d.ts} +17 -15
  13. package/dist/shared/Anchor.svelte +311 -0
  14. package/dist/shared/Anchor.svelte.d.ts +18 -0
  15. package/dist/shared/Controls.svelte +169 -18
  16. package/dist/shared/Controls.svelte.d.ts +9 -2
  17. package/dist/shared/{tools/IconButton.svelte → IconButton.svelte} +19 -3
  18. package/dist/shared/{tools/IconButton.svelte.d.ts → IconButton.svelte.d.ts} +4 -1
  19. package/dist/shared/ImageEditor.svelte +572 -289
  20. package/dist/shared/ImageEditor.svelte.d.ts +54 -56
  21. package/dist/shared/Layers.svelte +260 -0
  22. package/dist/shared/Layers.svelte.d.ts +37 -0
  23. package/dist/shared/Resize.svelte +218 -0
  24. package/dist/shared/Resize.svelte.d.ts +29 -0
  25. package/dist/shared/SecondaryToolbar.svelte +55 -0
  26. package/dist/shared/SecondaryToolbar.svelte.d.ts +37 -0
  27. package/dist/shared/Toolbar.svelte +337 -0
  28. package/dist/shared/Toolbar.svelte.d.ts +42 -0
  29. package/dist/shared/{tools → brush}/BrushOptions.svelte +68 -64
  30. package/dist/shared/{tools → brush}/BrushOptions.svelte.d.ts +9 -9
  31. package/dist/shared/{tools → brush}/BrushSize.svelte +2 -27
  32. package/dist/shared/{tools → brush}/ColorField.svelte +2 -1
  33. package/dist/shared/{tools → brush}/ColorField.svelte.d.ts +1 -0
  34. package/dist/shared/{tools → brush}/ColorPicker.svelte +81 -9
  35. package/dist/shared/{tools → brush}/ColorPicker.svelte.d.ts +1 -0
  36. package/dist/shared/{tools → brush}/ColorSwatch.svelte +78 -38
  37. package/dist/shared/{tools → brush}/ColorSwatch.svelte.d.ts +6 -2
  38. package/dist/shared/brush/brush-cursor.d.ts +101 -0
  39. package/dist/shared/brush/brush-cursor.js +327 -0
  40. package/dist/shared/brush/brush-textures.d.ts +65 -0
  41. package/dist/shared/brush/brush-textures.js +385 -0
  42. package/dist/shared/brush/brush-utils.d.ts +32 -0
  43. package/dist/shared/brush/brush-utils.js +59 -0
  44. package/dist/shared/brush/brush.d.ts +152 -0
  45. package/dist/shared/brush/brush.js +397 -0
  46. package/dist/shared/brush/types.d.ts +37 -0
  47. package/dist/shared/brush/types.js +1 -0
  48. package/dist/shared/core/editor.d.ts +261 -0
  49. package/dist/shared/core/editor.js +1264 -0
  50. package/dist/shared/crop/crop.d.ts +201 -0
  51. package/dist/shared/crop/crop.js +727 -0
  52. package/dist/shared/image/image.d.ts +89 -0
  53. package/dist/shared/image/image.js +183 -0
  54. package/dist/shared/resize/resize.d.ts +270 -0
  55. package/dist/shared/resize/resize.js +1413 -0
  56. package/dist/shared/types.d.ts +16 -0
  57. package/dist/shared/utils/pixi.d.ts +16 -57
  58. package/dist/shared/utils/pixi.js +15 -113
  59. package/dist/shared/zoom/zoom.d.ts +136 -0
  60. package/dist/shared/zoom/zoom.js +548 -0
  61. package/package.json +8 -7
  62. package/shared/Anchor.svelte +384 -0
  63. package/shared/Controls.svelte +178 -37
  64. package/shared/{tools/IconButton.svelte → IconButton.svelte} +21 -4
  65. package/shared/ImageEditor.svelte +712 -350
  66. package/shared/Layers.svelte +282 -0
  67. package/shared/Resize.svelte +239 -0
  68. package/shared/SecondaryToolbar.svelte +67 -0
  69. package/shared/Toolbar.svelte +386 -0
  70. package/shared/brush/BRUSH_TOOL.md +134 -0
  71. package/shared/brush/BrushOptions.svelte +200 -0
  72. package/shared/{tools → brush}/BrushSize.svelte +2 -30
  73. package/shared/{tools → brush}/ColorField.svelte +3 -1
  74. package/shared/{tools → brush}/ColorPicker.svelte +86 -9
  75. package/shared/{tools → brush}/ColorSwatch.svelte +95 -42
  76. package/shared/brush/brush-cursor.ts +408 -0
  77. package/shared/brush/brush-textures.ts +485 -0
  78. package/shared/brush/brush-utils.ts +76 -0
  79. package/shared/brush/brush.ts +510 -0
  80. package/shared/brush/types.ts +41 -0
  81. package/shared/core/EDITOR.md +182 -0
  82. package/shared/core/editor.ts +1788 -0
  83. package/shared/crop/CROP.md +139 -0
  84. package/shared/crop/crop.ts +1027 -0
  85. package/shared/image/IMAGE.md +135 -0
  86. package/shared/image/image.ts +298 -0
  87. package/shared/resize/resize.ts +1894 -0
  88. package/shared/types.ts +19 -0
  89. package/shared/utils/pixi.ts +19 -246
  90. package/shared/zoom/zoom.ts +729 -0
  91. package/dist/shared/layers/Layers.svelte +0 -231
  92. package/dist/shared/layers/Layers.svelte.d.ts +0 -18
  93. package/dist/shared/layers/utils.d.ts +0 -73
  94. package/dist/shared/layers/utils.js +0 -156
  95. package/dist/shared/tools/Brush.svelte +0 -215
  96. package/dist/shared/tools/Brush.svelte.d.ts +0 -29
  97. package/dist/shared/tools/Crop.svelte +0 -155
  98. package/dist/shared/tools/Crop.svelte.d.ts +0 -16
  99. package/dist/shared/tools/Cropper.svelte +0 -271
  100. package/dist/shared/tools/Cropper.svelte.d.ts +0 -41
  101. package/dist/shared/tools/Handle.svelte +0 -260
  102. package/dist/shared/tools/Handle.svelte.d.ts +0 -29
  103. package/dist/shared/tools/Sources.svelte +0 -257
  104. package/dist/shared/tools/Sources.svelte.d.ts +0 -34
  105. package/dist/shared/tools/Tools.svelte +0 -102
  106. package/dist/shared/tools/Tools.svelte.d.ts +0 -48
  107. package/dist/shared/tools/brush.d.ts +0 -62
  108. package/dist/shared/tools/brush.js +0 -133
  109. package/dist/shared/tools/crop.d.ts +0 -15
  110. package/dist/shared/tools/crop.js +0 -154
  111. package/dist/shared/tools/index.d.ts +0 -5
  112. package/dist/shared/tools/index.js +0 -5
  113. package/dist/shared/tools/sources.d.ts +0 -46
  114. package/dist/shared/tools/sources.js +0 -121
  115. package/dist/shared/tools/types.d.ts +0 -1
  116. package/shared/layers/Layers.svelte +0 -250
  117. package/shared/layers/utils.ts +0 -294
  118. package/shared/tools/Brush.svelte +0 -280
  119. package/shared/tools/BrushOptions.svelte +0 -180
  120. package/shared/tools/Crop.svelte +0 -189
  121. package/shared/tools/Cropper.svelte +0 -346
  122. package/shared/tools/Handle.svelte +0 -289
  123. package/shared/tools/Sources.svelte +0 -283
  124. package/shared/tools/Tools.svelte +0 -162
  125. package/shared/tools/brush.ts +0 -247
  126. package/shared/tools/crop.ts +0 -213
  127. package/shared/tools/index.ts +0 -5
  128. package/shared/tools/sources.ts +0 -195
  129. package/shared/tools/types.ts +0 -1
  130. /package/dist/shared/{tools → brush}/BrushSize.svelte.d.ts +0 -0
  131. /package/dist/shared/{tools/types.js → types.js} +0 -0
@@ -0,0 +1,327 @@
1
+ import { Container, Graphics, Sprite } from "pixi.js";
2
+ import {} from "../core/editor";
3
+ import {} from "./types";
4
+ import tinycolor from "tinycolor2";
5
+ import { clear_timeout } from "./brush-utils";
6
+ /**
7
+ * Class to handle all cursor preview-related functionality for the brush tool.
8
+ */
9
+ export class BrushCursor {
10
+ image_editor_context;
11
+ state;
12
+ scale;
13
+ // Cursor-related properties
14
+ cursor_graphics = null;
15
+ cursor_container = null;
16
+ brush_preview_container = null;
17
+ brush_preview_graphics = null;
18
+ is_preview_visible = false;
19
+ is_cursor_over_image = false;
20
+ cursor_position_check_timeout = null;
21
+ is_brush_or_erase_active = false;
22
+ // Event handlers
23
+ _bound_update_cursor = null;
24
+ _bound_check_cursor_over_image = null;
25
+ constructor(image_editor_context, state, scale) {
26
+ this.image_editor_context = image_editor_context;
27
+ this.state = state;
28
+ this.scale = scale;
29
+ this.initialize_cursor();
30
+ this.initialize_brush_preview();
31
+ }
32
+ /**
33
+ * Returns whether the cursor is currently over the image.
34
+ */
35
+ is_over_image() {
36
+ return this.is_cursor_over_image;
37
+ }
38
+ /**
39
+ * Sets up cursor-related event listeners.
40
+ */
41
+ setup_event_listeners() {
42
+ // Clean up any existing listeners
43
+ this.cleanup_event_listeners();
44
+ // Create bound event handlers
45
+ this._bound_update_cursor = this.update_cursor_position.bind(this);
46
+ this._bound_check_cursor_over_image =
47
+ this.check_cursor_over_image.bind(this);
48
+ // Add event listeners using Pixi event system
49
+ // Use app.stage for global events like pointermove
50
+ const stage = this.image_editor_context.app.stage;
51
+ stage.on("pointermove", this._bound_update_cursor);
52
+ stage.on("pointermove", this._bound_check_cursor_over_image);
53
+ // Add event listeners to the image container for enter/leave events
54
+ this.image_editor_context.image_container.on("pointerenter", this.on_image_container_pointer_enter.bind(this));
55
+ this.image_editor_context.image_container.on("pointerleave", this.on_image_container_pointer_leave.bind(this));
56
+ }
57
+ /**
58
+ * Removes all cursor-related event listeners.
59
+ */
60
+ cleanup_event_listeners() {
61
+ // Use Pixi event system for removal
62
+ const stage = this.image_editor_context.app.stage;
63
+ // Remove event listeners if they exist
64
+ if (this._bound_update_cursor) {
65
+ stage.off("pointermove", this._bound_update_cursor);
66
+ this._bound_update_cursor = null;
67
+ }
68
+ if (this._bound_check_cursor_over_image) {
69
+ stage.off("pointermove", this._bound_check_cursor_over_image);
70
+ this._bound_check_cursor_over_image = null;
71
+ }
72
+ // Remove image container event listeners
73
+ this.image_editor_context.image_container.off("pointerenter");
74
+ this.image_editor_context.image_container.off("pointerleave");
75
+ // Clear timeout
76
+ this.cursor_position_check_timeout = clear_timeout(this.cursor_position_check_timeout);
77
+ }
78
+ /**
79
+ * initializes the cursor for the brush tool.
80
+ */
81
+ initialize_cursor() {
82
+ // clean up existing cursor if it exists
83
+ if (this.cursor_container) {
84
+ if (this.cursor_container.parent) {
85
+ this.cursor_container.parent.removeChild(this.cursor_container);
86
+ }
87
+ this.cursor_container.destroy({ children: true });
88
+ this.cursor_container = null;
89
+ }
90
+ // create new cursor container and add to ui container
91
+ this.cursor_container = new Container();
92
+ this.image_editor_context.ui_container.addChild(this.cursor_container);
93
+ // create cursor graphics
94
+ this.cursor_graphics = new Graphics();
95
+ this.cursor_container.addChild(this.cursor_graphics);
96
+ // draw initial cursor
97
+ this.update_cursor_appearance();
98
+ }
99
+ /**
100
+ * updates the appearance of the cursor.
101
+ */
102
+ update_cursor_appearance() {
103
+ if (!this.cursor_graphics)
104
+ return;
105
+ // clear previous graphics
106
+ this.cursor_graphics.clear();
107
+ // set color based on mode
108
+ const cursor_color = this.state.mode === "draw"
109
+ ? tinycolor(this.state.color).toString()
110
+ : 0xffffff;
111
+ // draw circle with current brush size
112
+ this.cursor_graphics
113
+ .circle(0, 0, this.state.brush_size * this.scale)
114
+ .stroke({
115
+ width: 1.5,
116
+ color: cursor_color,
117
+ alpha: 0.8
118
+ });
119
+ // add a small dot in the center for precision
120
+ this.cursor_graphics.circle(0, 0, 1).fill({
121
+ color: cursor_color,
122
+ alpha: 0.8
123
+ });
124
+ }
125
+ /**
126
+ * updates the position of the cursor.
127
+ * @param {FederatedPointerEvent} event - The pointer event.
128
+ */
129
+ update_cursor_position(event) {
130
+ if (!this.cursor_container)
131
+ return;
132
+ // get position in image coordinates
133
+ const local_pos = this.image_editor_context.image_container.toLocal(event.global);
134
+ // convert to ui coordinates
135
+ const ui_pos = this.image_editor_context.ui_container.toLocal(this.image_editor_context.image_container.toGlobal(local_pos));
136
+ // update cursor position
137
+ this.cursor_container.position.set(ui_pos.x, ui_pos.y);
138
+ }
139
+ /**
140
+ * checks if the cursor is over the image container.
141
+ * @param {FederatedPointerEvent} event - The pointer event.
142
+ */
143
+ check_cursor_over_image(event) {
144
+ // cancel any pending timeout
145
+ if (this.cursor_position_check_timeout !== null) {
146
+ window.clearTimeout(this.cursor_position_check_timeout);
147
+ this.cursor_position_check_timeout = null;
148
+ }
149
+ // get the image container bounds in global coordinates
150
+ const image_container = this.image_editor_context.image_container;
151
+ const bounds = image_container.getBounds();
152
+ // check if cursor is over image
153
+ const was_over_image = this.is_cursor_over_image;
154
+ this.is_cursor_over_image =
155
+ event.global.x >= bounds.x &&
156
+ event.global.x <= bounds.x + bounds.width &&
157
+ event.global.y >= bounds.y &&
158
+ event.global.y <= bounds.y + bounds.height;
159
+ // update visibility if state changed
160
+ if (was_over_image !== this.is_cursor_over_image) {
161
+ this.update_cursor_and_preview_visibility();
162
+ }
163
+ }
164
+ /**
165
+ * updates the size of the cursor.
166
+ */
167
+ update_cursor_size() {
168
+ this.update_cursor_appearance();
169
+ }
170
+ /**
171
+ * Updates whether brush or erase tool is active
172
+ */
173
+ set_active(is_active) {
174
+ this.is_brush_or_erase_active = is_active;
175
+ this.update_cursor_and_preview_visibility();
176
+ }
177
+ /**
178
+ * updates the visibility of the cursor.
179
+ */
180
+ update_cursor_visibility() {
181
+ if (this.cursor_container) {
182
+ this.cursor_container.visible =
183
+ this.is_cursor_over_image && this.is_brush_or_erase_active;
184
+ }
185
+ }
186
+ /**
187
+ * Shows or hides the brush preview.
188
+ * @param {boolean} show - Whether to show the preview.
189
+ */
190
+ preview_brush(show) {
191
+ this.is_preview_visible = show;
192
+ if (this.brush_preview_container) {
193
+ this.brush_preview_container.visible =
194
+ show && this.is_brush_or_erase_active;
195
+ }
196
+ if (show) {
197
+ // update preview appearance and position
198
+ this.update_brush_preview();
199
+ this.update_brush_preview_position();
200
+ }
201
+ }
202
+ /**
203
+ * initializes the brush preview.
204
+ */
205
+ initialize_brush_preview() {
206
+ // clean up existing preview if it exists
207
+ if (this.brush_preview_container) {
208
+ if (this.brush_preview_container.parent) {
209
+ this.brush_preview_container.parent.removeChild(this.brush_preview_container);
210
+ }
211
+ this.brush_preview_container.destroy({ children: true });
212
+ this.brush_preview_container = null;
213
+ }
214
+ // create new preview container and add to ui container
215
+ this.brush_preview_container = new Container();
216
+ this.image_editor_context.ui_container.addChild(this.brush_preview_container);
217
+ // create preview graphics
218
+ this.brush_preview_graphics = new Graphics();
219
+ this.brush_preview_container.addChild(this.brush_preview_graphics);
220
+ // set initial visibility
221
+ this.brush_preview_container.visible = false;
222
+ }
223
+ /**
224
+ * updates the brush preview appearance.
225
+ */
226
+ update_brush_preview() {
227
+ if (!this.brush_preview_graphics)
228
+ return;
229
+ // clear previous graphics
230
+ this.brush_preview_graphics.clear();
231
+ // draw brush preview based on current settings
232
+ const preview_size = this.state.brush_size * this.scale;
233
+ const preview_color = this.state.mode === "draw"
234
+ ? tinycolor(this.state.color).setAlpha(this.state.opacity).toString()
235
+ : 0xffffff;
236
+ // draw circle with current brush settings
237
+ this.brush_preview_graphics.circle(0, 0, preview_size).fill({
238
+ color: preview_color,
239
+ alpha: this.state.mode === "draw" ? this.state.opacity : 0.3
240
+ });
241
+ // add outline
242
+ this.brush_preview_graphics.circle(0, 0, preview_size + 1).stroke({
243
+ width: 1,
244
+ color: 0x000000,
245
+ alpha: 0.5
246
+ });
247
+ }
248
+ /**
249
+ * updates the position of the brush preview to center of canvas.
250
+ */
251
+ update_brush_preview_position() {
252
+ if (!this.brush_preview_container)
253
+ return;
254
+ // get the center of the image in global coordinates
255
+ const image_container = this.image_editor_context.image_container;
256
+ const center_x = image_container.width / 2;
257
+ const center_y = image_container.height / 2;
258
+ const global_pos = image_container.toGlobal({ x: center_x, y: center_y });
259
+ // convert to ui coordinates
260
+ const ui_pos = this.image_editor_context.ui_container.toLocal(global_pos);
261
+ // update preview position
262
+ this.brush_preview_container.position.set(ui_pos.x, ui_pos.y);
263
+ }
264
+ /**
265
+ * Called when the pointer enters the image container.
266
+ */
267
+ on_image_container_pointer_enter() {
268
+ this.is_cursor_over_image = true;
269
+ this.update_cursor_and_preview_visibility();
270
+ }
271
+ /**
272
+ * Called when the pointer leaves the image container.
273
+ */
274
+ on_image_container_pointer_leave() {
275
+ this.is_cursor_over_image = false;
276
+ this.update_cursor_and_preview_visibility();
277
+ }
278
+ /**
279
+ * Updates both cursor and preview visibility based on cursor position.
280
+ */
281
+ update_cursor_and_preview_visibility() {
282
+ this.update_cursor_visibility();
283
+ if (this.brush_preview_container) {
284
+ this.brush_preview_container.visible =
285
+ this.is_preview_visible && this.is_brush_or_erase_active;
286
+ }
287
+ }
288
+ /**
289
+ * Cleans up all cursor resources.
290
+ */
291
+ cleanup() {
292
+ // Reset active state
293
+ this.is_brush_or_erase_active = false;
294
+ // clean up cursor
295
+ if (this.cursor_container) {
296
+ if (this.cursor_container.parent) {
297
+ this.cursor_container.parent.removeChild(this.cursor_container);
298
+ }
299
+ this.cursor_container.destroy({ children: true });
300
+ this.cursor_container = null;
301
+ }
302
+ // clean up preview
303
+ if (this.brush_preview_container) {
304
+ if (this.brush_preview_container.parent) {
305
+ this.brush_preview_container.parent.removeChild(this.brush_preview_container);
306
+ }
307
+ this.brush_preview_container.destroy({ children: true });
308
+ this.brush_preview_container = null;
309
+ }
310
+ // clear timeout
311
+ if (this.cursor_position_check_timeout !== null) {
312
+ window.clearTimeout(this.cursor_position_check_timeout);
313
+ this.cursor_position_check_timeout = null;
314
+ }
315
+ }
316
+ /**
317
+ * Updates the brush state.
318
+ */
319
+ update_state(state, scale) {
320
+ this.state = state;
321
+ this.scale = scale;
322
+ this.update_cursor_appearance();
323
+ if (this.is_preview_visible) {
324
+ this.update_brush_preview();
325
+ }
326
+ }
327
+ }
@@ -0,0 +1,65 @@
1
+ import { Application } from "pixi.js";
2
+ import { type ImageEditorContext } from "../core/editor";
3
+ /**
4
+ * Class to handle texture operations for the brush tool.
5
+ * Simplified to work directly with layer textures.
6
+ */
7
+ export declare class BrushTextures {
8
+ private image_editor_context;
9
+ private app;
10
+ private stroke_texture;
11
+ private erase_texture;
12
+ private display_container;
13
+ private stroke_container;
14
+ private stroke_graphics;
15
+ private preview_sprite;
16
+ private erase_graphics;
17
+ private dimensions;
18
+ private is_new_stroke;
19
+ private current_opacity;
20
+ private current_mode;
21
+ constructor(image_editor_context: ImageEditorContext, app: Application);
22
+ /**
23
+ * Initializes textures needed for the brush tool.
24
+ */
25
+ initialize_textures(): void;
26
+ /**
27
+ * Reinitializes textures when needed (e.g., after resizing).
28
+ */
29
+ reinitialize(): void;
30
+ /**
31
+ * Cleans up texture resources.
32
+ */
33
+ cleanup_textures(): void;
34
+ /**
35
+ * Preserve the canvas state when starting a new stroke.
36
+ */
37
+ preserve_canvas_state(): void;
38
+ /**
39
+ * Resets the eraser mask.
40
+ */
41
+ reset_eraser_mask(): void;
42
+ /**
43
+ * Commits the current stroke to the active layer.
44
+ */
45
+ commit_stroke(): void;
46
+ /**
47
+ * Calculates the distance between two points.
48
+ */
49
+ private calculateDistance;
50
+ /**
51
+ * Draws a segment for the current stroke using a simple "stamp" approach.
52
+ */
53
+ draw_segment(from_x: number, from_y: number, to_x: number, to_y: number, size: number, color: string, opacity: number, mode: "draw" | "erase"): void;
54
+ /**
55
+ * Gets current dimensions of the texture.
56
+ */
57
+ get_dimensions(): {
58
+ width: number;
59
+ height: number;
60
+ };
61
+ /**
62
+ * Cleanup all resources.
63
+ */
64
+ cleanup(): void;
65
+ }