@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,385 @@
1
+ import { Container, RenderTexture, Sprite, Graphics, Application } from "pixi.js";
2
+ import {} 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 class BrushTextures {
8
+ image_editor_context;
9
+ app;
10
+ // Only keep what we need
11
+ stroke_texture = null;
12
+ erase_texture = null;
13
+ display_container = null;
14
+ stroke_container = null;
15
+ stroke_graphics = null;
16
+ preview_sprite = null;
17
+ erase_graphics = null;
18
+ dimensions;
19
+ // Track if a new stroke is starting
20
+ is_new_stroke = true;
21
+ // Track the current drawing opacity
22
+ current_opacity = 1.0;
23
+ // Track current drawing mode
24
+ current_mode = "draw";
25
+ constructor(image_editor_context, app) {
26
+ this.image_editor_context = image_editor_context;
27
+ this.app = app;
28
+ this.dimensions = {
29
+ width: this.image_editor_context.image_container.width,
30
+ height: this.image_editor_context.image_container.height
31
+ };
32
+ }
33
+ /**
34
+ * Initializes textures needed for the brush tool.
35
+ */
36
+ initialize_textures() {
37
+ // Clean up any existing resources
38
+ this.cleanup_textures();
39
+ // Get dimensions from the image container
40
+ const local_bounds = this.image_editor_context.image_container.getLocalBounds();
41
+ this.dimensions = {
42
+ width: local_bounds.width,
43
+ height: local_bounds.height
44
+ };
45
+ // Create a texture for the current stroke preview
46
+ this.stroke_texture = RenderTexture.create({
47
+ width: this.dimensions.width,
48
+ height: this.dimensions.height,
49
+ resolution: window.devicePixelRatio || 1
50
+ });
51
+ // Create a texture for erasing
52
+ this.erase_texture = RenderTexture.create({
53
+ width: this.dimensions.width,
54
+ height: this.dimensions.height,
55
+ resolution: window.devicePixelRatio || 1
56
+ });
57
+ // Create a container to display preview
58
+ this.display_container = new Container();
59
+ // Get the active layer and add the display container to it
60
+ const active_layer = this.image_editor_context.layer_manager.get_active_layer();
61
+ if (active_layer) {
62
+ active_layer.addChild(this.display_container);
63
+ }
64
+ else {
65
+ this.image_editor_context.image_container.addChild(this.display_container);
66
+ }
67
+ // Create container for the stroke graphics
68
+ this.stroke_container = new Container();
69
+ this.stroke_graphics = new Graphics();
70
+ this.stroke_container.addChild(this.stroke_graphics);
71
+ // Create graphics for eraser mask
72
+ this.erase_graphics = new Graphics();
73
+ // Create a sprite for the preview of the current stroke
74
+ this.preview_sprite = new Sprite(this.stroke_texture);
75
+ // Start with the preview sprite invisible
76
+ this.preview_sprite.alpha = 0;
77
+ this.display_container.addChild(this.preview_sprite);
78
+ // Clear the stroke texture
79
+ const clear_container = new Container();
80
+ this.app.renderer.render(clear_container, {
81
+ renderTexture: this.stroke_texture
82
+ });
83
+ this.app.renderer.render(clear_container, {
84
+ renderTexture: this.erase_texture
85
+ });
86
+ clear_container.destroy();
87
+ // Reset drawing state
88
+ this.is_new_stroke = true;
89
+ this.current_opacity = 1.0;
90
+ }
91
+ /**
92
+ * Reinitializes textures when needed (e.g., after resizing).
93
+ */
94
+ reinitialize() {
95
+ if (this.image_editor_context.image_container.width !==
96
+ this.dimensions.width ||
97
+ this.image_editor_context.image_container.height !==
98
+ this.dimensions.height) {
99
+ this.initialize_textures();
100
+ }
101
+ }
102
+ /**
103
+ * Cleans up texture resources.
104
+ */
105
+ cleanup_textures() {
106
+ // Clean up stroke texture
107
+ if (this.stroke_texture) {
108
+ this.stroke_texture.destroy();
109
+ this.stroke_texture = null;
110
+ }
111
+ // Clean up erase texture
112
+ if (this.erase_texture) {
113
+ this.erase_texture.destroy();
114
+ this.erase_texture = null;
115
+ }
116
+ // Clean up display container
117
+ if (this.display_container) {
118
+ if (this.display_container.parent) {
119
+ this.display_container.parent.removeChild(this.display_container);
120
+ }
121
+ this.display_container.destroy({ children: true });
122
+ this.display_container = null;
123
+ }
124
+ // Nullify other references
125
+ this.stroke_container = null;
126
+ this.stroke_graphics = null;
127
+ this.preview_sprite = null;
128
+ this.erase_graphics = null;
129
+ }
130
+ /**
131
+ * Preserve the canvas state when starting a new stroke.
132
+ */
133
+ preserve_canvas_state() {
134
+ // Reset for a new stroke
135
+ this.is_new_stroke = true;
136
+ }
137
+ /**
138
+ * Resets the eraser mask.
139
+ */
140
+ reset_eraser_mask() {
141
+ if (!this.erase_graphics || !this.erase_texture)
142
+ return;
143
+ // Clear and reset the eraser graphics
144
+ this.erase_graphics.clear();
145
+ this.erase_graphics.beginFill(0xffffff, 1);
146
+ this.erase_graphics.drawRect(0, 0, this.dimensions.width, this.dimensions.height);
147
+ this.erase_graphics.endFill();
148
+ // Render the eraser graphics to the erase texture
149
+ this.app.renderer.render(this.erase_graphics, {
150
+ renderTexture: this.erase_texture
151
+ });
152
+ }
153
+ /**
154
+ * Commits the current stroke to the active layer.
155
+ */
156
+ commit_stroke() {
157
+ if (!this.stroke_texture || !this.preview_sprite || !this.stroke_graphics)
158
+ return;
159
+ // Hide the preview sprite
160
+ this.preview_sprite.visible = false;
161
+ // Get the active layer's texture
162
+ const active_layer = this.image_editor_context.layer_manager.get_active_layer();
163
+ if (!active_layer)
164
+ return;
165
+ // Get all layers to find the ID of the active layer
166
+ const layers = this.image_editor_context.layer_manager.get_layers();
167
+ const layer = layers.find((l) => l.container === active_layer);
168
+ if (!layer)
169
+ return;
170
+ // Get the active layer's draw texture
171
+ const layer_textures = this.image_editor_context.layer_manager.get_layer_textures(layer.id);
172
+ if (!layer_textures)
173
+ return;
174
+ // Save the current opacity for use in committing
175
+ const currentOpacity = this.current_opacity;
176
+ // Handle drawing or erasing
177
+ if (this.current_mode === "draw") {
178
+ // Drawing mode - simple composition
179
+ const temp_container = new Container();
180
+ // Add current layer texture as base
181
+ const base_sprite = new Sprite(layer_textures.draw);
182
+ temp_container.addChild(base_sprite);
183
+ // Add the current stroke with proper opacity
184
+ const stroke_sprite = new Sprite(this.stroke_texture);
185
+ stroke_sprite.alpha = currentOpacity;
186
+ temp_container.addChild(stroke_sprite);
187
+ // Render the composited result directly to the layer texture
188
+ this.app.renderer.render(temp_container, {
189
+ renderTexture: layer_textures.draw
190
+ });
191
+ // Clean up
192
+ temp_container.destroy({ children: true });
193
+ }
194
+ else {
195
+ // Erasing mode - use proper masking with setMask
196
+ if (!this.stroke_texture)
197
+ return;
198
+ // Create a container for the erase operation
199
+ const erase_container = new Container();
200
+ // Add the current layer content
201
+ const content_sprite = new Sprite(layer_textures.draw);
202
+ erase_container.addChild(content_sprite);
203
+ // Create the mask sprite from our stroke texture
204
+ const mask_sprite = new Sprite(this.stroke_texture);
205
+ // Apply the mask to the container using setMask with inverse: true
206
+ // This will only show content where the mask is NOT (inverse: true)
207
+ erase_container.setMask({ mask: mask_sprite, inverse: true });
208
+ // Render the masked content back to layer texture
209
+ this.app.renderer.render(erase_container, {
210
+ renderTexture: layer_textures.draw
211
+ });
212
+ // Clean up
213
+ erase_container.destroy({ children: true });
214
+ }
215
+ // Clear the stroke graphics and texture for the next stroke
216
+ if (this.stroke_graphics) {
217
+ this.stroke_graphics.clear();
218
+ }
219
+ const clear_container = new Container();
220
+ this.app.renderer.render(clear_container, {
221
+ renderTexture: this.stroke_texture
222
+ });
223
+ clear_container.destroy();
224
+ // Reset state for the next stroke
225
+ this.is_new_stroke = true;
226
+ }
227
+ /**
228
+ * Calculates the distance between two points.
229
+ */
230
+ calculateDistance(x1, y1, x2, y2) {
231
+ return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
232
+ }
233
+ /**
234
+ * Draws a segment for the current stroke using a simple "stamp" approach.
235
+ */
236
+ draw_segment(from_x, from_y, to_x, to_y, size, color, opacity, mode) {
237
+ if (!this.stroke_graphics ||
238
+ !this.stroke_texture ||
239
+ !this.stroke_container ||
240
+ !this.preview_sprite)
241
+ return;
242
+ // Store the current mode and opacity
243
+ this.current_mode = mode;
244
+ this.current_opacity =
245
+ mode === "draw" ? Math.min(Math.max(opacity, 0), 1) : 0.5;
246
+ // Apply scale to brush size for consistent rendering
247
+ const scaled_size = size;
248
+ // For new strokes, clear the graphics and texture completely
249
+ if (this.is_new_stroke) {
250
+ // Clean up for a new stroke
251
+ this.stroke_graphics.clear();
252
+ // Clear the stroke texture
253
+ const clear_container = new Container();
254
+ this.app.renderer.render(clear_container, {
255
+ renderTexture: this.stroke_texture
256
+ });
257
+ clear_container.destroy();
258
+ this.is_new_stroke = false;
259
+ }
260
+ // Set fill color and opacity for drawing
261
+ if (mode === "draw") {
262
+ // For drawing, use the specified color, but always full opacity in the graphics
263
+ // We need to convert the color string to a number
264
+ let colorValue = 0xffffff; // Default to white
265
+ try {
266
+ if (color.startsWith("#")) {
267
+ colorValue = parseInt(color.replace("#", "0x"), 16);
268
+ }
269
+ }
270
+ catch (e) {
271
+ // Default to white if there's an error
272
+ colorValue = 0xffffff;
273
+ }
274
+ this.stroke_graphics.setFillStyle({
275
+ color: colorValue,
276
+ alpha: 1.0
277
+ });
278
+ }
279
+ else {
280
+ // For erasing, always use white
281
+ this.stroke_graphics.setFillStyle({
282
+ color: 0xffffff,
283
+ alpha: 1.0
284
+ });
285
+ }
286
+ // Calculate the distance between the points
287
+ const distance = this.calculateDistance(from_x, from_y, to_x, to_y);
288
+ // If the points are the same, just draw a single circle
289
+ if (distance < 0.1) {
290
+ // Draw a circle at the point - use scaled_size as RADIUS
291
+ this.stroke_graphics.circle(from_x, from_y, scaled_size).fill();
292
+ }
293
+ else {
294
+ // Calculate how many circles to draw along the path
295
+ // Adaptive spacing that balances quality and performance
296
+ const spacing = Math.max(scaled_size / 3, 2);
297
+ const steps = Math.max(Math.ceil(distance / spacing), 2);
298
+ // Draw a circle at each point along the path
299
+ for (let i = 0; i < steps; i++) {
300
+ const t = i / (steps - 1);
301
+ const x = from_x + (to_x - from_x) * t;
302
+ const y = from_y + (to_y - from_y) * t;
303
+ // Create a circle at this point - use scaled_size as RADIUS
304
+ this.stroke_graphics.circle(x, y, scaled_size).fill();
305
+ }
306
+ }
307
+ // End the fill after all circles are drawn
308
+ this.stroke_graphics.endFill();
309
+ // Render the stroke to the texture
310
+ this.app.renderer.render(this.stroke_container, {
311
+ renderTexture: this.stroke_texture
312
+ });
313
+ // Update the preview based on mode
314
+ if (mode === "draw") {
315
+ // For drawing, show the stroke directly with proper opacity
316
+ this.preview_sprite.texture = this.stroke_texture;
317
+ this.preview_sprite.alpha = this.current_opacity;
318
+ // Set tint to white (no tint) instead of trying to tint the texture
319
+ this.preview_sprite.tint = 0xffffff;
320
+ }
321
+ else {
322
+ // For erasing, create a preview that shows what will be erased
323
+ // Get the active layer's texture for preview
324
+ const active_layer = this.image_editor_context.layer_manager.get_active_layer();
325
+ if (!active_layer)
326
+ return;
327
+ const layers = this.image_editor_context.layer_manager.get_layers();
328
+ const layer = layers.find((l) => l.container === active_layer);
329
+ if (!layer)
330
+ return;
331
+ const layer_textures = this.image_editor_context.layer_manager.get_layer_textures(layer.id);
332
+ if (!layer_textures)
333
+ return;
334
+ // Create a temporary texture for the preview
335
+ const preview_texture = RenderTexture.create({
336
+ width: this.dimensions.width,
337
+ height: this.dimensions.height,
338
+ resolution: window.devicePixelRatio || 1
339
+ });
340
+ // First, create a copy of the current layer content
341
+ const base_container = new Container();
342
+ const content_sprite = new Sprite(layer_textures.draw);
343
+ base_container.addChild(content_sprite);
344
+ this.app.renderer.render(base_container, {
345
+ renderTexture: preview_texture
346
+ });
347
+ base_container.destroy({ children: true });
348
+ // Create a container for the eraser preview with red overlay
349
+ const preview_container = new Container();
350
+ // Add our current stroke as the content
351
+ const mask_sprite = new Sprite(this.stroke_texture);
352
+ // Add a red overlay to show what's being erased
353
+ const overlay = new Graphics();
354
+ overlay.setFillStyle({ color: 0xffffff, alpha: 0.5 });
355
+ overlay.rect(0, 0, this.dimensions.width, this.dimensions.height).fill();
356
+ // Use setMask with inverse: false to only show overlay where the stroke is
357
+ // We want to show the red overlay ONLY where the stroke will erase
358
+ overlay.setMask({ mask: mask_sprite, inverse: false });
359
+ preview_container.addChild(overlay);
360
+ // Render the overlay on top of the base content
361
+ this.app.renderer.render(preview_container, {
362
+ renderTexture: preview_texture
363
+ });
364
+ // Update the preview sprite with our preview texture
365
+ this.preview_sprite.texture = preview_texture;
366
+ this.preview_sprite.alpha = 1.0;
367
+ // Clean up
368
+ preview_container.destroy({ children: true });
369
+ preview_texture.destroy();
370
+ }
371
+ this.preview_sprite.visible = true;
372
+ }
373
+ /**
374
+ * Gets current dimensions of the texture.
375
+ */
376
+ get_dimensions() {
377
+ return this.dimensions;
378
+ }
379
+ /**
380
+ * Cleanup all resources.
381
+ */
382
+ cleanup() {
383
+ this.cleanup_textures();
384
+ }
385
+ }
@@ -0,0 +1,32 @@
1
+ import { Container, Sprite, Graphics } from "pixi.js";
2
+ /**
3
+ * Sets the cursor style for a single PIXI object.
4
+ * @param child - The PIXI object to set the cursor for.
5
+ * @param cursor - The cursor style to set.
6
+ */
7
+ export declare function set_cursor(child: Container | Sprite | Graphics, cursor: "unset" | "none"): void;
8
+ /**
9
+ * Recursively sets the cursor style for PIXI objects.
10
+ * @param children - The PIXI objects to set the cursor for.
11
+ * @param cursor - The cursor style to set.
12
+ */
13
+ export declare function recurse_set_cursor(children: (Container | Sprite | Graphics)[], cursor: "unset" | "none"): void;
14
+ /**
15
+ * Safely removes a child from its parent.
16
+ * @param child - The child to remove.
17
+ */
18
+ export declare function safe_remove_child(child: Container | Sprite | Graphics | null): void;
19
+ /**
20
+ * Safely destroys a PIXI object and nullifies it.
21
+ * @param obj - The object to destroy.
22
+ * @returns null to assist with nullifying the reference.
23
+ */
24
+ export declare function safe_destroy<T extends {
25
+ destroy: (options?: any) => void;
26
+ }>(obj: T | null): null;
27
+ /**
28
+ * Clears a timeout safely and nullifies the reference.
29
+ * @param timeout - The timeout to clear.
30
+ * @returns null to assist with nullifying the reference.
31
+ */
32
+ export declare function clear_timeout(timeout: number | null): null;
@@ -0,0 +1,59 @@
1
+ import { Container, Sprite, Graphics } from "pixi.js";
2
+ /**
3
+ * Sets the cursor style for a single PIXI object.
4
+ * @param child - The PIXI object to set the cursor for.
5
+ * @param cursor - The cursor style to set.
6
+ */
7
+ export function set_cursor(child, cursor) {
8
+ if (child instanceof Container) {
9
+ child.cursor = cursor;
10
+ }
11
+ else if ("cursor" in child) {
12
+ child.cursor = cursor;
13
+ }
14
+ }
15
+ /**
16
+ * Recursively sets the cursor style for PIXI objects.
17
+ * @param children - The PIXI objects to set the cursor for.
18
+ * @param cursor - The cursor style to set.
19
+ */
20
+ export function recurse_set_cursor(children, cursor) {
21
+ for (const child of children) {
22
+ set_cursor(child, cursor);
23
+ if (child instanceof Container && child.children.length > 0) {
24
+ recurse_set_cursor(child.children, cursor);
25
+ }
26
+ }
27
+ }
28
+ /**
29
+ * Safely removes a child from its parent.
30
+ * @param child - The child to remove.
31
+ */
32
+ export function safe_remove_child(child) {
33
+ if (child && child.parent) {
34
+ child.parent.removeChild(child);
35
+ }
36
+ }
37
+ /**
38
+ * Safely destroys a PIXI object and nullifies it.
39
+ * @param obj - The object to destroy.
40
+ * @returns null to assist with nullifying the reference.
41
+ */
42
+ export function safe_destroy(obj) {
43
+ if (obj) {
44
+ safe_remove_child(obj);
45
+ obj.destroy({ children: true });
46
+ }
47
+ return null;
48
+ }
49
+ /**
50
+ * Clears a timeout safely and nullifies the reference.
51
+ * @param timeout - The timeout to clear.
52
+ * @returns null to assist with nullifying the reference.
53
+ */
54
+ export function clear_timeout(timeout) {
55
+ if (timeout !== null) {
56
+ window.clearTimeout(timeout);
57
+ }
58
+ return null;
59
+ }
@@ -0,0 +1,152 @@
1
+ import { type ImageEditorContext, type Tool } from "../core/editor";
2
+ import { type Tool as ToolbarTool, type Subtool } from "../Toolbar.svelte";
3
+ import type { ColorInput } from "tinycolor2";
4
+ /**
5
+ * BrushTool class implements the Tool interface for drawing and erasing.
6
+ * @class
7
+ * @implements {Tool}
8
+ */
9
+ export declare class BrushTool implements Tool {
10
+ /**
11
+ * The name of the tool.
12
+ * @type {string}
13
+ */
14
+ name: "brush";
15
+ /**
16
+ * The context of the image editor.
17
+ * @private
18
+ */
19
+ private image_editor_context;
20
+ /**
21
+ * The current tool selected in the toolbar.
22
+ * @private
23
+ */
24
+ private current_tool;
25
+ /**
26
+ * The current subtool selected in the toolbar.
27
+ * @private
28
+ */
29
+ private current_subtool;
30
+ /**
31
+ * The state of the brush tool.
32
+ * @private
33
+ */
34
+ private state;
35
+ /**
36
+ * Size settings for brush and eraser
37
+ * @private
38
+ */
39
+ private brush_size;
40
+ private eraser_size;
41
+ /**
42
+ * Drawing state
43
+ * @private
44
+ */
45
+ private is_drawing;
46
+ private last_x;
47
+ private last_y;
48
+ private scale;
49
+ /**
50
+ * Event listeners
51
+ * @private
52
+ */
53
+ private _bound_pointer_down;
54
+ private _bound_pointer_move;
55
+ private _bound_pointer_up;
56
+ private event_callbacks;
57
+ /**
58
+ * Utility modules
59
+ * @private
60
+ */
61
+ private brush_cursor;
62
+ private brush_textures;
63
+ /**
64
+ * Sets up the brush tool with the given context, tool, and subtool.
65
+ * @param {ImageEditorContext} context - The image editor context.
66
+ * @param {ToolbarTool} tool - The tool from the toolbar.
67
+ * @param {Subtool} subtool - The subtool from the toolbar.
68
+ * @returns {Promise<void>}
69
+ */
70
+ setup(context: ImageEditorContext, tool: ToolbarTool, subtool: Subtool): Promise<void>;
71
+ /**
72
+ * Handles cursor styles for the brush tool.
73
+ * @param {ToolbarTool} tool - The current tool.
74
+ * @private
75
+ */
76
+ private handle_cursors;
77
+ /**
78
+ * Sets the current tool and subtool.
79
+ * @param {ToolbarTool} tool - The current tool.
80
+ * @param {Subtool} subtool - The current subtool.
81
+ */
82
+ set_tool(tool: ToolbarTool, subtool: Subtool): void;
83
+ /**
84
+ * Commits any pending changes to the canvas.
85
+ * @private
86
+ */
87
+ private commit_pending_changes;
88
+ /**
89
+ * Called when the user presses the mouse button.
90
+ * @param {FederatedPointerEvent} event - The pointer event.
91
+ * @private
92
+ */
93
+ private on_pointer_down;
94
+ /**
95
+ * Called when the user moves the mouse while drawing.
96
+ * @param {FederatedPointerEvent} event - The pointer event.
97
+ * @private
98
+ */
99
+ private on_pointer_move;
100
+ /**
101
+ * Called when the user releases the mouse button.
102
+ * @private
103
+ */
104
+ private on_pointer_up;
105
+ /**
106
+ * Sets up event listeners for drawing.
107
+ * @private
108
+ */
109
+ private setup_event_listeners;
110
+ /**
111
+ * Cleans up event listeners.
112
+ * @private
113
+ */
114
+ private cleanup_event_listeners;
115
+ /**
116
+ * Sets the brush size.
117
+ * @param {number} size - The new brush size.
118
+ */
119
+ set_brush_size(size: number): void;
120
+ /**
121
+ * Sets the brush color.
122
+ * @param {string|ColorInput} color - The new brush color.
123
+ */
124
+ set_brush_color(color: string | ColorInput): void;
125
+ /**
126
+ * Sets the brush opacity.
127
+ * @param {number} opacity - The new brush opacity.
128
+ */
129
+ set_brush_opacity(opacity: number): void;
130
+ /**
131
+ * Sets the eraser size.
132
+ * @param {number} size - The new eraser size.
133
+ */
134
+ set_eraser_size(size: number): void;
135
+ /**
136
+ * Gets the current size based on mode (brush or eraser).
137
+ * @returns {number} The current size.
138
+ */
139
+ get_current_size(): number;
140
+ /**
141
+ * Shows or hides the brush preview.
142
+ * @param {boolean} show - Whether to show the preview.
143
+ */
144
+ preview_brush(show: boolean): void;
145
+ /**
146
+ * Cleans up resources used by the brush tool.
147
+ */
148
+ cleanup(): void;
149
+ on<T extends string>(event: T, callback: () => void): void;
150
+ off<T extends string>(event: T, callback: () => void): void;
151
+ private notify;
152
+ }