@gradio/imageeditor 0.19.0 → 0.20.1
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/CHANGELOG.md +32 -0
- package/Example.svelte +9 -3
- package/Index.svelte +23 -24
- package/InteractiveImageEditor.svelte +99 -61
- package/dist/Example.svelte +9 -3
- package/dist/Example.svelte.d.ts +4 -18
- package/dist/Index.svelte +23 -24
- package/dist/Index.svelte.d.ts +2 -19
- package/dist/InteractiveImageEditor.svelte +99 -61
- package/dist/InteractiveImageEditor.svelte.d.ts +15 -32
- package/dist/shared/Anchor.svelte +13 -11
- package/dist/shared/Anchor.svelte.d.ts +4 -19
- package/dist/shared/Controls.svelte +63 -39
- package/dist/shared/Controls.svelte.d.ts +13 -28
- package/dist/shared/IconButton.svelte +38 -17
- package/dist/shared/IconButton.svelte.d.ts +5 -19
- package/dist/shared/ImageEditor.svelte +235 -160
- package/dist/shared/ImageEditor.svelte.d.ts +55 -2
- package/dist/shared/Layers.svelte +43 -29
- package/dist/shared/Layers.svelte.d.ts +10 -25
- package/dist/shared/Resize.svelte +22 -16
- package/dist/shared/Resize.svelte.d.ts +6 -22
- package/dist/shared/SecondaryToolbar.svelte +34 -18
- package/dist/shared/SecondaryToolbar.svelte.d.ts +10 -25
- package/dist/shared/Toolbar.svelte +60 -76
- package/dist/shared/Toolbar.svelte.d.ts +9 -24
- package/dist/shared/brush/BrushOptions.svelte +49 -29
- package/dist/shared/brush/BrushOptions.svelte.d.ts +6 -21
- package/dist/shared/brush/BrushSize.svelte +12 -9
- package/dist/shared/brush/BrushSize.svelte.d.ts +5 -20
- package/dist/shared/brush/ColorField.svelte +21 -16
- package/dist/shared/brush/ColorField.svelte.d.ts +6 -22
- package/dist/shared/brush/ColorPicker.svelte +22 -16
- package/dist/shared/brush/ColorPicker.svelte.d.ts +4 -18
- package/dist/shared/brush/ColorSwatch.svelte +41 -21
- package/dist/shared/brush/ColorSwatch.svelte.d.ts +10 -24
- package/dist/shared/brush/brush.js +7 -8
- package/dist/shared/core/editor.d.ts +5 -0
- package/dist/shared/core/editor.js +43 -2
- package/dist/shared/resize/resize.d.ts +2 -0
- package/dist/shared/resize/resize.js +27 -18
- package/package.json +9 -9
- package/shared/Anchor.svelte +13 -11
- package/shared/Controls.svelte +63 -39
- package/shared/IconButton.svelte +38 -17
- package/shared/ImageEditor.svelte +235 -160
- package/shared/Layers.svelte +43 -29
- package/shared/Resize.svelte +22 -16
- package/shared/SecondaryToolbar.svelte +34 -18
- package/shared/Toolbar.svelte +60 -76
- package/shared/brush/BrushOptions.svelte +49 -29
- package/shared/brush/BrushSize.svelte +12 -9
- package/shared/brush/ColorField.svelte +21 -16
- package/shared/brush/ColorPicker.svelte +22 -16
- package/shared/brush/ColorSwatch.svelte +41 -21
- package/shared/brush/brush.ts +8 -10
- package/shared/core/editor.ts +49 -2
- package/shared/resize/resize.ts +28 -20
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
</script>
|
|
7
7
|
|
|
8
8
|
<script lang="ts">
|
|
9
|
-
import { onMount,
|
|
9
|
+
import { onMount, tick, type Snippet } from "svelte";
|
|
10
10
|
import { get } from "svelte/store";
|
|
11
11
|
import Toolbar, { type Tool as ToolbarTool } from "./Toolbar.svelte";
|
|
12
12
|
import { CropTool } from "./crop/crop";
|
|
@@ -30,49 +30,92 @@
|
|
|
30
30
|
import IconButton from "./IconButton.svelte";
|
|
31
31
|
|
|
32
32
|
const { drag, open_file_upload } = create_drag();
|
|
33
|
-
const dispatch = createEventDispatcher<{
|
|
34
|
-
clear?: never;
|
|
35
|
-
save: void;
|
|
36
|
-
change: void;
|
|
37
|
-
upload: void;
|
|
38
|
-
input: void;
|
|
39
|
-
download_error: string;
|
|
40
|
-
}>();
|
|
41
33
|
|
|
42
34
|
export const antialias = true;
|
|
43
35
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
36
|
+
let {
|
|
37
|
+
changeable = false,
|
|
38
|
+
sources = ["upload", "webcam", "clipboard"],
|
|
39
|
+
transforms = ["crop", "resize"],
|
|
40
|
+
canvas_size,
|
|
41
|
+
is_dragging = $bindable(false),
|
|
42
|
+
background_image = $bindable(false),
|
|
43
|
+
brush_options,
|
|
44
|
+
eraser_options,
|
|
45
|
+
fixed_canvas = false,
|
|
46
|
+
root,
|
|
47
|
+
i18n,
|
|
48
|
+
upload,
|
|
49
|
+
composite,
|
|
50
|
+
layers,
|
|
51
|
+
background,
|
|
52
|
+
border_region = 0,
|
|
53
|
+
layer_options,
|
|
54
|
+
current_tool = $bindable(),
|
|
55
|
+
webcam_options,
|
|
56
|
+
show_download_button = false,
|
|
57
|
+
theme_mode,
|
|
58
|
+
full_history = $bindable(null),
|
|
59
|
+
has_drawn = $bindable(false),
|
|
60
|
+
can_undo = $bindable(false),
|
|
61
|
+
onclear,
|
|
62
|
+
onsave,
|
|
63
|
+
onchange,
|
|
64
|
+
onupload,
|
|
65
|
+
oninput,
|
|
66
|
+
ondownload_error,
|
|
67
|
+
children
|
|
68
|
+
}: {
|
|
69
|
+
changeable?: boolean;
|
|
70
|
+
sources?: Source[];
|
|
71
|
+
transforms?: Transform[];
|
|
72
|
+
canvas_size: [number, number];
|
|
73
|
+
is_dragging?: boolean;
|
|
74
|
+
background_image?: boolean;
|
|
75
|
+
brush_options: Brush | false;
|
|
76
|
+
eraser_options: Eraser | false;
|
|
77
|
+
fixed_canvas?: boolean;
|
|
78
|
+
root: string;
|
|
79
|
+
i18n: I18nFormatter;
|
|
80
|
+
upload: Client["upload"];
|
|
81
|
+
composite: FileData | null;
|
|
82
|
+
layers: FileData[];
|
|
83
|
+
background: FileData | null;
|
|
84
|
+
border_region?: number;
|
|
85
|
+
layer_options: LayerOptions;
|
|
86
|
+
current_tool: ToolbarTool;
|
|
87
|
+
webcam_options: WebcamOptions;
|
|
88
|
+
show_download_button?: boolean;
|
|
89
|
+
theme_mode: "dark" | "light";
|
|
90
|
+
full_history?: CommandNode | null;
|
|
91
|
+
has_drawn?: boolean;
|
|
92
|
+
can_undo?: boolean;
|
|
93
|
+
onclear?: () => void;
|
|
94
|
+
onsave?: () => void;
|
|
95
|
+
onchange?: () => void;
|
|
96
|
+
onupload?: () => void;
|
|
97
|
+
oninput?: () => void;
|
|
98
|
+
ondownload_error?: (error: string) => void;
|
|
99
|
+
children?: Snippet;
|
|
100
|
+
} = $props();
|
|
66
101
|
|
|
67
102
|
let pixi_target: HTMLDivElement;
|
|
68
103
|
let pixi_target_crop: HTMLDivElement;
|
|
69
104
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
105
|
+
let layer_options_key: string | undefined | null = null;
|
|
106
|
+
$effect(() => {
|
|
107
|
+
if (!check_if_should_init()) return;
|
|
108
|
+
|
|
109
|
+
const next_layer_options_key = JSON.stringify(layer_options);
|
|
110
|
+
if (next_layer_options_key === layer_options_key) return;
|
|
111
|
+
|
|
112
|
+
layer_options_key = next_layer_options_key;
|
|
113
|
+
editor.set_layer_options(layer_options);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
$effect(() => {
|
|
117
|
+
refresh_tools();
|
|
118
|
+
});
|
|
76
119
|
|
|
77
120
|
function refresh_tools(): void {
|
|
78
121
|
if (!editor || !ready) return;
|
|
@@ -80,13 +123,14 @@
|
|
|
80
123
|
editor.set_subtool(current_subtool);
|
|
81
124
|
}
|
|
82
125
|
|
|
83
|
-
|
|
126
|
+
$effect(() => {
|
|
127
|
+
if (!(editor && ready && editor.layers)) return;
|
|
84
128
|
const current_layers = get(editor.layers);
|
|
85
129
|
|
|
86
130
|
if (current_layers.layers.length > 0 && !current_layers.active_layer) {
|
|
87
131
|
refresh_tools_for_layer_changes(current_layers);
|
|
88
132
|
}
|
|
89
|
-
}
|
|
133
|
+
});
|
|
90
134
|
|
|
91
135
|
/**
|
|
92
136
|
* Refreshes tools when layer state changes
|
|
@@ -115,8 +159,6 @@
|
|
|
115
159
|
return layer_options && editor && ready;
|
|
116
160
|
}
|
|
117
161
|
|
|
118
|
-
export let has_drawn = false;
|
|
119
|
-
|
|
120
162
|
/**
|
|
121
163
|
* Gets the image blobs from the editor
|
|
122
164
|
* @returns {Promise<ImageBlobs>} Object containing background, layers, and composite image blobs
|
|
@@ -176,8 +218,8 @@
|
|
|
176
218
|
crop.set_subtool("crop");
|
|
177
219
|
background_image = true;
|
|
178
220
|
zoom.set_zoom("fit");
|
|
179
|
-
|
|
180
|
-
|
|
221
|
+
onupload?.();
|
|
222
|
+
oninput?.();
|
|
181
223
|
} catch (error) {
|
|
182
224
|
console.error("Error adding image from URL:", error);
|
|
183
225
|
}
|
|
@@ -200,8 +242,8 @@
|
|
|
200
242
|
try {
|
|
201
243
|
await pending_bg;
|
|
202
244
|
await editor.add_layers_from_url(source.map((item) => item.url));
|
|
203
|
-
|
|
204
|
-
|
|
245
|
+
onchange?.();
|
|
246
|
+
oninput?.();
|
|
205
247
|
} catch (error) {
|
|
206
248
|
console.error("Error adding layer from URL:", error);
|
|
207
249
|
}
|
|
@@ -210,10 +252,10 @@
|
|
|
210
252
|
|
|
211
253
|
let brush: BrushTool;
|
|
212
254
|
let zoom: ZoomTool;
|
|
213
|
-
let zoom_level = 1;
|
|
214
|
-
let ready = false;
|
|
215
|
-
let mounted = false;
|
|
216
|
-
let min_zoom = true;
|
|
255
|
+
let zoom_level = $state(1);
|
|
256
|
+
let ready = $state(false);
|
|
257
|
+
let mounted = $state(false);
|
|
258
|
+
let min_zoom = $state(true);
|
|
217
259
|
|
|
218
260
|
let last_dimensions = { width: 0, height: 0 };
|
|
219
261
|
|
|
@@ -221,9 +263,11 @@
|
|
|
221
263
|
* Handles visibility changes and resets zoom if dimensions have changed
|
|
222
264
|
*/
|
|
223
265
|
async function handle_visibility_change(): Promise<void> {
|
|
224
|
-
if (!editor || !ready || !zoom) return;
|
|
266
|
+
if (!editor || !ready || !zoom || !pixi_target) return;
|
|
225
267
|
await tick();
|
|
226
268
|
|
|
269
|
+
if (!pixi_target) return;
|
|
270
|
+
|
|
227
271
|
const is_visible = pixi_target.offsetParent !== null;
|
|
228
272
|
|
|
229
273
|
if (is_visible) {
|
|
@@ -316,8 +360,7 @@
|
|
|
316
360
|
|
|
317
361
|
let crop: ImageEditor;
|
|
318
362
|
let crop_zoom: ZoomTool;
|
|
319
|
-
|
|
320
|
-
let can_redo = false;
|
|
363
|
+
let can_redo = $state(false);
|
|
321
364
|
async function init_image_editor(): Promise<void> {
|
|
322
365
|
brush = new BrushTool();
|
|
323
366
|
zoom = new ZoomTool();
|
|
@@ -382,8 +425,8 @@
|
|
|
382
425
|
});
|
|
383
426
|
|
|
384
427
|
editor.on("change", () => {
|
|
385
|
-
|
|
386
|
-
|
|
428
|
+
onchange?.();
|
|
429
|
+
oninput?.();
|
|
387
430
|
full_history = editor.command_manager.history;
|
|
388
431
|
});
|
|
389
432
|
|
|
@@ -403,23 +446,27 @@
|
|
|
403
446
|
refresh_tools();
|
|
404
447
|
}
|
|
405
448
|
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
449
|
+
$effect(() => {
|
|
450
|
+
if (
|
|
451
|
+
background == null &&
|
|
452
|
+
layers.length == 0 &&
|
|
453
|
+
composite == null &&
|
|
454
|
+
editor &&
|
|
455
|
+
ready
|
|
456
|
+
) {
|
|
457
|
+
editor.reset_canvas();
|
|
458
|
+
zoom.set_zoom("fit");
|
|
459
|
+
handle_tool_change({ tool: "image" });
|
|
460
|
+
background_image = false;
|
|
461
|
+
has_drawn = false;
|
|
462
|
+
}
|
|
463
|
+
});
|
|
419
464
|
|
|
420
|
-
|
|
421
|
-
current_subtool === "crop"
|
|
422
|
-
|
|
465
|
+
$effect(() => {
|
|
466
|
+
if (current_tool === "image" && current_subtool === "crop") {
|
|
467
|
+
crop_zoom.set_zoom("fit");
|
|
468
|
+
}
|
|
469
|
+
});
|
|
423
470
|
|
|
424
471
|
/**
|
|
425
472
|
* Handles file uploads
|
|
@@ -439,10 +486,15 @@
|
|
|
439
486
|
background_image = true;
|
|
440
487
|
zoom.set_zoom("fit");
|
|
441
488
|
handle_tool_change({ tool: "draw" });
|
|
442
|
-
|
|
489
|
+
onupload?.();
|
|
443
490
|
}
|
|
444
491
|
|
|
445
|
-
|
|
492
|
+
$effect(() => {
|
|
493
|
+
if (editor) {
|
|
494
|
+
background_image =
|
|
495
|
+
can_undo && editor.command_manager.contains("AddImage");
|
|
496
|
+
}
|
|
497
|
+
});
|
|
446
498
|
|
|
447
499
|
/**
|
|
448
500
|
* Handles tool change events
|
|
@@ -500,13 +552,13 @@
|
|
|
500
552
|
}
|
|
501
553
|
}
|
|
502
554
|
|
|
503
|
-
let eraser_size_visible = false;
|
|
504
|
-
let selected_color
|
|
505
|
-
let selected_size
|
|
506
|
-
let selected_opacity = 1;
|
|
507
|
-
let selected_eraser_size
|
|
555
|
+
let eraser_size_visible = $state(false);
|
|
556
|
+
let selected_color = $state<ColorInput | string>();
|
|
557
|
+
let selected_size = $state<number>();
|
|
558
|
+
let selected_opacity = $state(1);
|
|
559
|
+
let selected_eraser_size = $state<number>();
|
|
508
560
|
|
|
509
|
-
|
|
561
|
+
$effect(() => {
|
|
510
562
|
if (brush_options) {
|
|
511
563
|
update_brush_options();
|
|
512
564
|
}
|
|
@@ -514,7 +566,7 @@
|
|
|
514
566
|
if (eraser_options) {
|
|
515
567
|
update_eraser_options();
|
|
516
568
|
}
|
|
517
|
-
}
|
|
569
|
+
});
|
|
518
570
|
|
|
519
571
|
function update_brush_options(): void {
|
|
520
572
|
if (!brush_options) return;
|
|
@@ -551,51 +603,76 @@
|
|
|
551
603
|
options.default_size === "auto" ? 25 : options.default_size;
|
|
552
604
|
}
|
|
553
605
|
|
|
554
|
-
let brush_size_visible = false;
|
|
555
|
-
|
|
556
|
-
let brush_color_visible = false;
|
|
606
|
+
let brush_size_visible = $state(false);
|
|
607
|
+
|
|
608
|
+
let brush_color_visible = $state(false);
|
|
609
|
+
|
|
610
|
+
$effect(() => {
|
|
611
|
+
if (!brush) return;
|
|
612
|
+
brush.set_brush_color(
|
|
613
|
+
(() => {
|
|
614
|
+
let color_value: ColorInput = "black";
|
|
615
|
+
if (selected_color === "auto") {
|
|
616
|
+
if (!brush_options) return "black";
|
|
617
|
+
const default_color =
|
|
618
|
+
brush_options.colors.find((color) =>
|
|
619
|
+
Array.isArray(color)
|
|
620
|
+
? color[0] === brush_options.default_color
|
|
621
|
+
: color === brush_options.default_color
|
|
622
|
+
) || brush_options.colors[0];
|
|
623
|
+
|
|
624
|
+
color_value = Array.isArray(default_color)
|
|
625
|
+
? default_color[0]
|
|
626
|
+
: default_color;
|
|
627
|
+
} else {
|
|
628
|
+
color_value = selected_color ?? "black";
|
|
629
|
+
}
|
|
630
|
+
return color_value;
|
|
631
|
+
})()
|
|
632
|
+
);
|
|
633
|
+
});
|
|
557
634
|
|
|
558
|
-
|
|
559
|
-
(
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
const options = brush_options;
|
|
564
|
-
const default_color =
|
|
565
|
-
options.colors.find((color) =>
|
|
566
|
-
Array.isArray(color)
|
|
567
|
-
? color[0] === options.default_color
|
|
568
|
-
: color === options.default_color
|
|
569
|
-
) || options.colors[0];
|
|
635
|
+
$effect(() => {
|
|
636
|
+
brush?.set_brush_size(
|
|
637
|
+
typeof selected_size === "number" ? selected_size : 25
|
|
638
|
+
);
|
|
639
|
+
});
|
|
570
640
|
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
}
|
|
577
|
-
return color_value;
|
|
578
|
-
})()
|
|
579
|
-
);
|
|
641
|
+
$effect(() => {
|
|
642
|
+
brush?.set_eraser_size(
|
|
643
|
+
typeof selected_eraser_size === "number" ? selected_eraser_size : 25
|
|
644
|
+
);
|
|
645
|
+
});
|
|
580
646
|
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
647
|
+
let disable_click = $state(true);
|
|
648
|
+
$effect(() => {
|
|
649
|
+
disable_click =
|
|
650
|
+
current_tool !== "image" ||
|
|
651
|
+
(current_tool === "image" && background_image) ||
|
|
652
|
+
(current_tool === "image" && current_subtool === "webcam") ||
|
|
653
|
+
!sources.includes("upload");
|
|
654
|
+
});
|
|
584
655
|
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
)
|
|
656
|
+
let current_subtool = $state<Subtool | null>(null);
|
|
657
|
+
let preview = $state(false);
|
|
658
|
+
$effect(() => {
|
|
659
|
+
brush?.preview_brush(preview);
|
|
660
|
+
});
|
|
661
|
+
$effect(() => {
|
|
662
|
+
brush?.set_brush_opacity(selected_opacity);
|
|
663
|
+
});
|
|
588
664
|
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
(
|
|
592
|
-
(
|
|
593
|
-
|
|
665
|
+
function remove_image(): void {
|
|
666
|
+
onclear?.();
|
|
667
|
+
editor.reset_canvas();
|
|
668
|
+
handle_tool_change({ tool: "image" });
|
|
669
|
+
background_image = false;
|
|
670
|
+
has_drawn = false;
|
|
671
|
+
}
|
|
594
672
|
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
$: brush?.set_brush_opacity(selected_opacity);
|
|
673
|
+
export function handle_remove(): void {
|
|
674
|
+
remove_image();
|
|
675
|
+
}
|
|
599
676
|
|
|
600
677
|
function handle_zoom_change(zoom_level: number | "fit"): void {
|
|
601
678
|
zoom.set_zoom(zoom_level);
|
|
@@ -622,19 +699,23 @@
|
|
|
622
699
|
}
|
|
623
700
|
}
|
|
624
701
|
|
|
625
|
-
function handle_capture(
|
|
626
|
-
if (
|
|
627
|
-
handle_files(
|
|
702
|
+
function handle_capture(value: FileData | Blob | null): void {
|
|
703
|
+
if (value !== null) {
|
|
704
|
+
handle_files(value as Blob);
|
|
628
705
|
}
|
|
629
706
|
handle_subtool_change({ tool: current_tool, subtool: null });
|
|
630
707
|
}
|
|
631
708
|
|
|
632
709
|
function handle_save(): void {
|
|
633
|
-
|
|
710
|
+
onsave?.();
|
|
634
711
|
}
|
|
635
712
|
|
|
636
|
-
|
|
637
|
-
|
|
713
|
+
$effect(() => {
|
|
714
|
+
add_image_from_url(composite || background);
|
|
715
|
+
});
|
|
716
|
+
$effect(() => {
|
|
717
|
+
add_layers_from_url(layers);
|
|
718
|
+
});
|
|
638
719
|
|
|
639
720
|
async function handle_crop_confirm(): Promise<void> {
|
|
640
721
|
const { image } = await crop.get_crop_bounds();
|
|
@@ -645,8 +726,8 @@
|
|
|
645
726
|
resize: false
|
|
646
727
|
});
|
|
647
728
|
handle_subtool_change({ tool: "image", subtool: null });
|
|
648
|
-
|
|
649
|
-
|
|
729
|
+
onchange?.();
|
|
730
|
+
oninput?.();
|
|
650
731
|
}
|
|
651
732
|
|
|
652
733
|
async function handle_download(): Promise<void> {
|
|
@@ -654,7 +735,7 @@
|
|
|
654
735
|
|
|
655
736
|
const blob = blobs.composite;
|
|
656
737
|
if (!blob) {
|
|
657
|
-
|
|
738
|
+
ondownload_error?.("Unable to generate image to download.");
|
|
658
739
|
return;
|
|
659
740
|
}
|
|
660
741
|
const url = URL.createObjectURL(blob);
|
|
@@ -675,12 +756,13 @@
|
|
|
675
756
|
|
|
676
757
|
let old_background = background;
|
|
677
758
|
|
|
678
|
-
|
|
759
|
+
$effect(() => {
|
|
760
|
+
if (old_background === background) return;
|
|
679
761
|
handle_tool_change({ tool: "draw" });
|
|
680
762
|
handle_subtool_change({ tool: "draw", subtool: null });
|
|
681
763
|
current_tool = "draw";
|
|
682
764
|
old_background = background;
|
|
683
|
-
}
|
|
765
|
+
});
|
|
684
766
|
</script>
|
|
685
767
|
|
|
686
768
|
<div
|
|
@@ -691,7 +773,8 @@
|
|
|
691
773
|
on_drag_change: (dragging) => (is_dragging = dragging),
|
|
692
774
|
on_files: handle_files,
|
|
693
775
|
accepted_types: "image/*",
|
|
694
|
-
disable_click: disable_click
|
|
776
|
+
disable_click: disable_click,
|
|
777
|
+
ignore_click_selector: ".toolbar-wrap"
|
|
695
778
|
}}
|
|
696
779
|
aria-label={"Click to upload or drop files"}
|
|
697
780
|
aria-dropeffect="copy"
|
|
@@ -700,30 +783,24 @@
|
|
|
700
783
|
{#if current_subtool !== "crop"}
|
|
701
784
|
<Controls
|
|
702
785
|
{changeable}
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
786
|
+
onset_zoom={(zoom) => handle_zoom_change(zoom)}
|
|
787
|
+
onzoom_in={() => zoom_in_out("in")}
|
|
788
|
+
onzoom_out={() => zoom_in_out("out")}
|
|
706
789
|
{min_zoom}
|
|
707
790
|
current_zoom={zoom_level}
|
|
708
|
-
|
|
709
|
-
dispatch("clear");
|
|
710
|
-
editor.reset_canvas();
|
|
711
|
-
handle_tool_change({ tool: "image" });
|
|
712
|
-
background_image = false;
|
|
713
|
-
has_drawn = false;
|
|
714
|
-
}}
|
|
791
|
+
onremove_image={remove_image}
|
|
715
792
|
tool={current_tool}
|
|
716
793
|
can_save={true}
|
|
717
|
-
|
|
718
|
-
|
|
794
|
+
onsave={handle_save}
|
|
795
|
+
onpan={() => {
|
|
719
796
|
handle_tool_change({ tool: "pan" });
|
|
720
797
|
}}
|
|
721
798
|
enable_download={show_download_button}
|
|
722
|
-
|
|
799
|
+
ondownload={() => handle_download()}
|
|
723
800
|
{can_undo}
|
|
724
801
|
{can_redo}
|
|
725
|
-
|
|
726
|
-
|
|
802
|
+
onundo={handle_undo}
|
|
803
|
+
onredo={handle_redo}
|
|
727
804
|
/>
|
|
728
805
|
{/if}
|
|
729
806
|
|
|
@@ -732,8 +809,8 @@
|
|
|
732
809
|
{sources}
|
|
733
810
|
{transforms}
|
|
734
811
|
background={background_image}
|
|
735
|
-
|
|
736
|
-
|
|
812
|
+
ontool_change={(detail) => handle_tool_change(detail)}
|
|
813
|
+
onsubtool_change={(detail) => handle_subtool_change(detail)}
|
|
737
814
|
show_brush_size={brush_size_visible}
|
|
738
815
|
show_brush_color={brush_color_visible}
|
|
739
816
|
show_eraser_size={eraser_size_visible}
|
|
@@ -755,9 +832,7 @@
|
|
|
755
832
|
<Webcam
|
|
756
833
|
{upload}
|
|
757
834
|
{root}
|
|
758
|
-
|
|
759
|
-
on:error
|
|
760
|
-
on:drag
|
|
835
|
+
oncapture={handle_capture}
|
|
761
836
|
streaming={false}
|
|
762
837
|
mode="image"
|
|
763
838
|
include_audio={false}
|
|
@@ -773,23 +848,23 @@
|
|
|
773
848
|
<SecondaryToolbar
|
|
774
849
|
enable_additional_layers={layer_options.allow_additional_layers}
|
|
775
850
|
layers={editor.layers}
|
|
776
|
-
|
|
851
|
+
onnew_layer={() => {
|
|
777
852
|
editor.add_layer();
|
|
778
853
|
}}
|
|
779
|
-
|
|
780
|
-
editor.set_layer(
|
|
854
|
+
onchange_layer={(id) => {
|
|
855
|
+
editor.set_layer(id);
|
|
781
856
|
if (current_tool === "draw") {
|
|
782
857
|
handle_tool_change({ tool: "draw" });
|
|
783
858
|
}
|
|
784
859
|
}}
|
|
785
|
-
|
|
786
|
-
editor.move_layer(
|
|
860
|
+
onmove_layer={({ id, direction }) => {
|
|
861
|
+
editor.move_layer(id, direction);
|
|
787
862
|
}}
|
|
788
|
-
|
|
789
|
-
editor.delete_layer(
|
|
863
|
+
ondelete_layer={(id) => {
|
|
864
|
+
editor.delete_layer(id);
|
|
790
865
|
}}
|
|
791
|
-
|
|
792
|
-
editor.toggle_layer_visibility(
|
|
866
|
+
ontoggle_layer_visibility={(id) => {
|
|
867
|
+
editor.toggle_layer_visibility(id);
|
|
793
868
|
}}
|
|
794
869
|
/>
|
|
795
870
|
{/if}
|
|
@@ -820,7 +895,7 @@
|
|
|
820
895
|
/>
|
|
821
896
|
</div>
|
|
822
897
|
{/if}
|
|
823
|
-
|
|
898
|
+
{#if children}{@render children()}{/if}
|
|
824
899
|
</div>
|
|
825
900
|
|
|
826
901
|
<style>
|
|
@@ -1,6 +1,59 @@
|
|
|
1
1
|
export declare const EDITOR_KEY: unique symbol;
|
|
2
2
|
export type context_type = "bg" | "layers" | "crop" | "draw" | "erase";
|
|
3
|
+
import { type Snippet } from "svelte";
|
|
4
|
+
import { type Tool as ToolbarTool } from "./Toolbar.svelte";
|
|
5
|
+
import type { I18nFormatter } from "@gradio/utils";
|
|
6
|
+
import type { Client, FileData } from "@gradio/client";
|
|
7
|
+
import { type CommandNode } from "./core/commands";
|
|
3
8
|
import { ImageEditor } from "./core/editor";
|
|
4
|
-
|
|
5
|
-
type
|
|
9
|
+
import { type Brush, type Eraser } from "./brush/types";
|
|
10
|
+
import type { LayerOptions, Source, Transform, WebcamOptions } from "./types";
|
|
11
|
+
import { type ImageBlobs } from "./types";
|
|
12
|
+
type $$ComponentProps = {
|
|
13
|
+
changeable?: boolean;
|
|
14
|
+
sources?: Source[];
|
|
15
|
+
transforms?: Transform[];
|
|
16
|
+
canvas_size: [number, number];
|
|
17
|
+
is_dragging?: boolean;
|
|
18
|
+
background_image?: boolean;
|
|
19
|
+
brush_options: Brush | false;
|
|
20
|
+
eraser_options: Eraser | false;
|
|
21
|
+
fixed_canvas?: boolean;
|
|
22
|
+
root: string;
|
|
23
|
+
i18n: I18nFormatter;
|
|
24
|
+
upload: Client["upload"];
|
|
25
|
+
composite: FileData | null;
|
|
26
|
+
layers: FileData[];
|
|
27
|
+
background: FileData | null;
|
|
28
|
+
border_region?: number;
|
|
29
|
+
layer_options: LayerOptions;
|
|
30
|
+
current_tool: ToolbarTool;
|
|
31
|
+
webcam_options: WebcamOptions;
|
|
32
|
+
show_download_button?: boolean;
|
|
33
|
+
theme_mode: "dark" | "light";
|
|
34
|
+
full_history?: CommandNode | null;
|
|
35
|
+
has_drawn?: boolean;
|
|
36
|
+
can_undo?: boolean;
|
|
37
|
+
onclear?: () => void;
|
|
38
|
+
onsave?: () => void;
|
|
39
|
+
onchange?: () => void;
|
|
40
|
+
onupload?: () => void;
|
|
41
|
+
oninput?: () => void;
|
|
42
|
+
ondownload_error?: (error: string) => void;
|
|
43
|
+
children?: Snippet;
|
|
44
|
+
};
|
|
45
|
+
declare const ImageEditor: import("svelte").Component<$$ComponentProps, {
|
|
46
|
+
antialias: true;
|
|
47
|
+
get_blobs: () => Promise<ImageBlobs>;
|
|
48
|
+
add_image: (image: Blob | File) => void;
|
|
49
|
+
add_image_from_url: (source: string | {
|
|
50
|
+
url: string;
|
|
51
|
+
meta: {
|
|
52
|
+
_type: string;
|
|
53
|
+
};
|
|
54
|
+
} | any) => Promise<void>;
|
|
55
|
+
add_layers_from_url: (source: FileData[] | any) => Promise<void>;
|
|
56
|
+
handle_remove: () => void;
|
|
57
|
+
}, "current_tool" | "can_undo" | "is_dragging" | "background_image" | "full_history" | "has_drawn">;
|
|
58
|
+
type ImageEditor = ReturnType<typeof ImageEditor>;
|
|
6
59
|
export default ImageEditor;
|