@gradio/imageeditor 0.12.14 → 0.14.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 (131) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/Example.svelte +1 -1
  3. package/IMAGE_EDITOR_OVERVIEW.md +224 -0
  4. package/ImageEditor.stories.svelte +13 -5
  5. package/Index.svelte +46 -45
  6. package/{shared/InteractiveImageEditor.svelte → InteractiveImageEditor.svelte} +65 -103
  7. package/README.md +2 -0
  8. package/dist/Example.svelte.d.ts +1 -1
  9. package/dist/Index.svelte +35 -33
  10. package/dist/Index.svelte.d.ts +25 -16
  11. package/dist/{shared/InteractiveImageEditor.svelte → InteractiveImageEditor.svelte} +54 -88
  12. package/dist/{shared/InteractiveImageEditor.svelte.d.ts → InteractiveImageEditor.svelte.d.ts} +17 -15
  13. package/dist/shared/Anchor.svelte +311 -0
  14. package/dist/shared/Anchor.svelte.d.ts +18 -0
  15. package/dist/shared/Controls.svelte +169 -18
  16. package/dist/shared/Controls.svelte.d.ts +9 -2
  17. package/dist/shared/{tools/IconButton.svelte → IconButton.svelte} +19 -3
  18. package/dist/shared/{tools/IconButton.svelte.d.ts → IconButton.svelte.d.ts} +4 -1
  19. package/dist/shared/ImageEditor.svelte +572 -289
  20. package/dist/shared/ImageEditor.svelte.d.ts +54 -56
  21. package/dist/shared/Layers.svelte +260 -0
  22. package/dist/shared/Layers.svelte.d.ts +37 -0
  23. package/dist/shared/Resize.svelte +218 -0
  24. package/dist/shared/Resize.svelte.d.ts +29 -0
  25. package/dist/shared/SecondaryToolbar.svelte +55 -0
  26. package/dist/shared/SecondaryToolbar.svelte.d.ts +37 -0
  27. package/dist/shared/Toolbar.svelte +337 -0
  28. package/dist/shared/Toolbar.svelte.d.ts +42 -0
  29. package/dist/shared/{tools → brush}/BrushOptions.svelte +68 -64
  30. package/dist/shared/{tools → brush}/BrushOptions.svelte.d.ts +9 -9
  31. package/dist/shared/{tools → brush}/BrushSize.svelte +2 -27
  32. package/dist/shared/{tools → brush}/ColorField.svelte +2 -1
  33. package/dist/shared/{tools → brush}/ColorField.svelte.d.ts +1 -0
  34. package/dist/shared/{tools → brush}/ColorPicker.svelte +81 -9
  35. package/dist/shared/{tools → brush}/ColorPicker.svelte.d.ts +1 -0
  36. package/dist/shared/{tools → brush}/ColorSwatch.svelte +78 -38
  37. package/dist/shared/{tools → brush}/ColorSwatch.svelte.d.ts +6 -2
  38. package/dist/shared/brush/brush-cursor.d.ts +101 -0
  39. package/dist/shared/brush/brush-cursor.js +327 -0
  40. package/dist/shared/brush/brush-textures.d.ts +65 -0
  41. package/dist/shared/brush/brush-textures.js +385 -0
  42. package/dist/shared/brush/brush-utils.d.ts +32 -0
  43. package/dist/shared/brush/brush-utils.js +59 -0
  44. package/dist/shared/brush/brush.d.ts +152 -0
  45. package/dist/shared/brush/brush.js +397 -0
  46. package/dist/shared/brush/types.d.ts +37 -0
  47. package/dist/shared/brush/types.js +1 -0
  48. package/dist/shared/core/editor.d.ts +261 -0
  49. package/dist/shared/core/editor.js +1264 -0
  50. package/dist/shared/crop/crop.d.ts +201 -0
  51. package/dist/shared/crop/crop.js +727 -0
  52. package/dist/shared/image/image.d.ts +89 -0
  53. package/dist/shared/image/image.js +183 -0
  54. package/dist/shared/resize/resize.d.ts +270 -0
  55. package/dist/shared/resize/resize.js +1413 -0
  56. package/dist/shared/types.d.ts +16 -0
  57. package/dist/shared/utils/pixi.d.ts +16 -57
  58. package/dist/shared/utils/pixi.js +15 -113
  59. package/dist/shared/zoom/zoom.d.ts +136 -0
  60. package/dist/shared/zoom/zoom.js +548 -0
  61. package/package.json +8 -7
  62. package/shared/Anchor.svelte +384 -0
  63. package/shared/Controls.svelte +178 -37
  64. package/shared/{tools/IconButton.svelte → IconButton.svelte} +21 -4
  65. package/shared/ImageEditor.svelte +712 -350
  66. package/shared/Layers.svelte +282 -0
  67. package/shared/Resize.svelte +239 -0
  68. package/shared/SecondaryToolbar.svelte +67 -0
  69. package/shared/Toolbar.svelte +386 -0
  70. package/shared/brush/BRUSH_TOOL.md +134 -0
  71. package/shared/brush/BrushOptions.svelte +200 -0
  72. package/shared/{tools → brush}/BrushSize.svelte +2 -30
  73. package/shared/{tools → brush}/ColorField.svelte +3 -1
  74. package/shared/{tools → brush}/ColorPicker.svelte +86 -9
  75. package/shared/{tools → brush}/ColorSwatch.svelte +95 -42
  76. package/shared/brush/brush-cursor.ts +408 -0
  77. package/shared/brush/brush-textures.ts +485 -0
  78. package/shared/brush/brush-utils.ts +76 -0
  79. package/shared/brush/brush.ts +510 -0
  80. package/shared/brush/types.ts +41 -0
  81. package/shared/core/EDITOR.md +182 -0
  82. package/shared/core/editor.ts +1788 -0
  83. package/shared/crop/CROP.md +139 -0
  84. package/shared/crop/crop.ts +1027 -0
  85. package/shared/image/IMAGE.md +135 -0
  86. package/shared/image/image.ts +298 -0
  87. package/shared/resize/resize.ts +1894 -0
  88. package/shared/types.ts +19 -0
  89. package/shared/utils/pixi.ts +19 -246
  90. package/shared/zoom/zoom.ts +729 -0
  91. package/dist/shared/layers/Layers.svelte +0 -231
  92. package/dist/shared/layers/Layers.svelte.d.ts +0 -18
  93. package/dist/shared/layers/utils.d.ts +0 -73
  94. package/dist/shared/layers/utils.js +0 -156
  95. package/dist/shared/tools/Brush.svelte +0 -215
  96. package/dist/shared/tools/Brush.svelte.d.ts +0 -29
  97. package/dist/shared/tools/Crop.svelte +0 -155
  98. package/dist/shared/tools/Crop.svelte.d.ts +0 -16
  99. package/dist/shared/tools/Cropper.svelte +0 -271
  100. package/dist/shared/tools/Cropper.svelte.d.ts +0 -41
  101. package/dist/shared/tools/Handle.svelte +0 -260
  102. package/dist/shared/tools/Handle.svelte.d.ts +0 -29
  103. package/dist/shared/tools/Sources.svelte +0 -257
  104. package/dist/shared/tools/Sources.svelte.d.ts +0 -34
  105. package/dist/shared/tools/Tools.svelte +0 -102
  106. package/dist/shared/tools/Tools.svelte.d.ts +0 -48
  107. package/dist/shared/tools/brush.d.ts +0 -62
  108. package/dist/shared/tools/brush.js +0 -133
  109. package/dist/shared/tools/crop.d.ts +0 -15
  110. package/dist/shared/tools/crop.js +0 -154
  111. package/dist/shared/tools/index.d.ts +0 -5
  112. package/dist/shared/tools/index.js +0 -5
  113. package/dist/shared/tools/sources.d.ts +0 -46
  114. package/dist/shared/tools/sources.js +0 -121
  115. package/dist/shared/tools/types.d.ts +0 -1
  116. package/shared/layers/Layers.svelte +0 -250
  117. package/shared/layers/utils.ts +0 -294
  118. package/shared/tools/Brush.svelte +0 -280
  119. package/shared/tools/BrushOptions.svelte +0 -180
  120. package/shared/tools/Crop.svelte +0 -189
  121. package/shared/tools/Cropper.svelte +0 -346
  122. package/shared/tools/Handle.svelte +0 -289
  123. package/shared/tools/Sources.svelte +0 -283
  124. package/shared/tools/Tools.svelte +0 -162
  125. package/shared/tools/brush.ts +0 -247
  126. package/shared/tools/crop.ts +0 -213
  127. package/shared/tools/index.ts +0 -5
  128. package/shared/tools/sources.ts +0 -195
  129. package/shared/tools/types.ts +0 -1
  130. /package/dist/shared/{tools → brush}/BrushSize.svelte.d.ts +0 -0
  131. /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}