@gradio/imageeditor 0.13.0 → 0.14.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 +33 -0
- package/ImageEditor.stories.svelte +9 -1
- package/Index.svelte +13 -1
- package/InteractiveImageEditor.svelte +10 -1
- package/README.md +2 -0
- package/dist/Index.svelte +6 -0
- package/dist/Index.svelte.d.ts +9 -1
- package/dist/InteractiveImageEditor.svelte +7 -0
- package/dist/InteractiveImageEditor.svelte.d.ts +5 -1
- package/dist/shared/Controls.svelte +13 -1
- package/dist/shared/Controls.svelte.d.ts +2 -0
- package/dist/shared/ImageEditor.svelte +29 -3
- package/dist/shared/ImageEditor.svelte.d.ts +5 -2
- package/dist/shared/Layers.svelte +29 -2
- package/dist/shared/Layers.svelte.d.ts +2 -0
- package/dist/shared/SecondaryToolbar.svelte +1 -0
- package/dist/shared/SecondaryToolbar.svelte.d.ts +2 -0
- package/dist/shared/brush/brush-textures.d.ts +0 -6
- package/dist/shared/brush/brush-textures.js +0 -19
- package/dist/shared/brush/brush.js +3 -2
- package/dist/shared/core/editor.d.ts +15 -6
- package/dist/shared/core/editor.js +76 -33
- package/dist/shared/image/image.js +2 -4
- package/dist/shared/types.d.ts +4 -0
- package/dist/shared/zoom/zoom.js +1 -1
- package/package.json +9 -9
- package/shared/Controls.svelte +14 -40
- package/shared/ImageEditor.svelte +33 -4
- package/shared/Layers.svelte +36 -3
- package/shared/SecondaryToolbar.svelte +7 -1
- package/shared/brush/brush-textures.ts +0 -23
- package/shared/brush/brush.ts +6 -2
- package/shared/core/editor.ts +102 -44
- package/shared/image/image.ts +2 -4
- package/shared/types.ts +5 -0
- package/shared/zoom/zoom.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,38 @@
|
|
|
1
1
|
# @gradio/imageeditor
|
|
2
2
|
|
|
3
|
+
## 0.14.1
|
|
4
|
+
|
|
5
|
+
### Dependency updates
|
|
6
|
+
|
|
7
|
+
- @gradio/statustracker@0.10.9
|
|
8
|
+
- @gradio/atoms@0.15.2
|
|
9
|
+
- @gradio/client@1.14.2
|
|
10
|
+
- @gradio/utils@0.10.2
|
|
11
|
+
- @gradio/upload@0.16.2
|
|
12
|
+
- @gradio/image@0.22.2
|
|
13
|
+
|
|
14
|
+
## 0.14.0
|
|
15
|
+
|
|
16
|
+
### Features
|
|
17
|
+
|
|
18
|
+
- [#10981](https://github.com/gradio-app/gradio/pull/10981) [`0db230f`](https://github.com/gradio-app/gradio/commit/0db230f5c2f19d9b3b455adb1b30ed9374ae1791) - allow users to change the visibility of layers in the image editor. Thanks @pngwn!
|
|
19
|
+
|
|
20
|
+
### Fixes
|
|
21
|
+
|
|
22
|
+
- [#10999](https://github.com/gradio-app/gradio/pull/10999) [`8c70819`](https://github.com/gradio-app/gradio/commit/8c70819f87027b75e44f49a13050ae2c3e8b3580) - implement download button for the ImageEditor. Thanks @pngwn!
|
|
23
|
+
- [#10997](https://github.com/gradio-app/gradio/pull/10997) [`45d5840`](https://github.com/gradio-app/gradio/commit/45d5840fb265328f3aa0c050ce9c6b87ae7dbbc5) - When custom layers are provided to the ImageEditor, always default to the first layer. Thanks @pngwn!
|
|
24
|
+
- [#10979](https://github.com/gradio-app/gradio/pull/10979) [`975feee`](https://github.com/gradio-app/gradio/commit/975feee3925e5b65e52ae00da5c5066d8889ae6a) - improve webcam options for the ImageEditor. Thanks @pngwn!
|
|
25
|
+
- [#10995](https://github.com/gradio-app/gradio/pull/10995) [`fc59815`](https://github.com/gradio-app/gradio/commit/fc598151aa9c77a84f6e7eaf9bcc0cae6ba49369) - ensure the image editor background respects the theme mode. Thanks @pngwn!
|
|
26
|
+
- [#10994](https://github.com/gradio-app/gradio/pull/10994) [`714015a`](https://github.com/gradio-app/gradio/commit/714015a1868168721ae79d6b5bc10fbc5bbb4290) - ensure images uploaded to the ImageEditor correctly initialise the canvas dimensions. Thanks @pngwn!
|
|
27
|
+
|
|
28
|
+
### Dependency updates
|
|
29
|
+
|
|
30
|
+
- @gradio/upload@0.16.1
|
|
31
|
+
- @gradio/atoms@0.15.1
|
|
32
|
+
- @gradio/statustracker@0.10.8
|
|
33
|
+
- @gradio/icons@0.12.0
|
|
34
|
+
- @gradio/image@0.22.1
|
|
35
|
+
|
|
3
36
|
## 0.13.0
|
|
4
37
|
|
|
5
38
|
### Features
|
|
@@ -51,6 +51,10 @@
|
|
|
51
51
|
},
|
|
52
52
|
eraser: {
|
|
53
53
|
default_size: "auto"
|
|
54
|
+
},
|
|
55
|
+
webcam_options: {
|
|
56
|
+
mirror: true,
|
|
57
|
+
constraints: null
|
|
54
58
|
}
|
|
55
59
|
}}
|
|
56
60
|
/>
|
|
@@ -133,6 +137,10 @@
|
|
|
133
137
|
interactive: false,
|
|
134
138
|
label: "Image Editor",
|
|
135
139
|
show_label: true,
|
|
136
|
-
canvas_size: [800, 600]
|
|
140
|
+
canvas_size: [800, 600],
|
|
141
|
+
webcam_options: {
|
|
142
|
+
mirror: true,
|
|
143
|
+
constraints: null
|
|
144
|
+
}
|
|
137
145
|
}}
|
|
138
146
|
/>
|
package/Index.svelte
CHANGED
|
@@ -13,7 +13,13 @@
|
|
|
13
13
|
import { StatusTracker } from "@gradio/statustracker";
|
|
14
14
|
import type { LoadingStatus } from "@gradio/statustracker";
|
|
15
15
|
import { tick } from "svelte";
|
|
16
|
-
import type {
|
|
16
|
+
import type {
|
|
17
|
+
LayerOptions,
|
|
18
|
+
Transform,
|
|
19
|
+
Source,
|
|
20
|
+
WebcamOptions
|
|
21
|
+
} from "./shared/types";
|
|
22
|
+
|
|
17
23
|
export let elem_id = "";
|
|
18
24
|
export let elem_classes: string[] = [];
|
|
19
25
|
export let visible = true;
|
|
@@ -66,6 +72,8 @@
|
|
|
66
72
|
clear_status: LoadingStatus;
|
|
67
73
|
}>;
|
|
68
74
|
export let border_region = 0;
|
|
75
|
+
export let webcam_options: WebcamOptions;
|
|
76
|
+
export let theme_mode: "dark" | "light";
|
|
69
77
|
|
|
70
78
|
let editor_instance: InteractiveImageEditor;
|
|
71
79
|
let image_id: null | string = null;
|
|
@@ -235,6 +243,10 @@
|
|
|
235
243
|
upload={(...args) => gradio.client.upload(...args)}
|
|
236
244
|
{placeholder}
|
|
237
245
|
{full_history}
|
|
246
|
+
{webcam_options}
|
|
247
|
+
{show_download_button}
|
|
248
|
+
{theme_mode}
|
|
249
|
+
on:download_error={(e) => gradio.dispatch("error", e.detail)}
|
|
238
250
|
></InteractiveImageEditor>
|
|
239
251
|
</Block>
|
|
240
252
|
{/if}
|
|
@@ -31,8 +31,10 @@
|
|
|
31
31
|
import {
|
|
32
32
|
type LayerOptions,
|
|
33
33
|
type Transform,
|
|
34
|
-
type Source
|
|
34
|
+
type Source,
|
|
35
|
+
type WebcamOptions
|
|
35
36
|
} from "./shared/types";
|
|
37
|
+
|
|
36
38
|
export let brush: IBrush;
|
|
37
39
|
export let eraser: Eraser;
|
|
38
40
|
export let sources: Source[];
|
|
@@ -41,6 +43,7 @@
|
|
|
41
43
|
export let label: string | undefined = undefined;
|
|
42
44
|
export let show_label: boolean;
|
|
43
45
|
export let changeable = false;
|
|
46
|
+
export let theme_mode: "dark" | "light";
|
|
44
47
|
|
|
45
48
|
export let layers: FileData[];
|
|
46
49
|
export let composite: FileData | null;
|
|
@@ -58,6 +61,8 @@
|
|
|
58
61
|
export let placeholder: string | undefined = undefined;
|
|
59
62
|
export let border_region: number;
|
|
60
63
|
export let full_history: CommandNode | null = null;
|
|
64
|
+
export let webcam_options: WebcamOptions;
|
|
65
|
+
export let show_download_button = false;
|
|
61
66
|
|
|
62
67
|
const dispatch = createEventDispatcher<{
|
|
63
68
|
clear?: never;
|
|
@@ -220,6 +225,7 @@
|
|
|
220
225
|
on:save
|
|
221
226
|
on:change={handle_change}
|
|
222
227
|
on:clear={() => dispatch("clear")}
|
|
228
|
+
on:download_error
|
|
223
229
|
{sources}
|
|
224
230
|
{full_history}
|
|
225
231
|
bind:background_image
|
|
@@ -234,6 +240,9 @@
|
|
|
234
240
|
{upload}
|
|
235
241
|
bind:is_dragging
|
|
236
242
|
bind:has_drawn
|
|
243
|
+
{webcam_options}
|
|
244
|
+
{show_download_button}
|
|
245
|
+
{theme_mode}
|
|
237
246
|
>
|
|
238
247
|
{#if !background_image && current_tool === "image" && !has_drawn}
|
|
239
248
|
<div class="empty wrap">
|
package/README.md
CHANGED
package/dist/Index.svelte
CHANGED
|
@@ -42,6 +42,8 @@ export let show_fullscreen_button = true;
|
|
|
42
42
|
export let full_history = null;
|
|
43
43
|
export let gradio;
|
|
44
44
|
export let border_region = 0;
|
|
45
|
+
export let webcam_options;
|
|
46
|
+
export let theme_mode;
|
|
45
47
|
let editor_instance;
|
|
46
48
|
let image_id = null;
|
|
47
49
|
export async function get_value() {
|
|
@@ -194,6 +196,10 @@ $:
|
|
|
194
196
|
upload={(...args) => gradio.client.upload(...args)}
|
|
195
197
|
{placeholder}
|
|
196
198
|
{full_history}
|
|
199
|
+
{webcam_options}
|
|
200
|
+
{show_download_button}
|
|
201
|
+
{theme_mode}
|
|
202
|
+
on:download_error={(e) => gradio.dispatch("error", e.detail)}
|
|
197
203
|
></InteractiveImageEditor>
|
|
198
204
|
</Block>
|
|
199
205
|
{/if}
|
package/dist/Index.svelte.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type { Brush, Eraser } from "./shared/brush/types";
|
|
|
3
3
|
import type { EditorData, ImageBlobs } from "./InteractiveImageEditor.svelte";
|
|
4
4
|
import type { Gradio, SelectData } from "@gradio/utils";
|
|
5
5
|
import type { LoadingStatus } from "@gradio/statustracker";
|
|
6
|
-
import type { LayerOptions, Transform, Source } from "./shared/types";
|
|
6
|
+
import type { LayerOptions, Transform, Source, WebcamOptions } from "./shared/types";
|
|
7
7
|
declare const __propDef: {
|
|
8
8
|
props: {
|
|
9
9
|
elem_id?: string | undefined;
|
|
@@ -52,6 +52,8 @@ declare const __propDef: {
|
|
|
52
52
|
clear_status: LoadingStatus;
|
|
53
53
|
}>;
|
|
54
54
|
border_region?: number | undefined;
|
|
55
|
+
webcam_options: WebcamOptions;
|
|
56
|
+
theme_mode: "dark" | "light";
|
|
55
57
|
get_value?: (() => Promise<ImageBlobs | {
|
|
56
58
|
id: string;
|
|
57
59
|
}>) | undefined;
|
|
@@ -194,6 +196,12 @@ export default class Index extends SvelteComponent<IndexProps, IndexEvents, Inde
|
|
|
194
196
|
get border_region(): number | undefined;
|
|
195
197
|
/**accessor*/
|
|
196
198
|
set border_region(_: number | undefined);
|
|
199
|
+
get webcam_options(): WebcamOptions;
|
|
200
|
+
/**accessor*/
|
|
201
|
+
set webcam_options(_: WebcamOptions);
|
|
202
|
+
get theme_mode(): "light" | "dark";
|
|
203
|
+
/**accessor*/
|
|
204
|
+
set theme_mode(_: "light" | "dark");
|
|
197
205
|
get undefined(): any;
|
|
198
206
|
/**accessor*/
|
|
199
207
|
set undefined(_: any);
|
|
@@ -20,6 +20,7 @@ export let root;
|
|
|
20
20
|
export let label = void 0;
|
|
21
21
|
export let show_label;
|
|
22
22
|
export let changeable = false;
|
|
23
|
+
export let theme_mode;
|
|
23
24
|
export let layers;
|
|
24
25
|
export let composite;
|
|
25
26
|
export let background;
|
|
@@ -34,6 +35,8 @@ export let is_dragging;
|
|
|
34
35
|
export let placeholder = void 0;
|
|
35
36
|
export let border_region;
|
|
36
37
|
export let full_history = null;
|
|
38
|
+
export let webcam_options;
|
|
39
|
+
export let show_download_button = false;
|
|
37
40
|
const dispatch = createEventDispatcher();
|
|
38
41
|
let editor;
|
|
39
42
|
let has_drawn = false;
|
|
@@ -168,6 +171,7 @@ let current_tool;
|
|
|
168
171
|
on:save
|
|
169
172
|
on:change={handle_change}
|
|
170
173
|
on:clear={() => dispatch("clear")}
|
|
174
|
+
on:download_error
|
|
171
175
|
{sources}
|
|
172
176
|
{full_history}
|
|
173
177
|
bind:background_image
|
|
@@ -182,6 +186,9 @@ let current_tool;
|
|
|
182
186
|
{upload}
|
|
183
187
|
bind:is_dragging
|
|
184
188
|
bind:has_drawn
|
|
189
|
+
{webcam_options}
|
|
190
|
+
{show_download_button}
|
|
191
|
+
{theme_mode}
|
|
185
192
|
>
|
|
186
193
|
{#if !background_image && current_tool === "image" && !has_drawn}
|
|
187
194
|
<div class="empty wrap">
|
|
@@ -13,7 +13,7 @@ import { type I18nFormatter } from "@gradio/utils";
|
|
|
13
13
|
import { type FileData, type Client } from "@gradio/client";
|
|
14
14
|
import { type CommandNode } from "./shared/utils/commands";
|
|
15
15
|
import { type Brush as IBrush, type Eraser } from "./shared/brush/types";
|
|
16
|
-
import { type LayerOptions, type Transform, type Source } from "./shared/types";
|
|
16
|
+
import { type LayerOptions, type Transform, type Source, type WebcamOptions } from "./shared/types";
|
|
17
17
|
declare const __propDef: {
|
|
18
18
|
props: {
|
|
19
19
|
brush: IBrush;
|
|
@@ -24,6 +24,7 @@ declare const __propDef: {
|
|
|
24
24
|
label?: string | undefined;
|
|
25
25
|
show_label: boolean;
|
|
26
26
|
changeable?: boolean | undefined;
|
|
27
|
+
theme_mode: "dark" | "light";
|
|
27
28
|
layers: FileData[];
|
|
28
29
|
composite: FileData | null;
|
|
29
30
|
background: FileData | null;
|
|
@@ -38,12 +39,15 @@ declare const __propDef: {
|
|
|
38
39
|
placeholder?: string | undefined;
|
|
39
40
|
border_region: number;
|
|
40
41
|
full_history?: (CommandNode | null) | undefined;
|
|
42
|
+
webcam_options: WebcamOptions;
|
|
43
|
+
show_download_button?: boolean | undefined;
|
|
41
44
|
get_data?: (() => Promise<ImageBlobs>) | undefined;
|
|
42
45
|
image_id?: (null | string) | undefined;
|
|
43
46
|
};
|
|
44
47
|
events: {
|
|
45
48
|
history: CustomEvent<import("svelte/store").Writable<CommandNode>>;
|
|
46
49
|
save: CustomEvent<void>;
|
|
50
|
+
download_error: CustomEvent<string>;
|
|
47
51
|
clear?: CustomEvent<undefined> | undefined;
|
|
48
52
|
upload?: CustomEvent<undefined> | undefined;
|
|
49
53
|
change?: CustomEvent<undefined> | undefined;
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
<script>import { createEventDispatcher } from "svelte";
|
|
2
2
|
import { IconButton, IconButtonWrapper } from "@gradio/atoms";
|
|
3
|
-
import { Check, Trash, ZoomIn, ZoomOut, Pan } from "@gradio/icons";
|
|
3
|
+
import { Check, Trash, ZoomIn, ZoomOut, Pan, Download } from "@gradio/icons";
|
|
4
4
|
export let can_save = false;
|
|
5
5
|
export let changeable = false;
|
|
6
6
|
export let current_zoom = 1;
|
|
7
7
|
export let tool;
|
|
8
8
|
export let min_zoom = true;
|
|
9
|
+
export let enable_download = false;
|
|
9
10
|
const dispatch = createEventDispatcher();
|
|
10
11
|
let show_zoom_popup = false;
|
|
11
12
|
function handle_zoom_click(e) {
|
|
@@ -26,6 +27,17 @@ $:
|
|
|
26
27
|
</script>
|
|
27
28
|
|
|
28
29
|
<IconButtonWrapper>
|
|
30
|
+
{#if enable_download}
|
|
31
|
+
<IconButton
|
|
32
|
+
Icon={Download}
|
|
33
|
+
label="Download"
|
|
34
|
+
on:click={(event) => {
|
|
35
|
+
dispatch("download");
|
|
36
|
+
event.stopPropagation();
|
|
37
|
+
}}
|
|
38
|
+
/>
|
|
39
|
+
{/if}
|
|
40
|
+
|
|
29
41
|
<IconButton
|
|
30
42
|
Icon={Pan}
|
|
31
43
|
label="Pan"
|
|
@@ -6,6 +6,7 @@ declare const __propDef: {
|
|
|
6
6
|
current_zoom?: number | undefined;
|
|
7
7
|
tool: string;
|
|
8
8
|
min_zoom?: boolean | undefined;
|
|
9
|
+
enable_download?: boolean | undefined;
|
|
9
10
|
};
|
|
10
11
|
events: {
|
|
11
12
|
remove_image: CustomEvent<void>;
|
|
@@ -16,6 +17,7 @@ declare const __propDef: {
|
|
|
16
17
|
zoom_out: CustomEvent<void>;
|
|
17
18
|
set_zoom: CustomEvent<number | "fit">;
|
|
18
19
|
pan: CustomEvent<void>;
|
|
20
|
+
download: CustomEvent<void>;
|
|
19
21
|
} & {
|
|
20
22
|
[evt: string]: CustomEvent<any>;
|
|
21
23
|
};
|
|
@@ -32,7 +32,6 @@ export let brush_options;
|
|
|
32
32
|
export let eraser_options;
|
|
33
33
|
export let fixed_canvas = false;
|
|
34
34
|
export let root;
|
|
35
|
-
export let mirror_webcam = true;
|
|
36
35
|
export let i18n;
|
|
37
36
|
export let upload;
|
|
38
37
|
export let composite;
|
|
@@ -41,6 +40,9 @@ export let background;
|
|
|
41
40
|
export let border_region = 0;
|
|
42
41
|
export let layer_options;
|
|
43
42
|
export let current_tool;
|
|
43
|
+
export let webcam_options;
|
|
44
|
+
export let show_download_button = false;
|
|
45
|
+
export let theme_mode;
|
|
44
46
|
let pixi_target;
|
|
45
47
|
let pixi_target_crop;
|
|
46
48
|
$:
|
|
@@ -171,7 +173,8 @@ async function init_image_editor() {
|
|
|
171
173
|
tools: ["image", zoom, new ResizeTool(), brush],
|
|
172
174
|
fixed_canvas,
|
|
173
175
|
border_region,
|
|
174
|
-
layer_options
|
|
176
|
+
layer_options,
|
|
177
|
+
theme_mode
|
|
175
178
|
});
|
|
176
179
|
brush.on("change", () => {
|
|
177
180
|
has_drawn = true;
|
|
@@ -391,6 +394,20 @@ async function handle_crop_confirm() {
|
|
|
391
394
|
dispatch("change");
|
|
392
395
|
dispatch("input");
|
|
393
396
|
}
|
|
397
|
+
async function handle_download() {
|
|
398
|
+
const blobs = await editor.get_blobs();
|
|
399
|
+
const blob = blobs.composite;
|
|
400
|
+
if (!blob) {
|
|
401
|
+
dispatch("download_error", "Unable to generate image to download.");
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
404
|
+
const url = URL.createObjectURL(blob);
|
|
405
|
+
const link = document.createElement("a");
|
|
406
|
+
link.href = url;
|
|
407
|
+
link.download = "image.png";
|
|
408
|
+
link.click();
|
|
409
|
+
URL.revokeObjectURL(url);
|
|
410
|
+
}
|
|
394
411
|
</script>
|
|
395
412
|
|
|
396
413
|
<div
|
|
@@ -427,6 +444,8 @@ async function handle_crop_confirm() {
|
|
|
427
444
|
on:pan={(e) => {
|
|
428
445
|
handle_tool_change({ tool: "pan" });
|
|
429
446
|
}}
|
|
447
|
+
enable_download={show_download_button}
|
|
448
|
+
on:download={() => handle_download()}
|
|
430
449
|
/>
|
|
431
450
|
{/if}
|
|
432
451
|
|
|
@@ -461,11 +480,12 @@ async function handle_crop_confirm() {
|
|
|
461
480
|
on:capture={handle_capture}
|
|
462
481
|
on:error
|
|
463
482
|
on:drag
|
|
464
|
-
{mirror_webcam}
|
|
465
483
|
streaming={false}
|
|
466
484
|
mode="image"
|
|
467
485
|
include_audio={false}
|
|
468
486
|
{i18n}
|
|
487
|
+
mirror_webcam={webcam_options.mirror}
|
|
488
|
+
webcam_constraints={webcam_options.constraints}
|
|
469
489
|
/>
|
|
470
490
|
</div>
|
|
471
491
|
</div>
|
|
@@ -480,6 +500,9 @@ async function handle_crop_confirm() {
|
|
|
480
500
|
}}
|
|
481
501
|
on:change_layer={(e) => {
|
|
482
502
|
editor.set_layer(e.detail);
|
|
503
|
+
if (current_tool === "draw") {
|
|
504
|
+
handle_tool_change({ tool: "draw" });
|
|
505
|
+
}
|
|
483
506
|
}}
|
|
484
507
|
on:move_layer={(e) => {
|
|
485
508
|
editor.move_layer(e.detail.id, e.detail.direction);
|
|
@@ -487,6 +510,9 @@ async function handle_crop_confirm() {
|
|
|
487
510
|
on:delete_layer={(e) => {
|
|
488
511
|
editor.delete_layer(e.detail);
|
|
489
512
|
}}
|
|
513
|
+
on:toggle_layer_visibility={(e) => {
|
|
514
|
+
editor.toggle_layer_visibility(e.detail);
|
|
515
|
+
}}
|
|
490
516
|
/>
|
|
491
517
|
{/if}
|
|
492
518
|
{/if}
|
|
@@ -6,7 +6,7 @@ import type { I18nFormatter } from "@gradio/utils";
|
|
|
6
6
|
import type { Client, FileData } from "@gradio/client";
|
|
7
7
|
import { type CommandNode } from "./utils/commands";
|
|
8
8
|
import { type Brush, type Eraser } from "./brush/types";
|
|
9
|
-
import type { LayerOptions, Source, Transform } from "./types";
|
|
9
|
+
import type { LayerOptions, Source, Transform, WebcamOptions } from "./types";
|
|
10
10
|
import { type ImageBlobs } from "./types";
|
|
11
11
|
declare const __propDef: {
|
|
12
12
|
props: {
|
|
@@ -22,7 +22,6 @@ declare const __propDef: {
|
|
|
22
22
|
eraser_options: Eraser;
|
|
23
23
|
fixed_canvas?: boolean | undefined;
|
|
24
24
|
root: string;
|
|
25
|
-
mirror_webcam?: boolean | undefined;
|
|
26
25
|
i18n: I18nFormatter;
|
|
27
26
|
upload: Client["upload"];
|
|
28
27
|
composite: FileData | null;
|
|
@@ -31,6 +30,9 @@ declare const __propDef: {
|
|
|
31
30
|
border_region?: number | undefined;
|
|
32
31
|
layer_options: LayerOptions;
|
|
33
32
|
current_tool: ToolbarTool;
|
|
33
|
+
webcam_options: WebcamOptions;
|
|
34
|
+
show_download_button?: boolean | undefined;
|
|
35
|
+
theme_mode: "dark" | "light";
|
|
34
36
|
has_drawn?: boolean | undefined;
|
|
35
37
|
get_blobs?: (() => Promise<ImageBlobs>) | undefined;
|
|
36
38
|
add_image?: ((image: Blob | File) => void) | undefined;
|
|
@@ -51,6 +53,7 @@ declare const __propDef: {
|
|
|
51
53
|
history: CustomEvent<import("svelte/store").Writable<CommandNode>>;
|
|
52
54
|
upload: CustomEvent<void>;
|
|
53
55
|
input: CustomEvent<void>;
|
|
56
|
+
download_error: CustomEvent<string>;
|
|
54
57
|
} & {
|
|
55
58
|
[evt: string]: CustomEvent<any>;
|
|
56
59
|
};
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
<script>import { click_outside } from "./utils/events";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
Layers,
|
|
4
|
+
Clear,
|
|
5
|
+
ArrowUp,
|
|
6
|
+
ArrowDown,
|
|
7
|
+
Plus,
|
|
8
|
+
Visibility,
|
|
9
|
+
VisibilityOff
|
|
10
|
+
} from "@gradio/icons";
|
|
3
11
|
import { IconButton } from "@gradio/atoms";
|
|
4
12
|
import { createEventDispatcher } from "svelte";
|
|
5
13
|
const dispatch = createEventDispatcher();
|
|
@@ -40,8 +48,27 @@ function delete_layer(id) {
|
|
|
40
48
|
</button>
|
|
41
49
|
{#if show_layers}
|
|
42
50
|
<ul>
|
|
43
|
-
{#each $layers.layers as { id, name, user_created }, i (i)}
|
|
51
|
+
{#each $layers.layers as { id, name, user_created, visible }, i (i)}
|
|
44
52
|
<li>
|
|
53
|
+
{#if !visible}
|
|
54
|
+
<IconButton
|
|
55
|
+
Icon={VisibilityOff}
|
|
56
|
+
size="small"
|
|
57
|
+
on:click={(e) => {
|
|
58
|
+
e.stopPropagation();
|
|
59
|
+
dispatch("toggle_layer_visibility", id);
|
|
60
|
+
}}
|
|
61
|
+
/>
|
|
62
|
+
{:else}
|
|
63
|
+
<IconButton
|
|
64
|
+
Icon={Visibility}
|
|
65
|
+
size="small"
|
|
66
|
+
on:click={(e) => {
|
|
67
|
+
e.stopPropagation();
|
|
68
|
+
dispatch("toggle_layer_visibility", id);
|
|
69
|
+
}}
|
|
70
|
+
/>
|
|
71
|
+
{/if}
|
|
45
72
|
<button
|
|
46
73
|
class:selected_layer={$layers.active_layer === id}
|
|
47
74
|
aria-label={`layer-${i + 1}`}
|
|
@@ -8,6 +8,7 @@ declare const __propDef: {
|
|
|
8
8
|
name: string;
|
|
9
9
|
id: string;
|
|
10
10
|
user_created: boolean;
|
|
11
|
+
visible: boolean;
|
|
11
12
|
}[];
|
|
12
13
|
}>;
|
|
13
14
|
enable_additional_layers?: boolean | undefined;
|
|
@@ -22,6 +23,7 @@ declare const __propDef: {
|
|
|
22
23
|
direction: "up" | "down";
|
|
23
24
|
}>;
|
|
24
25
|
delete_layer: CustomEvent<string>;
|
|
26
|
+
toggle_layer_visibility: CustomEvent<string>;
|
|
25
27
|
} & {
|
|
26
28
|
[evt: string]: CustomEvent<any>;
|
|
27
29
|
};
|
|
@@ -8,6 +8,7 @@ declare const __propDef: {
|
|
|
8
8
|
name: string;
|
|
9
9
|
id: string;
|
|
10
10
|
user_created: boolean;
|
|
11
|
+
visible: boolean;
|
|
11
12
|
}[];
|
|
12
13
|
}>;
|
|
13
14
|
enable_additional_layers?: boolean | undefined;
|
|
@@ -22,6 +23,7 @@ declare const __propDef: {
|
|
|
22
23
|
direction: "up" | "down";
|
|
23
24
|
}>;
|
|
24
25
|
delete_layer: CustomEvent<string>;
|
|
26
|
+
toggle_layer_visibility: CustomEvent<string>;
|
|
25
27
|
} & {
|
|
26
28
|
[evt: string]: CustomEvent<any>;
|
|
27
29
|
};
|
|
@@ -16,14 +16,8 @@ export declare class BrushTextures {
|
|
|
16
16
|
private erase_graphics;
|
|
17
17
|
private dimensions;
|
|
18
18
|
private is_new_stroke;
|
|
19
|
-
private scale;
|
|
20
19
|
private current_opacity;
|
|
21
20
|
private current_mode;
|
|
22
|
-
private last_from_x;
|
|
23
|
-
private last_from_y;
|
|
24
|
-
private last_to_x;
|
|
25
|
-
private last_to_y;
|
|
26
|
-
private last_size;
|
|
27
21
|
constructor(image_editor_context: ImageEditorContext, app: Application);
|
|
28
22
|
/**
|
|
29
23
|
* Initializes textures needed for the brush tool.
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Container, RenderTexture, Sprite, Graphics, Application } from "pixi.js";
|
|
2
|
-
import { safe_destroy, safe_remove_child } from "./brush-utils";
|
|
3
2
|
import {} from "../core/editor";
|
|
4
3
|
/**
|
|
5
4
|
* Class to handle texture operations for the brush tool.
|
|
@@ -19,18 +18,10 @@ export class BrushTextures {
|
|
|
19
18
|
dimensions;
|
|
20
19
|
// Track if a new stroke is starting
|
|
21
20
|
is_new_stroke = true;
|
|
22
|
-
// Current scale factor
|
|
23
|
-
scale = 1;
|
|
24
21
|
// Track the current drawing opacity
|
|
25
22
|
current_opacity = 1.0;
|
|
26
23
|
// Track current drawing mode
|
|
27
24
|
current_mode = "draw";
|
|
28
|
-
// Store last drawing parameters for eraser recreation
|
|
29
|
-
last_from_x = null;
|
|
30
|
-
last_from_y = null;
|
|
31
|
-
last_to_x = null;
|
|
32
|
-
last_to_y = null;
|
|
33
|
-
last_size = null;
|
|
34
25
|
constructor(image_editor_context, app) {
|
|
35
26
|
this.image_editor_context = image_editor_context;
|
|
36
27
|
this.app = app;
|
|
@@ -38,10 +29,6 @@ export class BrushTextures {
|
|
|
38
29
|
width: this.image_editor_context.image_container.width,
|
|
39
30
|
height: this.image_editor_context.image_container.height
|
|
40
31
|
};
|
|
41
|
-
// Subscribe to scale changes
|
|
42
|
-
this.image_editor_context.scale.subscribe((scale) => {
|
|
43
|
-
this.scale = scale;
|
|
44
|
-
});
|
|
45
32
|
}
|
|
46
33
|
/**
|
|
47
34
|
* Initializes textures needed for the brush tool.
|
|
@@ -256,12 +243,6 @@ export class BrushTextures {
|
|
|
256
243
|
this.current_mode = mode;
|
|
257
244
|
this.current_opacity =
|
|
258
245
|
mode === "draw" ? Math.min(Math.max(opacity, 0), 1) : 0.5;
|
|
259
|
-
// Store parameters for potential eraser recreation
|
|
260
|
-
this.last_from_x = from_x;
|
|
261
|
-
this.last_from_y = from_y;
|
|
262
|
-
this.last_to_x = to_x;
|
|
263
|
-
this.last_to_y = to_y;
|
|
264
|
-
this.last_size = size;
|
|
265
246
|
// Apply scale to brush size for consistent rendering
|
|
266
247
|
const scaled_size = size;
|
|
267
248
|
// For new strokes, clear the graphics and texture completely
|
|
@@ -171,8 +171,9 @@ export class BrushTool {
|
|
|
171
171
|
* @private
|
|
172
172
|
*/
|
|
173
173
|
on_pointer_down(event) {
|
|
174
|
-
|
|
175
|
-
if (
|
|
174
|
+
const current_layer = this.image_editor_context.layer_manager.get_active_layer();
|
|
175
|
+
if (!current_layer?.visible ||
|
|
176
|
+
(this.current_tool !== "erase" && this.current_tool !== "draw")) {
|
|
176
177
|
return;
|
|
177
178
|
}
|
|
178
179
|
if (this.brush_cursor && !this.brush_cursor.is_over_image())
|