@gradio/imageeditor 0.14.4 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +21 -0
- package/InteractiveImageEditor.svelte +4 -7
- package/dist/InteractiveImageEditor.svelte +4 -3
- package/dist/InteractiveImageEditor.svelte.d.ts +1 -1
- package/dist/shared/Controls.svelte +32 -1
- package/dist/shared/Controls.svelte.d.ts +2 -0
- package/dist/shared/ImageEditor.svelte +23 -1
- package/dist/shared/ImageEditor.svelte.d.ts +2 -1
- package/dist/shared/brush/brush-cursor.js +0 -42
- package/dist/shared/brush/brush-textures.d.ts +19 -2
- package/dist/shared/brush/brush-textures.js +120 -82
- package/dist/shared/brush/brush.js +0 -52
- package/dist/shared/{utils → core}/commands.d.ts +19 -58
- package/dist/shared/core/commands.js +70 -0
- package/dist/shared/core/editor.d.ts +4 -91
- package/dist/shared/core/editor.js +18 -708
- package/dist/shared/core/layers.d.ts +143 -0
- package/dist/shared/core/layers.js +774 -0
- package/dist/shared/image/image.d.ts +14 -4
- package/dist/shared/image/image.js +91 -18
- package/dist/shared/resize/resize.d.ts +31 -0
- package/dist/shared/resize/resize.js +127 -290
- package/dist/shared/zoom/zoom.js +0 -51
- package/package.json +7 -7
- package/shared/Controls.svelte +33 -1
- package/shared/ImageEditor.svelte +25 -9
- package/shared/Toolbar.svelte +1 -4
- package/shared/brush/ColorSwatch.svelte +0 -3
- package/shared/brush/brush-cursor.ts +0 -42
- package/shared/brush/brush-textures.ts +166 -83
- package/shared/brush/brush.ts +0 -53
- package/shared/core/commands.ts +118 -0
- package/shared/core/editor.ts +33 -957
- package/shared/core/layers.ts +1068 -0
- package/shared/image/image.ts +139 -21
- package/shared/resize/resize.ts +160 -299
- package/shared/zoom/zoom.ts +0 -51
- package/dist/shared/utils/commands.js +0 -73
- package/shared/utils/commands.ts +0 -174
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Container, type ColorSource, Sprite, type Renderer, Texture } from "pixi.js";
|
|
2
2
|
import { type ImageEditorContext, type Tool } from "../core/editor";
|
|
3
3
|
import { type Tool as ToolbarTool, type Subtool } from "../Toolbar.svelte";
|
|
4
|
-
import { type Command } from "../
|
|
4
|
+
import { type Command } from "../core/commands";
|
|
5
5
|
/**
|
|
6
6
|
* Handles adding images to the editor
|
|
7
7
|
* Only a single image can be added at a time
|
|
@@ -26,10 +26,10 @@ interface BgImageCommand extends Command {
|
|
|
26
26
|
* Initial setup for the bg command
|
|
27
27
|
* @returns
|
|
28
28
|
*/
|
|
29
|
-
start: () => Promise<
|
|
29
|
+
start: () => Promise<void>;
|
|
30
30
|
}
|
|
31
31
|
export declare class AddImageCommand implements BgImageCommand {
|
|
32
|
-
sprite: Sprite;
|
|
32
|
+
sprite: Sprite | null;
|
|
33
33
|
fixed_canvas: boolean;
|
|
34
34
|
context: ImageEditorContext;
|
|
35
35
|
background: Blob | File | Texture;
|
|
@@ -37,6 +37,10 @@ export declare class AddImageCommand implements BgImageCommand {
|
|
|
37
37
|
width: number;
|
|
38
38
|
height: number;
|
|
39
39
|
};
|
|
40
|
+
computed_dimensions: {
|
|
41
|
+
width: number;
|
|
42
|
+
height: number;
|
|
43
|
+
};
|
|
40
44
|
current_scale: number;
|
|
41
45
|
current_position: {
|
|
42
46
|
x: number;
|
|
@@ -45,8 +49,14 @@ export declare class AddImageCommand implements BgImageCommand {
|
|
|
45
49
|
border_region: number;
|
|
46
50
|
scaled_width: number;
|
|
47
51
|
scaled_height: number;
|
|
52
|
+
private previous_image;
|
|
53
|
+
name: string;
|
|
48
54
|
constructor(context: ImageEditorContext, background: Blob | File | Texture, fixed_canvas: boolean, border_region?: number);
|
|
49
|
-
|
|
55
|
+
/**
|
|
56
|
+
* Creates a copy of a texture to avoid reference issues
|
|
57
|
+
*/
|
|
58
|
+
private clone_texture;
|
|
59
|
+
start(): Promise<void>;
|
|
50
60
|
private handle_image;
|
|
51
61
|
execute(): Promise<void>;
|
|
52
62
|
undo(): Promise<void>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Container, Graphics, Color, RenderTexture, Sprite, Texture } from "pixi.js";
|
|
2
2
|
import {} from "../core/editor";
|
|
3
3
|
import {} from "../Toolbar.svelte";
|
|
4
|
-
import {} from "../
|
|
4
|
+
import {} from "../core/commands";
|
|
5
5
|
import { make_graphics } from "../utils/pixi";
|
|
6
6
|
import { get } from "svelte/store";
|
|
7
7
|
/**
|
|
@@ -30,17 +30,21 @@ export class ImageTool {
|
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
export class AddImageCommand {
|
|
33
|
-
sprite;
|
|
33
|
+
sprite = null;
|
|
34
34
|
fixed_canvas;
|
|
35
35
|
context;
|
|
36
36
|
background;
|
|
37
37
|
current_canvas_size;
|
|
38
|
+
computed_dimensions;
|
|
38
39
|
current_scale;
|
|
39
40
|
current_position;
|
|
40
41
|
border_region;
|
|
41
42
|
scaled_width;
|
|
42
43
|
scaled_height;
|
|
44
|
+
previous_image = null;
|
|
45
|
+
name;
|
|
43
46
|
constructor(context, background, fixed_canvas, border_region = 0) {
|
|
47
|
+
this.name = "AddImage";
|
|
44
48
|
this.context = context;
|
|
45
49
|
this.background = background;
|
|
46
50
|
this.fixed_canvas = fixed_canvas;
|
|
@@ -48,10 +52,40 @@ export class AddImageCommand {
|
|
|
48
52
|
this.current_canvas_size = get(this.context.dimensions);
|
|
49
53
|
this.current_scale = get(this.context.scale);
|
|
50
54
|
this.current_position = get(this.context.position);
|
|
51
|
-
this.
|
|
55
|
+
this.computed_dimensions = { width: 0, height: 0 };
|
|
56
|
+
if (this.context.background_image &&
|
|
57
|
+
this.context.background_image.texture) {
|
|
58
|
+
const bg = this.context.background_image;
|
|
59
|
+
const stored_border_region = bg.borderRegion || 0;
|
|
60
|
+
this.previous_image = {
|
|
61
|
+
texture: this.clone_texture(bg.texture),
|
|
62
|
+
width: bg.width,
|
|
63
|
+
height: bg.height,
|
|
64
|
+
x: bg.position.x,
|
|
65
|
+
y: bg.position.y,
|
|
66
|
+
border_region: stored_border_region
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Creates a copy of a texture to avoid reference issues
|
|
72
|
+
*/
|
|
73
|
+
clone_texture(texture) {
|
|
74
|
+
const render_texture = RenderTexture.create({
|
|
75
|
+
width: texture.width,
|
|
76
|
+
height: texture.height,
|
|
77
|
+
resolution: window.devicePixelRatio || 1
|
|
78
|
+
});
|
|
79
|
+
const sprite = new Sprite(texture);
|
|
80
|
+
const container = new Container();
|
|
81
|
+
container.addChild(sprite);
|
|
82
|
+
this.context.app.renderer.render(container, {
|
|
83
|
+
renderTexture: render_texture
|
|
84
|
+
});
|
|
85
|
+
container.destroy({ children: true });
|
|
86
|
+
return render_texture;
|
|
52
87
|
}
|
|
53
88
|
async start() {
|
|
54
|
-
// Create the sprite from the blob
|
|
55
89
|
let image_texture;
|
|
56
90
|
if (this.background instanceof Texture) {
|
|
57
91
|
image_texture = this.background;
|
|
@@ -61,27 +95,25 @@ export class AddImageCommand {
|
|
|
61
95
|
image_texture = Texture.from(img);
|
|
62
96
|
}
|
|
63
97
|
this.sprite = new Sprite(image_texture);
|
|
64
|
-
|
|
98
|
+
const [width, height] = this.handle_image();
|
|
99
|
+
this.computed_dimensions = { width, height };
|
|
65
100
|
}
|
|
66
101
|
handle_image() {
|
|
67
|
-
|
|
102
|
+
if (this.sprite === null) {
|
|
103
|
+
return [0, 0];
|
|
104
|
+
}
|
|
68
105
|
if (this.fixed_canvas) {
|
|
69
|
-
// Calculate the effective canvas size accounting for border region
|
|
70
106
|
const effectiveCanvasWidth = Math.max(this.current_canvas_size.width - this.border_region * 2, 10);
|
|
71
107
|
const effectiveCanvasHeight = Math.max(this.current_canvas_size.height - this.border_region * 2, 10);
|
|
72
|
-
// Fit the image to the canvas while maintaining aspect ratio
|
|
73
108
|
const { width, height, x, y } = fit_image_to_canvas(this.sprite.width, this.sprite.height, effectiveCanvasWidth, effectiveCanvasHeight);
|
|
74
109
|
this.sprite.width = width;
|
|
75
110
|
this.sprite.height = height;
|
|
76
|
-
// Center the image in the canvas
|
|
77
111
|
this.sprite.x = x + this.border_region;
|
|
78
112
|
this.sprite.y = y + this.border_region;
|
|
79
113
|
}
|
|
80
114
|
else {
|
|
81
|
-
// For non-fixed canvas, use natural dimensions plus border
|
|
82
115
|
const width = this.sprite.width;
|
|
83
116
|
const height = this.sprite.height;
|
|
84
|
-
// Position at the border's offset from origin
|
|
85
117
|
this.sprite.x = this.border_region;
|
|
86
118
|
this.sprite.y = this.border_region;
|
|
87
119
|
return [width + this.border_region * 2, height + this.border_region * 2];
|
|
@@ -89,11 +121,13 @@ export class AddImageCommand {
|
|
|
89
121
|
return [this.current_canvas_size.width, this.current_canvas_size.height];
|
|
90
122
|
}
|
|
91
123
|
async execute() {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
124
|
+
await this.start();
|
|
125
|
+
if (this.sprite === null) {
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
const { width, height } = this.computed_dimensions;
|
|
95
129
|
await this.context.set_image_properties({
|
|
96
|
-
scale: 1,
|
|
130
|
+
scale: 1,
|
|
97
131
|
position: {
|
|
98
132
|
x: this.context.app.screen.width / 2,
|
|
99
133
|
y: this.context.app.screen.height / 2
|
|
@@ -101,18 +135,57 @@ export class AddImageCommand {
|
|
|
101
135
|
width: this.fixed_canvas ? this.current_canvas_size.width : width,
|
|
102
136
|
height: this.fixed_canvas ? this.current_canvas_size.height : height
|
|
103
137
|
});
|
|
104
|
-
// Create new background layer and add the sprite
|
|
105
138
|
const background_layer = this.context.layer_manager.create_background_layer(this.fixed_canvas ? this.current_canvas_size.width : width, this.fixed_canvas ? this.current_canvas_size.height : height);
|
|
106
139
|
this.sprite.zIndex = 0;
|
|
107
140
|
background_layer.addChild(this.sprite);
|
|
108
|
-
// Resize and preserve content of existing layers
|
|
109
141
|
this.context.layer_manager.reset_layers(this.fixed_canvas ? this.current_canvas_size.width : width, this.fixed_canvas ? this.current_canvas_size.height : height, true);
|
|
142
|
+
if (this.border_region > 0) {
|
|
143
|
+
this.sprite.borderRegion = this.border_region;
|
|
144
|
+
}
|
|
110
145
|
this.context.set_background_image(this.sprite);
|
|
111
146
|
this.context.reset();
|
|
112
147
|
}
|
|
113
148
|
async undo() {
|
|
114
149
|
if (this.sprite) {
|
|
115
150
|
this.sprite.destroy();
|
|
151
|
+
if (this.previous_image) {
|
|
152
|
+
const previous_sprite = new Sprite(this.previous_image.texture);
|
|
153
|
+
previous_sprite.width = this.previous_image.width;
|
|
154
|
+
previous_sprite.height = this.previous_image.height;
|
|
155
|
+
previous_sprite.position.set(this.previous_image.x, this.previous_image.y);
|
|
156
|
+
if (this.previous_image.border_region > 0) {
|
|
157
|
+
previous_sprite.borderRegion =
|
|
158
|
+
this.previous_image.border_region;
|
|
159
|
+
}
|
|
160
|
+
await this.context.set_image_properties({
|
|
161
|
+
scale: 1,
|
|
162
|
+
position: {
|
|
163
|
+
x: this.context.app.screen.width / 2,
|
|
164
|
+
y: this.context.app.screen.height / 2
|
|
165
|
+
},
|
|
166
|
+
width: this.previous_image.width,
|
|
167
|
+
height: this.previous_image.height
|
|
168
|
+
});
|
|
169
|
+
const background_layer = this.context.layer_manager.create_background_layer(this.previous_image.width, this.previous_image.height);
|
|
170
|
+
previous_sprite.zIndex = 0;
|
|
171
|
+
background_layer.addChild(previous_sprite);
|
|
172
|
+
this.context.layer_manager.reset_layers(this.previous_image.width, this.previous_image.height, true);
|
|
173
|
+
this.context.set_background_image(previous_sprite);
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
await this.context.set_image_properties({
|
|
177
|
+
scale: 1,
|
|
178
|
+
position: {
|
|
179
|
+
x: this.context.app.screen.width / 2,
|
|
180
|
+
y: this.context.app.screen.height / 2
|
|
181
|
+
},
|
|
182
|
+
width: this.current_canvas_size.width,
|
|
183
|
+
height: this.current_canvas_size.height
|
|
184
|
+
});
|
|
185
|
+
this.context.layer_manager.create_background_layer(this.current_canvas_size.width, this.current_canvas_size.height);
|
|
186
|
+
this.context.layer_manager.reset_layers(this.current_canvas_size.width, this.current_canvas_size.height);
|
|
187
|
+
}
|
|
188
|
+
this.context.reset();
|
|
116
189
|
}
|
|
117
190
|
}
|
|
118
191
|
}
|
|
@@ -129,6 +202,7 @@ export class AddImageCommand {
|
|
|
129
202
|
export function add_bg_color(container, renderer, color, width, height, resize) {
|
|
130
203
|
let sprite;
|
|
131
204
|
return {
|
|
205
|
+
name: "AddBgColor",
|
|
132
206
|
start() {
|
|
133
207
|
container.removeChildren();
|
|
134
208
|
const graphics = make_graphics(1);
|
|
@@ -171,7 +245,6 @@ export function fit_image_to_canvas(image_width, image_height, canvas_width, can
|
|
|
171
245
|
new_height = canvas_height;
|
|
172
246
|
new_width = canvas_height * image_aspect_ratio;
|
|
173
247
|
}
|
|
174
|
-
// center image
|
|
175
248
|
const x = Math.round((canvas_width - new_width) / 2);
|
|
176
249
|
const y = Math.round((canvas_height - new_height) / 2);
|
|
177
250
|
return {
|
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
import { type ImageEditorContext, type Tool } from "../core/editor";
|
|
2
2
|
import { type Tool as ToolbarTool, type Subtool } from "../Toolbar.svelte";
|
|
3
|
+
import { type Command } from "../core/commands";
|
|
4
|
+
/**
|
|
5
|
+
* Command that handles resizing the image and supports undo/redo
|
|
6
|
+
*/
|
|
7
|
+
export declare class ResizeCommand implements Command {
|
|
8
|
+
private context;
|
|
9
|
+
private original_width;
|
|
10
|
+
private original_height;
|
|
11
|
+
private original_x;
|
|
12
|
+
private original_y;
|
|
13
|
+
private new_width;
|
|
14
|
+
private new_height;
|
|
15
|
+
private new_x;
|
|
16
|
+
private new_y;
|
|
17
|
+
private reset_ui;
|
|
18
|
+
name: string;
|
|
19
|
+
constructor(context: ImageEditorContext, original_state: {
|
|
20
|
+
width: number;
|
|
21
|
+
height: number;
|
|
22
|
+
x: number;
|
|
23
|
+
y: number;
|
|
24
|
+
}, new_state: {
|
|
25
|
+
width: number;
|
|
26
|
+
height: number;
|
|
27
|
+
x: number;
|
|
28
|
+
y: number;
|
|
29
|
+
}, reset_ui: () => void);
|
|
30
|
+
execute(): Promise<void>;
|
|
31
|
+
undo(): Promise<void>;
|
|
32
|
+
}
|
|
3
33
|
/**
|
|
4
34
|
* @class ResizeTool
|
|
5
35
|
* @implements {Tool}
|
|
@@ -31,6 +61,7 @@ export declare class ResizeTool implements Tool {
|
|
|
31
61
|
private dom_mouseup_handler;
|
|
32
62
|
private event_callbacks;
|
|
33
63
|
private last_scale;
|
|
64
|
+
private original_state;
|
|
34
65
|
/**
|
|
35
66
|
* @method setup
|
|
36
67
|
* @async
|