@gradio/imageeditor 0.12.14 → 0.13.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 +14 -0
- package/Example.svelte +1 -1
- package/IMAGE_EDITOR_OVERVIEW.md +224 -0
- package/ImageEditor.stories.svelte +4 -4
- package/Index.svelte +35 -46
- package/{shared/InteractiveImageEditor.svelte → InteractiveImageEditor.svelte} +56 -103
- package/dist/Example.svelte.d.ts +1 -1
- package/dist/Index.svelte +29 -33
- package/dist/Index.svelte.d.ts +17 -16
- package/dist/{shared/InteractiveImageEditor.svelte → InteractiveImageEditor.svelte} +47 -88
- package/dist/{shared/InteractiveImageEditor.svelte.d.ts → InteractiveImageEditor.svelte.d.ts} +13 -15
- package/dist/shared/Anchor.svelte +311 -0
- package/dist/shared/Anchor.svelte.d.ts +18 -0
- package/dist/shared/Controls.svelte +162 -23
- package/dist/shared/Controls.svelte.d.ts +7 -2
- package/dist/shared/{tools/IconButton.svelte → IconButton.svelte} +19 -3
- package/dist/shared/{tools/IconButton.svelte.d.ts → IconButton.svelte.d.ts} +4 -1
- package/dist/shared/ImageEditor.svelte +546 -289
- package/dist/shared/ImageEditor.svelte.d.ts +51 -56
- package/dist/shared/Layers.svelte +233 -0
- package/dist/shared/Layers.svelte.d.ts +35 -0
- package/dist/shared/Resize.svelte +218 -0
- package/dist/shared/Resize.svelte.d.ts +29 -0
- package/dist/shared/SecondaryToolbar.svelte +54 -0
- package/dist/shared/SecondaryToolbar.svelte.d.ts +35 -0
- package/dist/shared/Toolbar.svelte +337 -0
- package/dist/shared/Toolbar.svelte.d.ts +42 -0
- package/dist/shared/{tools → brush}/BrushOptions.svelte +68 -64
- package/dist/shared/{tools → brush}/BrushOptions.svelte.d.ts +9 -9
- package/dist/shared/{tools → brush}/BrushSize.svelte +2 -27
- package/dist/shared/{tools → brush}/ColorField.svelte +2 -1
- package/dist/shared/{tools → brush}/ColorField.svelte.d.ts +1 -0
- package/dist/shared/{tools → brush}/ColorPicker.svelte +81 -9
- package/dist/shared/{tools → brush}/ColorPicker.svelte.d.ts +1 -0
- package/dist/shared/{tools → brush}/ColorSwatch.svelte +78 -38
- package/dist/shared/{tools → brush}/ColorSwatch.svelte.d.ts +6 -2
- package/dist/shared/brush/brush-cursor.d.ts +101 -0
- package/dist/shared/brush/brush-cursor.js +327 -0
- package/dist/shared/brush/brush-textures.d.ts +71 -0
- package/dist/shared/brush/brush-textures.js +404 -0
- package/dist/shared/brush/brush-utils.d.ts +32 -0
- package/dist/shared/brush/brush-utils.js +59 -0
- package/dist/shared/brush/brush.d.ts +152 -0
- package/dist/shared/brush/brush.js +396 -0
- package/dist/shared/brush/types.d.ts +37 -0
- package/dist/shared/brush/types.js +1 -0
- package/dist/shared/core/editor.d.ts +252 -0
- package/dist/shared/core/editor.js +1221 -0
- package/dist/shared/crop/crop.d.ts +201 -0
- package/dist/shared/crop/crop.js +727 -0
- package/dist/shared/image/image.d.ts +89 -0
- package/dist/shared/image/image.js +185 -0
- package/dist/shared/resize/resize.d.ts +270 -0
- package/dist/shared/resize/resize.js +1413 -0
- package/dist/shared/types.d.ts +12 -0
- package/dist/shared/utils/pixi.d.ts +16 -57
- package/dist/shared/utils/pixi.js +15 -113
- package/dist/shared/zoom/zoom.d.ts +136 -0
- package/dist/shared/zoom/zoom.js +548 -0
- package/package.json +10 -9
- package/shared/Anchor.svelte +384 -0
- package/shared/Controls.svelte +194 -27
- package/shared/{tools/IconButton.svelte → IconButton.svelte} +21 -4
- package/shared/ImageEditor.svelte +682 -349
- package/shared/Layers.svelte +249 -0
- package/shared/Resize.svelte +239 -0
- package/shared/SecondaryToolbar.svelte +61 -0
- package/shared/Toolbar.svelte +386 -0
- package/shared/brush/BRUSH_TOOL.md +134 -0
- package/shared/brush/BrushOptions.svelte +200 -0
- package/shared/{tools → brush}/BrushSize.svelte +2 -30
- package/shared/{tools → brush}/ColorField.svelte +3 -1
- package/shared/{tools → brush}/ColorPicker.svelte +86 -9
- package/shared/{tools → brush}/ColorSwatch.svelte +95 -42
- package/shared/brush/brush-cursor.ts +408 -0
- package/shared/brush/brush-textures.ts +508 -0
- package/shared/brush/brush-utils.ts +76 -0
- package/shared/brush/brush.ts +506 -0
- package/shared/brush/types.ts +41 -0
- package/shared/core/EDITOR.md +182 -0
- package/shared/core/editor.ts +1730 -0
- package/shared/crop/CROP.md +139 -0
- package/shared/crop/crop.ts +1027 -0
- package/shared/image/IMAGE.md +135 -0
- package/shared/image/image.ts +300 -0
- package/shared/resize/resize.ts +1894 -0
- package/shared/types.ts +14 -0
- package/shared/utils/pixi.ts +19 -246
- package/shared/zoom/zoom.ts +729 -0
- package/dist/shared/layers/Layers.svelte +0 -231
- package/dist/shared/layers/Layers.svelte.d.ts +0 -18
- package/dist/shared/layers/utils.d.ts +0 -73
- package/dist/shared/layers/utils.js +0 -156
- package/dist/shared/tools/Brush.svelte +0 -215
- package/dist/shared/tools/Brush.svelte.d.ts +0 -29
- package/dist/shared/tools/Crop.svelte +0 -155
- package/dist/shared/tools/Crop.svelte.d.ts +0 -16
- package/dist/shared/tools/Cropper.svelte +0 -271
- package/dist/shared/tools/Cropper.svelte.d.ts +0 -41
- package/dist/shared/tools/Handle.svelte +0 -260
- package/dist/shared/tools/Handle.svelte.d.ts +0 -29
- package/dist/shared/tools/Sources.svelte +0 -257
- package/dist/shared/tools/Sources.svelte.d.ts +0 -34
- package/dist/shared/tools/Tools.svelte +0 -102
- package/dist/shared/tools/Tools.svelte.d.ts +0 -48
- package/dist/shared/tools/brush.d.ts +0 -62
- package/dist/shared/tools/brush.js +0 -133
- package/dist/shared/tools/crop.d.ts +0 -15
- package/dist/shared/tools/crop.js +0 -154
- package/dist/shared/tools/index.d.ts +0 -5
- package/dist/shared/tools/index.js +0 -5
- package/dist/shared/tools/sources.d.ts +0 -46
- package/dist/shared/tools/sources.js +0 -121
- package/dist/shared/tools/types.d.ts +0 -1
- package/shared/layers/Layers.svelte +0 -250
- package/shared/layers/utils.ts +0 -294
- package/shared/tools/Brush.svelte +0 -280
- package/shared/tools/BrushOptions.svelte +0 -180
- package/shared/tools/Crop.svelte +0 -189
- package/shared/tools/Cropper.svelte +0 -346
- package/shared/tools/Handle.svelte +0 -289
- package/shared/tools/Sources.svelte +0 -283
- package/shared/tools/Tools.svelte +0 -162
- package/shared/tools/brush.ts +0 -247
- package/shared/tools/crop.ts +0 -213
- package/shared/tools/index.ts +0 -5
- package/shared/tools/sources.ts +0 -195
- package/shared/tools/types.ts +0 -1
- /package/dist/shared/{tools → brush}/BrushSize.svelte.d.ts +0 -0
- /package/dist/shared/{tools/types.js → types.js} +0 -0
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# Image Tool Documentation
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The Image Tool is a component of the image editor that handles adding and managing background images on the canvas. It allows users to upload, paste, or capture images from a webcam and set them as the background of the editing canvas. The tool manages image sizing, positioning, and integration with the layer system.
|
|
6
|
+
|
|
7
|
+
## File Structure
|
|
8
|
+
|
|
9
|
+
- `js/imageeditor/shared/image/image.ts` - Main implementation of the image tool
|
|
10
|
+
- `js/imageeditor/shared/image/Sources.svelte` - UI component for image source options
|
|
11
|
+
- `js/imageeditor/shared/core/editor.ts` - Defines the `Tool` interface and `ImageEditorContext`
|
|
12
|
+
- `js/imageeditor/shared/Toolbar.svelte` - Defines the tool types and subtool types
|
|
13
|
+
|
|
14
|
+
## Implementation Details
|
|
15
|
+
|
|
16
|
+
### Class: `ImageTool`
|
|
17
|
+
|
|
18
|
+
The `ImageTool` class implements the `Tool` interface defined in `editor.ts`. It provides the following functionality:
|
|
19
|
+
|
|
20
|
+
- Adding images to the canvas
|
|
21
|
+
- Managing image dimensions and positioning
|
|
22
|
+
- Integrating with the layer system
|
|
23
|
+
|
|
24
|
+
### Key Components
|
|
25
|
+
|
|
26
|
+
#### `ImageTool` Class
|
|
27
|
+
|
|
28
|
+
The main class that implements the `Tool` interface with methods:
|
|
29
|
+
- `setup(context, tool, subtool)` - Initializes the tool with the editor context
|
|
30
|
+
- `cleanup()` - Cleans up resources
|
|
31
|
+
- `add_image(image, fixed_canvas)` - Adds an image to the canvas
|
|
32
|
+
- `set_tool(tool, subtool)` - Updates the current tool and subtool
|
|
33
|
+
|
|
34
|
+
#### `AddImageCommand` Class
|
|
35
|
+
|
|
36
|
+
Implements the command pattern for adding images, allowing for undo/redo functionality:
|
|
37
|
+
- `start()` - Initializes the image sprite and calculates dimensions
|
|
38
|
+
- `execute()` - Adds the image to the canvas and updates the editor state
|
|
39
|
+
- `undo()` - Removes the image from the canvas
|
|
40
|
+
|
|
41
|
+
#### Helper Functions
|
|
42
|
+
|
|
43
|
+
- `fit_image_to_canvas(image_width, image_height, canvas_width, canvas_height)` - Calculates dimensions to fit an image within the canvas while maintaining aspect ratio
|
|
44
|
+
- `add_bg_color(container, renderer, color, width, height, resize)` - Adds a solid color background to the canvas
|
|
45
|
+
|
|
46
|
+
### Image Processing Flow
|
|
47
|
+
|
|
48
|
+
1. **Image Acquisition**: The image is acquired as a Blob or File from one of the sources (upload, clipboard, webcam)
|
|
49
|
+
2. **Image Processing**:
|
|
50
|
+
- The image is converted to a bitmap and then to a PIXI.js Texture
|
|
51
|
+
- The dimensions are calculated based on whether fixed_canvas is true or false
|
|
52
|
+
- If fixed_canvas is true, the image is scaled to fit the canvas while maintaining aspect ratio
|
|
53
|
+
- If fixed_canvas is false, the canvas is resized to match the image dimensions
|
|
54
|
+
|
|
55
|
+
3. **Canvas Integration**:
|
|
56
|
+
- The editor's image properties are updated with the new dimensions
|
|
57
|
+
- Existing layers are preserved and scaled to match the new dimensions
|
|
58
|
+
- A new background layer is created with the image sprite
|
|
59
|
+
- The image is centered in the viewport
|
|
60
|
+
|
|
61
|
+
4. **Layer Management**:
|
|
62
|
+
- The image is added as a sprite to a background layer
|
|
63
|
+
- Existing layers are preserved and scaled to match the new dimensions
|
|
64
|
+
- If no layers exist, an initial drawing layer is created
|
|
65
|
+
|
|
66
|
+
## Command Pattern Implementation
|
|
67
|
+
|
|
68
|
+
The image tool uses the command pattern to implement undo/redo functionality:
|
|
69
|
+
|
|
70
|
+
1. **Command Creation**: When adding an image, an `AddImageCommand` is created
|
|
71
|
+
2. **Command Execution**: The command's `execute()` method is called to add the image
|
|
72
|
+
3. **Command Registration**: The command is registered with the editor's command manager
|
|
73
|
+
4. **Undo Support**: The command's `undo()` method can be called to remove the image
|
|
74
|
+
|
|
75
|
+
## Integration with Editor
|
|
76
|
+
|
|
77
|
+
The image tool integrates with the editor through the `ImageEditorContext` interface, which provides:
|
|
78
|
+
|
|
79
|
+
- `app` - The PIXI.js Application instance
|
|
80
|
+
- `layer_manager` - Manages the layers in the editor
|
|
81
|
+
- `set_image_properties` - Updates the image dimensions and position
|
|
82
|
+
- `set_background_image` - Sets the background image sprite
|
|
83
|
+
- `execute_command` - Registers a command with the command manager
|
|
84
|
+
|
|
85
|
+
## Usage Flow
|
|
86
|
+
|
|
87
|
+
1. The user selects an image source (upload, clipboard, webcam)
|
|
88
|
+
2. The image is acquired as a Blob or File
|
|
89
|
+
3. The `add_image` method is called with the image and a flag indicating whether to maintain the canvas size
|
|
90
|
+
4. An `AddImageCommand` is created and executed
|
|
91
|
+
5. The image is added to the canvas as a background layer
|
|
92
|
+
6. The editor's state is updated with the new dimensions and position
|
|
93
|
+
|
|
94
|
+
## Implementation Notes
|
|
95
|
+
|
|
96
|
+
### Image Scaling
|
|
97
|
+
|
|
98
|
+
The tool provides two modes for handling image dimensions:
|
|
99
|
+
|
|
100
|
+
1. **Fixed Canvas Mode** (fixed_canvas = true):
|
|
101
|
+
- The image is scaled to fit within the canvas dimensions
|
|
102
|
+
- The aspect ratio is maintained
|
|
103
|
+
- The canvas size remains unchanged
|
|
104
|
+
|
|
105
|
+
2. **Flexible Canvas Mode** (fixed_canvas = false):
|
|
106
|
+
- The canvas is resized to match the image dimensions
|
|
107
|
+
- No scaling is applied to the image
|
|
108
|
+
- Existing layers are scaled to match the new dimensions
|
|
109
|
+
|
|
110
|
+
### Layer Preservation
|
|
111
|
+
|
|
112
|
+
When adding a new background image:
|
|
113
|
+
|
|
114
|
+
1. Existing layers are preserved
|
|
115
|
+
2. Layer textures are captured before modification
|
|
116
|
+
3. New layers are created with the new dimensions
|
|
117
|
+
4. Content from old layers is scaled and centered on the new layers
|
|
118
|
+
5. If no layers exist, an initial drawing layer is created
|
|
119
|
+
|
|
120
|
+
## Maintenance Notes
|
|
121
|
+
|
|
122
|
+
When modifying the image tool, consider:
|
|
123
|
+
|
|
124
|
+
1. **Command Pattern**: Ensure that all modifications to the canvas state are implemented as commands for proper undo/redo support
|
|
125
|
+
2. **Layer Management**: Be careful with layer creation and destruction to avoid memory leaks
|
|
126
|
+
3. **Image Scaling**: Ensure that aspect ratios are maintained when scaling images
|
|
127
|
+
4. **Performance**: Large images may need to be downsampled for performance
|
|
128
|
+
5. **Memory Management**: Properly destroy textures and sprites when they are no longer needed
|
|
129
|
+
|
|
130
|
+
## Related Components
|
|
131
|
+
|
|
132
|
+
- **Toolbar**: Controls tool selection
|
|
133
|
+
- **ImageEditor**: Provides the context and manages the overall editor state
|
|
134
|
+
- **LayerManager**: Manages image layers
|
|
135
|
+
- **Sources.svelte**: Provides UI for selecting image sources
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Container,
|
|
3
|
+
Graphics,
|
|
4
|
+
Color,
|
|
5
|
+
type ColorSource,
|
|
6
|
+
RenderTexture,
|
|
7
|
+
Sprite,
|
|
8
|
+
type Renderer,
|
|
9
|
+
Texture
|
|
10
|
+
} from "pixi.js";
|
|
11
|
+
import { type ImageEditorContext, type Tool } from "../core/editor";
|
|
12
|
+
import { type Tool as ToolbarTool, type Subtool } from "../Toolbar.svelte";
|
|
13
|
+
import { type Command } from "../utils/commands";
|
|
14
|
+
import { make_graphics } from "../utils/pixi";
|
|
15
|
+
import { get } from "svelte/store";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Handles adding images to the editor
|
|
19
|
+
* Only a single image can be added at a time
|
|
20
|
+
* Adding an image removes the current image is one exists
|
|
21
|
+
*/
|
|
22
|
+
export class ImageTool implements Tool {
|
|
23
|
+
name = "image";
|
|
24
|
+
context!: ImageEditorContext;
|
|
25
|
+
current_tool!: ToolbarTool;
|
|
26
|
+
current_subtool!: Subtool;
|
|
27
|
+
async setup(
|
|
28
|
+
context: ImageEditorContext,
|
|
29
|
+
tool: ToolbarTool,
|
|
30
|
+
subtool: Subtool
|
|
31
|
+
): Promise<void> {
|
|
32
|
+
this.context = context;
|
|
33
|
+
this.current_tool = tool;
|
|
34
|
+
this.current_subtool = subtool;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
cleanup(): void {}
|
|
38
|
+
|
|
39
|
+
async add_image({
|
|
40
|
+
image,
|
|
41
|
+
fixed_canvas,
|
|
42
|
+
border_region = 0
|
|
43
|
+
}: {
|
|
44
|
+
image: Blob | File | Texture;
|
|
45
|
+
fixed_canvas: boolean;
|
|
46
|
+
border_region?: number;
|
|
47
|
+
}): Promise<void> {
|
|
48
|
+
const image_command = new AddImageCommand(
|
|
49
|
+
this.context,
|
|
50
|
+
image,
|
|
51
|
+
fixed_canvas,
|
|
52
|
+
border_region
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
await image_command.start();
|
|
56
|
+
this.context.execute_command(image_command);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
set_tool(tool: ToolbarTool, subtool: Subtool): void {
|
|
60
|
+
this.current_tool = tool;
|
|
61
|
+
this.current_subtool = subtool;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
interface BgImageCommand extends Command {
|
|
66
|
+
/**
|
|
67
|
+
* Initial setup for the bg command
|
|
68
|
+
* @returns
|
|
69
|
+
*/
|
|
70
|
+
start: () => Promise<[number, number]>;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export class AddImageCommand implements BgImageCommand {
|
|
74
|
+
sprite: Sprite;
|
|
75
|
+
fixed_canvas: boolean;
|
|
76
|
+
context: ImageEditorContext;
|
|
77
|
+
background: Blob | File | Texture;
|
|
78
|
+
current_canvas_size: { width: number; height: number };
|
|
79
|
+
current_scale: number;
|
|
80
|
+
current_position: { x: number; y: number };
|
|
81
|
+
border_region: number;
|
|
82
|
+
|
|
83
|
+
scaled_width!: number;
|
|
84
|
+
scaled_height!: number;
|
|
85
|
+
|
|
86
|
+
constructor(
|
|
87
|
+
context: ImageEditorContext,
|
|
88
|
+
background: Blob | File | Texture,
|
|
89
|
+
fixed_canvas: boolean,
|
|
90
|
+
border_region = 0
|
|
91
|
+
) {
|
|
92
|
+
this.context = context;
|
|
93
|
+
this.background = background;
|
|
94
|
+
this.fixed_canvas = fixed_canvas;
|
|
95
|
+
this.border_region = border_region;
|
|
96
|
+
this.current_canvas_size = get(this.context.dimensions);
|
|
97
|
+
this.current_scale = get(this.context.scale);
|
|
98
|
+
this.current_position = get(this.context.position);
|
|
99
|
+
this.sprite = new Sprite();
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
async start(): Promise<[number, number]> {
|
|
103
|
+
// Create the sprite from the blob
|
|
104
|
+
let image_texture: Texture;
|
|
105
|
+
if (this.background instanceof Texture) {
|
|
106
|
+
image_texture = this.background;
|
|
107
|
+
} else {
|
|
108
|
+
const img = await createImageBitmap(this.background);
|
|
109
|
+
image_texture = Texture.from(img);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
this.sprite = new Sprite(image_texture);
|
|
113
|
+
|
|
114
|
+
return this.handle_image();
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
private handle_image(): [number, number] {
|
|
118
|
+
// Handle fixed canvas differently when border region is present
|
|
119
|
+
if (this.fixed_canvas) {
|
|
120
|
+
// Calculate the effective canvas size accounting for border region
|
|
121
|
+
const effectiveCanvasWidth = Math.max(
|
|
122
|
+
this.current_canvas_size.width - this.border_region * 2,
|
|
123
|
+
10
|
|
124
|
+
);
|
|
125
|
+
const effectiveCanvasHeight = Math.max(
|
|
126
|
+
this.current_canvas_size.height - this.border_region * 2,
|
|
127
|
+
10
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
// Fit the image to the canvas while maintaining aspect ratio
|
|
131
|
+
|
|
132
|
+
const { width, height, x, y } = fit_image_to_canvas(
|
|
133
|
+
this.sprite.width,
|
|
134
|
+
this.sprite.height,
|
|
135
|
+
effectiveCanvasWidth,
|
|
136
|
+
effectiveCanvasHeight
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
this.sprite.width = width;
|
|
140
|
+
this.sprite.height = height;
|
|
141
|
+
|
|
142
|
+
// Center the image in the canvas
|
|
143
|
+
this.sprite.x = x + this.border_region;
|
|
144
|
+
this.sprite.y = y + this.border_region;
|
|
145
|
+
} else {
|
|
146
|
+
// For non-fixed canvas, use natural dimensions plus border
|
|
147
|
+
const width = this.sprite.width;
|
|
148
|
+
const height = this.sprite.height;
|
|
149
|
+
|
|
150
|
+
// Position at the border's offset from origin
|
|
151
|
+
this.sprite.x = this.border_region;
|
|
152
|
+
this.sprite.y = this.border_region;
|
|
153
|
+
|
|
154
|
+
return [width + this.border_region * 2, height + this.border_region * 2];
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return [this.current_canvas_size.width, this.current_canvas_size.height];
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
async execute(): Promise<void> {
|
|
161
|
+
// First ensure we have run start() to create the sprite and get dimensions
|
|
162
|
+
const [width, height] = await this.start();
|
|
163
|
+
|
|
164
|
+
// Update image properties with the original dimensions and center in viewport
|
|
165
|
+
this.context.set_image_properties({
|
|
166
|
+
scale: 1, // Start at 1:1 scale
|
|
167
|
+
position: {
|
|
168
|
+
x: this.context.app.screen.width / 2,
|
|
169
|
+
y: this.context.app.screen.height / 2
|
|
170
|
+
},
|
|
171
|
+
width: this.fixed_canvas ? this.current_canvas_size.width : width,
|
|
172
|
+
height: this.fixed_canvas ? this.current_canvas_size.height : height
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
// Create new background layer and add the sprite
|
|
176
|
+
const background_layer = this.context.layer_manager.create_background_layer(
|
|
177
|
+
this.fixed_canvas ? this.current_canvas_size.width : width,
|
|
178
|
+
this.fixed_canvas ? this.current_canvas_size.height : height
|
|
179
|
+
);
|
|
180
|
+
this.sprite.zIndex = 0;
|
|
181
|
+
background_layer.addChild(this.sprite);
|
|
182
|
+
|
|
183
|
+
// Resize and preserve content of existing layers
|
|
184
|
+
this.context.layer_manager.reset_layers(
|
|
185
|
+
this.fixed_canvas ? this.current_canvas_size.width : width,
|
|
186
|
+
this.fixed_canvas ? this.current_canvas_size.height : height,
|
|
187
|
+
true
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
this.context.set_background_image(this.sprite);
|
|
191
|
+
|
|
192
|
+
this.context.reset();
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
async undo(): Promise<void> {
|
|
196
|
+
if (this.sprite) {
|
|
197
|
+
this.sprite.destroy();
|
|
198
|
+
}
|
|
199
|
+
// The background layer will be automatically cleaned up when a new image is added
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Command that sets a background
|
|
205
|
+
*/
|
|
206
|
+
interface BgColorCommand extends Command {
|
|
207
|
+
/**
|
|
208
|
+
* Initial setup for the bg command
|
|
209
|
+
* @returns
|
|
210
|
+
*/
|
|
211
|
+
start: () => [number, number];
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Adds a background color to the canvas.
|
|
216
|
+
* @param container The container to add the image to.
|
|
217
|
+
* @param renderer The renderer to use for the image.
|
|
218
|
+
* @param color The background color to add.
|
|
219
|
+
* @param width The width of the background.
|
|
220
|
+
* @param height The height of the background.
|
|
221
|
+
* @param resize The function to resize the canvas.
|
|
222
|
+
* @returns A command that can be used to undo the action.
|
|
223
|
+
*/
|
|
224
|
+
export function add_bg_color(
|
|
225
|
+
container: Container,
|
|
226
|
+
renderer: Renderer,
|
|
227
|
+
color: ColorSource,
|
|
228
|
+
width: number,
|
|
229
|
+
height: number,
|
|
230
|
+
resize: (width: number, height: number) => void
|
|
231
|
+
): BgColorCommand {
|
|
232
|
+
let sprite: Sprite;
|
|
233
|
+
return {
|
|
234
|
+
start() {
|
|
235
|
+
container.removeChildren();
|
|
236
|
+
const graphics = make_graphics(1);
|
|
237
|
+
const texture = RenderTexture.create({
|
|
238
|
+
width,
|
|
239
|
+
height
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
renderer.render(graphics, { renderTexture: texture });
|
|
243
|
+
sprite = new Sprite(texture);
|
|
244
|
+
return [sprite.width, sprite.height];
|
|
245
|
+
},
|
|
246
|
+
async execute() {
|
|
247
|
+
resize(sprite.width, sprite.height);
|
|
248
|
+
sprite.zIndex = 1;
|
|
249
|
+
container.addChild(sprite);
|
|
250
|
+
},
|
|
251
|
+
undo() {
|
|
252
|
+
container.removeChildren();
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Calculates new dimensions and position for an image to fit within a canvas while maintaining aspect ratio
|
|
259
|
+
* @param image_width Original width of the image
|
|
260
|
+
* @param image_height Original height of the image
|
|
261
|
+
* @param canvas_width Width of the canvas
|
|
262
|
+
* @param canvas_height Height of the canvas
|
|
263
|
+
* @returns Object containing new dimensions and position
|
|
264
|
+
*/
|
|
265
|
+
export function fit_image_to_canvas(
|
|
266
|
+
image_width: number,
|
|
267
|
+
image_height: number,
|
|
268
|
+
canvas_width: number,
|
|
269
|
+
canvas_height: number
|
|
270
|
+
): {
|
|
271
|
+
width: number;
|
|
272
|
+
height: number;
|
|
273
|
+
x: number;
|
|
274
|
+
y: number;
|
|
275
|
+
} {
|
|
276
|
+
const image_aspect_ratio = image_width / image_height;
|
|
277
|
+
const canvas_aspect_ratio = canvas_width / canvas_height;
|
|
278
|
+
|
|
279
|
+
let new_width: number;
|
|
280
|
+
let new_height: number;
|
|
281
|
+
|
|
282
|
+
if (image_aspect_ratio > canvas_aspect_ratio) {
|
|
283
|
+
new_width = canvas_width;
|
|
284
|
+
new_height = canvas_width / image_aspect_ratio;
|
|
285
|
+
} else {
|
|
286
|
+
new_height = canvas_height;
|
|
287
|
+
new_width = canvas_height * image_aspect_ratio;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// center image
|
|
291
|
+
const x = Math.round((canvas_width - new_width) / 2);
|
|
292
|
+
const y = Math.round((canvas_height - new_height) / 2);
|
|
293
|
+
|
|
294
|
+
return {
|
|
295
|
+
width: Math.round(new_width),
|
|
296
|
+
height: Math.round(new_height),
|
|
297
|
+
x,
|
|
298
|
+
y
|
|
299
|
+
};
|
|
300
|
+
}
|