@gradio/imageeditor 0.12.13 → 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.
Files changed (130) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/Example.svelte +1 -1
  3. package/IMAGE_EDITOR_OVERVIEW.md +224 -0
  4. package/ImageEditor.stories.svelte +4 -4
  5. package/Index.svelte +35 -46
  6. package/{shared/InteractiveImageEditor.svelte → InteractiveImageEditor.svelte} +56 -103
  7. package/dist/Example.svelte.d.ts +1 -1
  8. package/dist/Index.svelte +29 -33
  9. package/dist/Index.svelte.d.ts +17 -16
  10. package/dist/{shared/InteractiveImageEditor.svelte → InteractiveImageEditor.svelte} +47 -88
  11. package/dist/{shared/InteractiveImageEditor.svelte.d.ts → InteractiveImageEditor.svelte.d.ts} +13 -15
  12. package/dist/shared/Anchor.svelte +311 -0
  13. package/dist/shared/Anchor.svelte.d.ts +18 -0
  14. package/dist/shared/Controls.svelte +162 -23
  15. package/dist/shared/Controls.svelte.d.ts +7 -2
  16. package/dist/shared/{tools/IconButton.svelte → IconButton.svelte} +19 -3
  17. package/dist/shared/{tools/IconButton.svelte.d.ts → IconButton.svelte.d.ts} +4 -1
  18. package/dist/shared/ImageEditor.svelte +546 -289
  19. package/dist/shared/ImageEditor.svelte.d.ts +51 -56
  20. package/dist/shared/Layers.svelte +233 -0
  21. package/dist/shared/Layers.svelte.d.ts +35 -0
  22. package/dist/shared/Resize.svelte +218 -0
  23. package/dist/shared/Resize.svelte.d.ts +29 -0
  24. package/dist/shared/SecondaryToolbar.svelte +54 -0
  25. package/dist/shared/SecondaryToolbar.svelte.d.ts +35 -0
  26. package/dist/shared/Toolbar.svelte +337 -0
  27. package/dist/shared/Toolbar.svelte.d.ts +42 -0
  28. package/dist/shared/{tools → brush}/BrushOptions.svelte +68 -64
  29. package/dist/shared/{tools → brush}/BrushOptions.svelte.d.ts +9 -9
  30. package/dist/shared/{tools → brush}/BrushSize.svelte +2 -27
  31. package/dist/shared/{tools → brush}/ColorField.svelte +2 -1
  32. package/dist/shared/{tools → brush}/ColorField.svelte.d.ts +1 -0
  33. package/dist/shared/{tools → brush}/ColorPicker.svelte +81 -9
  34. package/dist/shared/{tools → brush}/ColorPicker.svelte.d.ts +1 -0
  35. package/dist/shared/{tools → brush}/ColorSwatch.svelte +78 -38
  36. package/dist/shared/{tools → brush}/ColorSwatch.svelte.d.ts +6 -2
  37. package/dist/shared/brush/brush-cursor.d.ts +101 -0
  38. package/dist/shared/brush/brush-cursor.js +327 -0
  39. package/dist/shared/brush/brush-textures.d.ts +71 -0
  40. package/dist/shared/brush/brush-textures.js +404 -0
  41. package/dist/shared/brush/brush-utils.d.ts +32 -0
  42. package/dist/shared/brush/brush-utils.js +59 -0
  43. package/dist/shared/brush/brush.d.ts +152 -0
  44. package/dist/shared/brush/brush.js +396 -0
  45. package/dist/shared/brush/types.d.ts +37 -0
  46. package/dist/shared/brush/types.js +1 -0
  47. package/dist/shared/core/editor.d.ts +252 -0
  48. package/dist/shared/core/editor.js +1221 -0
  49. package/dist/shared/crop/crop.d.ts +201 -0
  50. package/dist/shared/crop/crop.js +727 -0
  51. package/dist/shared/image/image.d.ts +89 -0
  52. package/dist/shared/image/image.js +185 -0
  53. package/dist/shared/resize/resize.d.ts +270 -0
  54. package/dist/shared/resize/resize.js +1413 -0
  55. package/dist/shared/types.d.ts +12 -0
  56. package/dist/shared/utils/pixi.d.ts +16 -57
  57. package/dist/shared/utils/pixi.js +15 -113
  58. package/dist/shared/zoom/zoom.d.ts +136 -0
  59. package/dist/shared/zoom/zoom.js +548 -0
  60. package/package.json +11 -10
  61. package/shared/Anchor.svelte +384 -0
  62. package/shared/Controls.svelte +194 -27
  63. package/shared/{tools/IconButton.svelte → IconButton.svelte} +21 -4
  64. package/shared/ImageEditor.svelte +682 -349
  65. package/shared/Layers.svelte +249 -0
  66. package/shared/Resize.svelte +239 -0
  67. package/shared/SecondaryToolbar.svelte +61 -0
  68. package/shared/Toolbar.svelte +386 -0
  69. package/shared/brush/BRUSH_TOOL.md +134 -0
  70. package/shared/brush/BrushOptions.svelte +200 -0
  71. package/shared/{tools → brush}/BrushSize.svelte +2 -30
  72. package/shared/{tools → brush}/ColorField.svelte +3 -1
  73. package/shared/{tools → brush}/ColorPicker.svelte +86 -9
  74. package/shared/{tools → brush}/ColorSwatch.svelte +95 -42
  75. package/shared/brush/brush-cursor.ts +408 -0
  76. package/shared/brush/brush-textures.ts +508 -0
  77. package/shared/brush/brush-utils.ts +76 -0
  78. package/shared/brush/brush.ts +506 -0
  79. package/shared/brush/types.ts +41 -0
  80. package/shared/core/EDITOR.md +182 -0
  81. package/shared/core/editor.ts +1730 -0
  82. package/shared/crop/CROP.md +139 -0
  83. package/shared/crop/crop.ts +1027 -0
  84. package/shared/image/IMAGE.md +135 -0
  85. package/shared/image/image.ts +300 -0
  86. package/shared/resize/resize.ts +1894 -0
  87. package/shared/types.ts +14 -0
  88. package/shared/utils/pixi.ts +19 -246
  89. package/shared/zoom/zoom.ts +729 -0
  90. package/dist/shared/layers/Layers.svelte +0 -231
  91. package/dist/shared/layers/Layers.svelte.d.ts +0 -18
  92. package/dist/shared/layers/utils.d.ts +0 -73
  93. package/dist/shared/layers/utils.js +0 -156
  94. package/dist/shared/tools/Brush.svelte +0 -215
  95. package/dist/shared/tools/Brush.svelte.d.ts +0 -29
  96. package/dist/shared/tools/Crop.svelte +0 -155
  97. package/dist/shared/tools/Crop.svelte.d.ts +0 -16
  98. package/dist/shared/tools/Cropper.svelte +0 -271
  99. package/dist/shared/tools/Cropper.svelte.d.ts +0 -41
  100. package/dist/shared/tools/Handle.svelte +0 -260
  101. package/dist/shared/tools/Handle.svelte.d.ts +0 -29
  102. package/dist/shared/tools/Sources.svelte +0 -257
  103. package/dist/shared/tools/Sources.svelte.d.ts +0 -34
  104. package/dist/shared/tools/Tools.svelte +0 -102
  105. package/dist/shared/tools/Tools.svelte.d.ts +0 -48
  106. package/dist/shared/tools/brush.d.ts +0 -62
  107. package/dist/shared/tools/brush.js +0 -133
  108. package/dist/shared/tools/crop.d.ts +0 -15
  109. package/dist/shared/tools/crop.js +0 -154
  110. package/dist/shared/tools/index.d.ts +0 -5
  111. package/dist/shared/tools/index.js +0 -5
  112. package/dist/shared/tools/sources.d.ts +0 -46
  113. package/dist/shared/tools/sources.js +0 -121
  114. package/dist/shared/tools/types.d.ts +0 -1
  115. package/shared/layers/Layers.svelte +0 -250
  116. package/shared/layers/utils.ts +0 -294
  117. package/shared/tools/Brush.svelte +0 -280
  118. package/shared/tools/BrushOptions.svelte +0 -180
  119. package/shared/tools/Crop.svelte +0 -189
  120. package/shared/tools/Cropper.svelte +0 -346
  121. package/shared/tools/Handle.svelte +0 -289
  122. package/shared/tools/Sources.svelte +0 -283
  123. package/shared/tools/Tools.svelte +0 -162
  124. package/shared/tools/brush.ts +0 -247
  125. package/shared/tools/crop.ts +0 -213
  126. package/shared/tools/index.ts +0 -5
  127. package/shared/tools/sources.ts +0 -195
  128. package/shared/tools/types.ts +0 -1
  129. /package/dist/shared/{tools → brush}/BrushSize.svelte.d.ts +0 -0
  130. /package/dist/shared/{tools/types.js → types.js} +0 -0
@@ -1,280 +0,0 @@
1
- <script lang="ts" context="module">
2
- import { type ColorInput } from "tinycolor2";
3
-
4
- export interface Eraser {
5
- /**
6
- * The default size of the eraser.
7
- */
8
- default_size: number | "auto";
9
- }
10
-
11
- export interface Brush extends Eraser {
12
- /**
13
- * The default color of the brush.
14
- */
15
- default_color: ColorInput;
16
- /**
17
- * The colors to show in the color swatch
18
- */
19
- colors: ColorInput[];
20
- /**
21
- * Whether to show _only_ the color swatches specified in `colors`, or to show the color swatches specified in `colors` along with the colorpicker.
22
- */
23
- color_mode: "fixed" | "defaults";
24
- }
25
-
26
- type brush_option_type = boolean;
27
- </script>
28
-
29
- <script lang="ts">
30
- import tinycolor from "tinycolor2";
31
- import { clamp } from "../utils/pixi";
32
-
33
- import { getContext, onMount, tick } from "svelte";
34
- import { type ToolContext, TOOL_KEY } from "./Tools.svelte";
35
- import { type EditorContext, EDITOR_KEY } from "../ImageEditor.svelte";
36
- import { draw_path, type DrawCommand } from "./brush";
37
- import BrushOptions from "./BrushOptions.svelte";
38
- import type { FederatedPointerEvent } from "pixi.js";
39
-
40
- export let default_size: Brush["default_size"];
41
- export let default_color: Brush["default_color"] | undefined = undefined;
42
- export let colors: Brush["colors"] | undefined = undefined;
43
- export let color_mode: Brush["color_mode"] | undefined = undefined;
44
- export let mode: "erase" | "draw";
45
-
46
- let processed_colors: string[] = [];
47
- let old_colors: string[] = [];
48
- if (colors && JSON.stringify(old_colors) !== JSON.stringify(colors)) {
49
- processed_colors = colors.map(process_color).filter((_, i) => i < 4);
50
- old_colors = processed_colors;
51
- }
52
-
53
- let selected_color = process_color(default_color || "#000000");
54
-
55
- $: if (mode === "draw") {
56
- current_color.set(selected_color);
57
- }
58
-
59
- let brush_options: brush_option_type = false;
60
-
61
- const {
62
- pixi,
63
- dimensions,
64
- current_layer,
65
- command_manager,
66
- register_context,
67
- editor_box,
68
- crop,
69
- toolbar_box
70
- } = getContext<EditorContext>(EDITOR_KEY);
71
-
72
- const { active_tool, register_tool, current_color } =
73
- getContext<ToolContext>(TOOL_KEY);
74
-
75
- let drawing = false;
76
- let draw: DrawCommand;
77
-
78
- function generate_sizes(x: number, y: number): number {
79
- const min = clamp(Math.min(x, y), 500, 1000);
80
-
81
- return Math.round((min * 2) / 100);
82
- }
83
-
84
- $: mode === "draw" && current_color.set(selected_color);
85
-
86
- let selected_size =
87
- default_size === "auto" ? generate_sizes(...$dimensions) : default_size;
88
-
89
- function pointer_down_handler(event: FederatedPointerEvent): void {
90
- if ($active_tool !== mode) {
91
- return;
92
- }
93
- drawing = true;
94
-
95
- if (!$pixi || !$current_layer) {
96
- return;
97
- }
98
-
99
- draw = draw_path(
100
- $pixi.renderer!,
101
- $pixi.layer_container,
102
- $current_layer,
103
- mode
104
- );
105
-
106
- draw.start({
107
- x: event.screen.x,
108
- y: event.screen.y,
109
- color: selected_color || undefined,
110
- size: selected_size,
111
- opacity: 1
112
- });
113
- }
114
-
115
- function pointer_up_handler(event: FederatedPointerEvent): void {
116
- if (!$pixi || !$current_layer) {
117
- return;
118
- }
119
- if ($active_tool !== mode) {
120
- return;
121
- }
122
- draw.stop();
123
- command_manager.execute(draw);
124
- drawing = false;
125
- }
126
-
127
- function pointer_move_handler(event: FederatedPointerEvent): void {
128
- if ($active_tool !== mode) {
129
- return;
130
- }
131
- if (drawing) {
132
- draw.continue({
133
- x: event.screen.x,
134
- y: event.screen.y
135
- });
136
- }
137
-
138
- const x_bound = $crop[0] * $dimensions[0];
139
- const y_bound = $crop[1] * $dimensions[1];
140
-
141
- if (
142
- x_bound > event.screen.x ||
143
- y_bound > event.screen.y ||
144
- event.screen.x > x_bound + $crop[2] * $dimensions[0] ||
145
- event.screen.y > y_bound + $crop[3] * $dimensions[1]
146
- ) {
147
- brush_cursor = false;
148
- document.body.style.cursor = "auto";
149
- } else {
150
- brush_cursor = true;
151
- document.body.style.cursor = "none";
152
- }
153
- if (brush_cursor) {
154
- pos = {
155
- x: event.clientX - $editor_box.child_left,
156
- y: event.clientY - $editor_box.child_top
157
- };
158
- }
159
- }
160
-
161
- let brush_cursor = false;
162
-
163
- async function toggle_listeners(on_off: "on" | "off"): Promise<void> {
164
- $pixi?.layer_container[on_off]("pointerdown", pointer_down_handler);
165
-
166
- $pixi?.layer_container[on_off]("pointerup", pointer_up_handler);
167
-
168
- $pixi?.layer_container[on_off]("pointermove", pointer_move_handler);
169
- $pixi?.layer_container[on_off](
170
- "pointerenter",
171
- (event: FederatedPointerEvent) => {
172
- if ($active_tool === mode) {
173
- brush_cursor = true;
174
- document.body.style.cursor = "none";
175
- }
176
- }
177
- );
178
- $pixi?.layer_container[on_off](
179
- "pointerleave",
180
- () => ((brush_cursor = false), (document.body.style.cursor = "auto"))
181
- );
182
- }
183
-
184
- register_context(mode, {
185
- init_fn: () => {
186
- toggle_listeners("on");
187
- },
188
- reset_fn: () => {
189
- toggle_listeners("off");
190
- }
191
- });
192
- const toggle_options = debounce_toggle();
193
-
194
- const unregister = register_tool(mode, {
195
- cb: toggle_options
196
- });
197
- onMount(() => {
198
- return () => {
199
- unregister();
200
- toggle_listeners("off");
201
- };
202
- });
203
-
204
- let recent_colors: (string | null)[] = [null, null, null];
205
-
206
- function process_color(color: ColorInput): string {
207
- return tinycolor(color).toRgbString();
208
- }
209
-
210
- let pos = { x: 0, y: 0 };
211
- $: brush_size =
212
- (selected_size / $dimensions[0]) * $editor_box.child_width * 2;
213
-
214
- function debounce_toggle(): (should_close?: boolean) => void {
215
- let timeout: NodeJS.Timeout | null = null;
216
-
217
- return function executedFunction(should_close?: boolean) {
218
- const later = (): void => {
219
- if (timeout) {
220
- clearTimeout(timeout);
221
- }
222
- if (should_close !== undefined) {
223
- brush_options = should_close;
224
- return;
225
- }
226
- brush_options = !brush_options;
227
- };
228
-
229
- if (timeout) {
230
- clearTimeout(timeout);
231
- }
232
- timeout = setTimeout(later, 100);
233
- };
234
- }
235
- </script>
236
-
237
- <svelte:window
238
- on:keydown={({ key }) => key === "Escape" && toggle_options(false)}
239
- />
240
-
241
- <span
242
- style:transform="translate({pos.x}px, {pos.y}px)"
243
- style:top="{$editor_box.child_top -
244
- $editor_box.parent_top -
245
- brush_size / 2}px"
246
- style:left="{$editor_box.child_left -
247
- $editor_box.parent_left -
248
- brush_size / 2}px"
249
- style:width="{brush_size}px"
250
- style:height="{brush_size}px"
251
- style:opacity={brush_cursor ? 1 : 0}
252
- />
253
-
254
- {#if brush_options}
255
- <div>
256
- <BrushOptions
257
- show_swatch={mode === "draw"}
258
- on:click_outside={() => toggle_options()}
259
- colors={processed_colors}
260
- bind:selected_color
261
- {color_mode}
262
- bind:recent_colors
263
- bind:selected_size
264
- dimensions={$dimensions}
265
- parent_width={$editor_box.parent_width}
266
- parent_height={$editor_box.parent_height}
267
- parent_left={$editor_box.parent_left}
268
- toolbar_box={$toolbar_box}
269
- />
270
- </div>
271
- {/if}
272
-
273
- <style>
274
- span {
275
- position: absolute;
276
- background: rgba(0, 0, 0, 0.5);
277
- pointer-events: none;
278
- border-radius: 50%;
279
- }
280
- </style>
@@ -1,180 +0,0 @@
1
- <script lang="ts">
2
- import { createEventDispatcher } from "svelte";
3
- import { click_outside } from "../utils/events";
4
-
5
- import { type Brush } from "./Brush.svelte";
6
- import ColorPicker from "./ColorPicker.svelte";
7
- import ColorSwatch from "./ColorSwatch.svelte";
8
- import ColorField from "./ColorField.svelte";
9
- import BrushSize from "./BrushSize.svelte";
10
-
11
- export let colors: string[];
12
- export let selected_color: string;
13
- export let color_mode: Brush["color_mode"] | undefined = undefined;
14
- export let recent_colors: (string | null)[] = [];
15
- export let selected_size: number;
16
- export let dimensions: [number, number];
17
- export let parent_width: number;
18
- export let parent_height: number;
19
- export let parent_left: number;
20
- export let toolbar_box: DOMRect | Record<string, never>;
21
- export let show_swatch: boolean;
22
-
23
- let color_picker = false;
24
- let current_mode: "hex" | "rgb" | "hsl" = "hex";
25
- let editing_index: number | null = null;
26
-
27
- const dispatch = createEventDispatcher<{
28
- click_outside: void;
29
- }>();
30
-
31
- function handle_color_selection(
32
- {
33
- index,
34
- color
35
- }: {
36
- index: number | null;
37
- color: string | null;
38
- },
39
- type: "core" | "user"
40
- ): void {
41
- if (type === "user" && !color) {
42
- editing_index = index;
43
- color_picker = true;
44
- }
45
-
46
- if (!color) return;
47
- selected_color = color;
48
-
49
- if (type === "core") {
50
- color_picker = false;
51
- }
52
- }
53
-
54
- function handle_color_change(color: string): void {
55
- if (editing_index === null) return;
56
- recent_colors[editing_index] = color;
57
- }
58
-
59
- $: handle_color_change(selected_color);
60
- let width = 0;
61
- let height = 0;
62
- let c_width = 0;
63
- let c_height = 0;
64
- let wrap_el: HTMLDivElement;
65
- let full_screen = false;
66
- let anchor: "default" | "center" | "top" = "default";
67
- let left_anchor = 0;
68
- let top_anchor = null;
69
- $: {
70
- if (wrap_el && (width || height || c_height || c_width)) {
71
- const box = wrap_el.getBoundingClientRect();
72
- color_picker;
73
-
74
- if (box.width > parent_width) {
75
- full_screen = true;
76
- } else if (parent_width > box.width + 230 * 2 + 25) {
77
- anchor = "default";
78
-
79
- left_anchor = toolbar_box.right - parent_left + 24;
80
- } else {
81
- anchor = "center";
82
- }
83
-
84
- if (box.height + 50 > parent_height) {
85
- anchor = "top";
86
- top_anchor = true;
87
- }
88
- }
89
- }
90
- </script>
91
-
92
- <svelte:window bind:innerHeight={height} bind:innerWidth={width} />
93
-
94
- <div
95
- class="wrap"
96
- class:padded={!color_picker}
97
- use:click_outside={() => dispatch("click_outside")}
98
- class:anchor_default={anchor === "default"}
99
- class:anchor_center={anchor === "center"}
100
- class:anchor_top={anchor === "top"}
101
- bind:this={wrap_el}
102
- bind:clientWidth={c_width}
103
- bind:clientHeight={c_height}
104
- class:anchor={`${left_anchor}px`}
105
- >
106
- {#if color_mode === "defaults"}
107
- {#if color_picker}
108
- <ColorPicker bind:color={selected_color} />
109
- <ColorField
110
- bind:current_mode
111
- color={selected_color}
112
- on:close={() => (color_picker = false)}
113
- on:selected={({ detail }) => (selected_color = detail)}
114
- />
115
- {/if}
116
- {/if}
117
- {#if show_swatch}
118
- <ColorSwatch
119
- bind:color_picker
120
- {colors}
121
- on:select={({ detail }) => handle_color_selection(detail, "core")}
122
- on:edit={({ detail }) => handle_color_selection(detail, "user")}
123
- user_colors={color_mode === "defaults" ? recent_colors : null}
124
- {selected_color}
125
- {current_mode}
126
- />
127
- {/if}
128
-
129
- {#if color_picker || show_swatch}
130
- <div class="sep"></div>
131
- {/if}
132
-
133
- <BrushSize max={dimensions[0] / 10} min={1} bind:selected_size />
134
- </div>
135
-
136
- <style>
137
- .wrap {
138
- max-width: 230px;
139
- width: 90%;
140
- position: absolute;
141
- display: flex;
142
- flex-direction: column;
143
- gap: 5px;
144
- background: var(--background-fill-secondary);
145
- border: 1px solid var(--block-border-color);
146
- border-radius: var(--radius-md);
147
- box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.1);
148
- padding-bottom: var(--size-2);
149
- pointer-events: all;
150
- cursor: default;
151
- z-index: var(--layer-top);
152
- overflow: hidden;
153
- }
154
-
155
- .anchor_default {
156
- position: absolute;
157
- left: var(--left-anchor);
158
- bottom: 8px;
159
- }
160
- .anchor_center {
161
- position: absolute;
162
- bottom: 50px;
163
- left: 50%;
164
- transform: translateX(-50%);
165
- }
166
-
167
- .anchor_top {
168
- position: absolute;
169
- top: 1px;
170
- left: 50%;
171
- transform: translateX(-50%);
172
- }
173
-
174
- .sep {
175
- height: 1px;
176
- background-color: var(--block-border-color);
177
- margin: 0 var(--size-3);
178
- margin-top: var(--size-1);
179
- }
180
- </style>
@@ -1,189 +0,0 @@
1
- <script lang="ts">
2
- import { getContext, onDestroy, onMount, tick } from "svelte";
3
-
4
- import { type ToolContext, TOOL_KEY } from "./Tools.svelte";
5
- import { type EditorContext, EDITOR_KEY } from "../ImageEditor.svelte";
6
- import { crop_canvas, resize_and_reposition, type CropCommand } from "./crop";
7
-
8
- import Cropper from "./Cropper.svelte";
9
-
10
- const { active_tool, register_tool } = getContext<ToolContext>(TOOL_KEY);
11
- const {
12
- dimensions,
13
- editor_box,
14
- pixi,
15
- crop,
16
- command_manager,
17
- current_history
18
- } = getContext<EditorContext>(EDITOR_KEY);
19
-
20
- let cropper: CropCommand | null;
21
-
22
- export let crop_constraint: [number, number] | `${string}:${string}` | null;
23
-
24
- let _crop_constraint: number | null = null;
25
- $: {
26
- if (typeof crop_constraint === "string") {
27
- const [w, h] = crop_constraint.split(":");
28
- _crop_constraint = parseInt(w) / parseInt(h);
29
- } else if (Array.isArray(crop_constraint)) {
30
- _crop_constraint = crop_constraint[0] / crop_constraint[1];
31
- }
32
- }
33
-
34
- let w_p = 1;
35
- let h_p = 1;
36
- let l_p = 0;
37
- let t_p = 0;
38
-
39
- let current_opacity = 0;
40
-
41
- let manually_cropped = false;
42
-
43
- $: {
44
- if (!manually_cropped && _crop_constraint && $pixi && $active_tool) {
45
- requestAnimationFrame(() => {
46
- initial_crop();
47
- });
48
- }
49
- }
50
-
51
- let c: CropCommand | null = null;
52
-
53
- async function initial_crop(): Promise<void> {
54
- if (c || $current_history.previous) return;
55
- const { new_height, new_width, x_offset, y_offset } = resize_and_reposition(
56
- $editor_box.child_width,
57
- $editor_box.child_height,
58
- "c",
59
- _crop_constraint!,
60
-
61
- $editor_box.child_width,
62
- $editor_box.child_height
63
- );
64
-
65
- w_p = new_width / $editor_box.child_width;
66
- h_p = new_height / $editor_box.child_height;
67
- l_p = x_offset / $editor_box.child_width;
68
- t_p = y_offset / $editor_box.child_height;
69
-
70
- c = crop_canvas($pixi!.renderer, $pixi!.background_container, crop, 0.2);
71
- c.start(...$dimensions, current_crop, false);
72
-
73
- c.continue(
74
- [
75
- l_p * $dimensions[0],
76
- t_p * $dimensions[1],
77
- w_p * $dimensions[0],
78
- h_p * $dimensions[1]
79
- ],
80
- false
81
- );
82
- c.stop();
83
-
84
- c.execute();
85
- c = null;
86
- current_opacity = 0;
87
- }
88
-
89
- function handle_crop(
90
- type: "start" | "stop" | "continue",
91
-
92
- {
93
- x,
94
- y,
95
- width,
96
- height
97
- }: {
98
- x: number;
99
- y: number;
100
- width: number;
101
- height: number;
102
- }
103
- ): void {
104
- if (!$pixi) return;
105
-
106
- if (type === "start") {
107
- if (cropper) {
108
- current_opacity = cropper.stop();
109
- cropper = null;
110
- }
111
-
112
- cropper = crop_canvas(
113
- $pixi?.renderer,
114
- $pixi.background_container,
115
- crop,
116
- current_opacity
117
- );
118
- cropper.start(...$dimensions, current_crop);
119
- } else if (type === "continue") {
120
- if (!cropper) return;
121
- cropper.continue([
122
- x * $dimensions[0],
123
- y * $dimensions[1],
124
- width * $dimensions[0],
125
- height * $dimensions[1]
126
- ]);
127
- } else if (type === "stop") {
128
- if (!cropper) return;
129
- command_manager.execute(cropper);
130
- }
131
- manually_cropped = true;
132
- }
133
-
134
- let measured = false;
135
-
136
- function get_measurements(): void {
137
- if (measured) return;
138
- if (!$editor_box.child_height) return;
139
- const _height = $editor_box.child_height;
140
- const _width = $editor_box.child_width;
141
- const _top = $editor_box.child_top - $editor_box.parent_top;
142
- const _left = $editor_box.child_left - $editor_box.parent_left;
143
-
144
- w_p = _width / $editor_box.child_width;
145
- h_p = _height / $editor_box.child_height;
146
- l_p =
147
- (_left - $editor_box.child_left + $editor_box.parent_left) /
148
- $editor_box.child_width;
149
- t_p =
150
- (_top - $editor_box.child_top + $editor_box.parent_top) /
151
- $editor_box.child_height;
152
-
153
- measured = true;
154
- }
155
-
156
- let current_crop: [number, number, number, number];
157
- $: current_crop = [
158
- l_p * $dimensions[0],
159
- t_p * $dimensions[1],
160
- w_p * $dimensions[0],
161
- h_p * $dimensions[1]
162
- ];
163
-
164
- $: {
165
- l_p = $crop[0];
166
- t_p = $crop[1];
167
- w_p = $crop[2];
168
- h_p = $crop[3];
169
- }
170
-
171
- $: $editor_box && get_measurements();
172
-
173
- const unregister = register_tool("crop");
174
- onDestroy(unregister);
175
- </script>
176
-
177
- {#if $active_tool === "crop" && measured}
178
- <Cropper
179
- crop_constraint={_crop_constraint}
180
- {w_p}
181
- {h_p}
182
- {l_p}
183
- {t_p}
184
- {editor_box}
185
- on:crop_start={({ detail }) => handle_crop("start", detail)}
186
- on:crop_continue={({ detail }) => handle_crop("continue", detail)}
187
- on:crop_end={({ detail }) => handle_crop("stop", detail)}
188
- />
189
- {/if}