@gradio/image 0.3.0-beta.7 → 0.3.0-beta.9

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.
@@ -1,624 +0,0 @@
1
- <script>
2
- // @ts-nocheck
3
- /* eslint-disable */
4
-
5
- import { onMount, onDestroy, createEventDispatcher, tick } from "svelte";
6
- import { fade } from "svelte/transition";
7
- import { LazyBrush } from "lazy-brush/src";
8
- import ResizeObserver from "resize-observer-polyfill";
9
-
10
- const dispatch = createEventDispatcher();
11
-
12
- export let value;
13
- export let value_img;
14
- export let mode = "sketch";
15
- export let brush_color = "#0b0f19";
16
- export let brush_radius;
17
- export let mask_opacity = 0.7;
18
- export let source;
19
-
20
- export let width = 400;
21
- export let height = 200;
22
- export let container_height = 200;
23
- export let shape;
24
-
25
- $: {
26
- if (shape && (width || height)) {
27
- width = shape[0];
28
- height = shape[1];
29
- }
30
- }
31
-
32
- let mounted;
33
-
34
- let catenary_color = "#aaa";
35
-
36
- let canvas_width = width;
37
- let canvas_height = height;
38
-
39
- $: mounted && !value && clear();
40
-
41
- let last_value_img;
42
-
43
- $: {
44
- if (mounted && value_img !== last_value_img) {
45
- last_value_img = value_img;
46
-
47
- clear();
48
-
49
- setTimeout(() => {
50
- if (source === "webcam") {
51
- ctx.temp.save();
52
- ctx.temp.translate(width, 0);
53
- ctx.temp.scale(-1, 1);
54
- ctx.temp.drawImage(value_img, 0, 0);
55
- ctx.temp.restore();
56
- } else {
57
- draw_cropped_image();
58
- }
59
-
60
- ctx.drawing.drawImage(canvas.temp, 0, 0, width, height);
61
-
62
- draw_lines({ lines: lines.slice() });
63
- trigger_on_change();
64
- }, 50);
65
- }
66
- }
67
-
68
- function mid_point(p1, p2) {
69
- return {
70
- x: p1.x + (p2.x - p1.x) / 2,
71
- y: p1.y + (p2.y - p1.y) / 2
72
- };
73
- }
74
-
75
- const canvas_types = [
76
- {
77
- name: "interface",
78
- zIndex: 15
79
- },
80
- {
81
- name: "mask",
82
- zIndex: 13,
83
- opacity: mask_opacity
84
- },
85
- {
86
- name: "drawing",
87
- zIndex: 11
88
- },
89
- {
90
- name: "temp",
91
- zIndex: 12
92
- }
93
- ];
94
-
95
- let canvas = {};
96
- let ctx = {};
97
- let points = [];
98
- let lines = [];
99
- let mouse_has_moved = true;
100
- let values_changed = true;
101
- let is_drawing = false;
102
- let is_pressing = false;
103
- let lazy = null;
104
- let canvas_container = null;
105
- let canvas_observer = null;
106
- let line_count = 0;
107
-
108
- function draw_cropped_image() {
109
- if (!shape) {
110
- ctx.temp.drawImage(value_img, 0, 0, width, height);
111
- return;
112
- }
113
-
114
- let _width = value_img.naturalWidth;
115
- let _height = value_img.naturalHeight;
116
-
117
- const shape_ratio = shape[0] / shape[1];
118
- const image_ratio = _width / _height;
119
-
120
- let x = 0;
121
- let y = 0;
122
-
123
- if (shape_ratio < image_ratio) {
124
- _width = shape[1] * image_ratio;
125
- _height = shape[1];
126
- x = (shape[0] - _width) / 2;
127
- } else if (shape_ratio > image_ratio) {
128
- _width = shape[0];
129
- _height = shape[0] / image_ratio;
130
- y = (shape[1] - _height) / 2;
131
- } else {
132
- x = 0;
133
- y = 0;
134
- _width = shape[0];
135
- _height = shape[1];
136
- }
137
-
138
- ctx.temp.drawImage(value_img, x, y, _width, _height);
139
- }
140
-
141
- onMount(async () => {
142
- Object.keys(canvas).forEach((key) => {
143
- ctx[key] = canvas[key].getContext("2d");
144
- });
145
-
146
- await tick();
147
-
148
- if (value_img) {
149
- value_img.addEventListener("load", (_) => {
150
- if (source === "webcam") {
151
- ctx.temp.save();
152
- ctx.temp.translate(width, 0);
153
- ctx.temp.scale(-1, 1);
154
- ctx.temp.drawImage(value_img, 0, 0);
155
- ctx.temp.restore();
156
- } else {
157
- draw_cropped_image();
158
- }
159
- ctx.drawing.drawImage(canvas.temp, 0, 0, width, height);
160
-
161
- trigger_on_change();
162
- });
163
-
164
- setTimeout(() => {
165
- if (source === "webcam") {
166
- ctx.temp.save();
167
- ctx.temp.translate(width, 0);
168
- ctx.temp.scale(-1, 1);
169
- ctx.temp.drawImage(value_img, 0, 0);
170
- ctx.temp.restore();
171
- } else {
172
- draw_cropped_image();
173
- }
174
-
175
- ctx.drawing.drawImage(canvas.temp, 0, 0, width, height);
176
-
177
- draw_lines({ lines: lines.slice() });
178
- trigger_on_change();
179
- }, 100);
180
- }
181
-
182
- lazy = new LazyBrush({
183
- radius: brush_radius * 0.05,
184
- enabled: true,
185
- initialPoint: {
186
- x: width / 2,
187
- y: height / 2
188
- }
189
- });
190
-
191
- canvas_observer = new ResizeObserver((entries, observer, ...rest) => {
192
- handle_canvas_resize(entries, observer);
193
- });
194
- canvas_observer.observe(canvas_container);
195
-
196
- loop();
197
- mounted = true;
198
-
199
- requestAnimationFrame(() => {
200
- init();
201
- requestAnimationFrame(() => {
202
- clear();
203
- });
204
- });
205
- });
206
-
207
- function init() {
208
- const initX = width / 2;
209
- const initY = height / 2;
210
- lazy.update({ x: initX, y: initY }, { both: true });
211
- lazy.update({ x: initX, y: initY }, { both: false });
212
- mouse_has_moved = true;
213
- values_changed = true;
214
- }
215
-
216
- onDestroy(() => {
217
- mounted = false;
218
- canvas_observer.unobserve(canvas_container);
219
- });
220
-
221
- function redraw_image(_lines) {
222
- clear_canvas();
223
-
224
- if (value_img) {
225
- if (source === "webcam") {
226
- ctx.temp.save();
227
- ctx.temp.translate(width, 0);
228
- ctx.temp.scale(-1, 1);
229
- ctx.temp.drawImage(value_img, 0, 0);
230
- ctx.temp.restore();
231
- } else {
232
- draw_cropped_image();
233
- }
234
-
235
- if (!lines || !lines.length) {
236
- ctx.drawing.drawImage(canvas.temp, 0, 0, width, height);
237
- }
238
- }
239
-
240
- draw_lines({ lines: _lines });
241
- line_count = _lines.length;
242
-
243
- lines = _lines;
244
- ctx.drawing.drawImage(canvas.temp, 0, 0, width, height);
245
-
246
- if (lines.length == 0) {
247
- dispatch("clear");
248
- }
249
- }
250
-
251
- export function clear_mask() {
252
- const _lines = [];
253
-
254
- redraw_image(_lines);
255
- trigger_on_change();
256
- }
257
-
258
- export function undo() {
259
- const _lines = lines.slice(0, -1);
260
-
261
- redraw_image(_lines);
262
- trigger_on_change();
263
- }
264
-
265
- let get_save_data = () => {
266
- return JSON.stringify({
267
- lines: lines,
268
- width: canvas_width,
269
- height: canvas_height
270
- });
271
- };
272
-
273
- let draw_lines = ({ lines }) => {
274
- lines.forEach((line) => {
275
- const { points: _points, brush_color, brush_radius } = line;
276
- draw_points({
277
- points: _points,
278
- brush_color,
279
- brush_radius,
280
- mask: mode === "mask"
281
- });
282
- });
283
-
284
- saveLine({ brush_color, brush_radius });
285
- if (mode === "mask") {
286
- save_mask_line();
287
- }
288
- };
289
-
290
- let handle_draw_start = (e) => {
291
- e.preventDefault();
292
- is_pressing = true;
293
- const { x, y } = get_pointer_pos(e);
294
- if (e.touches && e.touches.length > 0) {
295
- lazy.update({ x, y }, { both: true });
296
- }
297
- handle_pointer_move(x, y);
298
- line_count += 1;
299
- };
300
-
301
- let handle_draw_move = (e) => {
302
- e.preventDefault();
303
- const { x, y } = get_pointer_pos(e);
304
- handle_pointer_move(x, y);
305
- };
306
-
307
- let handle_draw_end = (e) => {
308
- e.preventDefault();
309
- handle_draw_move(e);
310
- is_drawing = false;
311
- is_pressing = false;
312
- saveLine();
313
-
314
- if (mode === "mask") {
315
- save_mask_line();
316
- }
317
- };
318
-
319
- let old_width = 0;
320
- let old_height = 0;
321
- let old_container_height = 0;
322
- let add_lr_border = false;
323
-
324
- let handle_canvas_resize = async () => {
325
- if (shape && canvas_container) {
326
- const x = canvas_container?.getBoundingClientRect();
327
- const shape_ratio = shape[0] / shape[1];
328
- const container_ratio = x.width / x.height;
329
- add_lr_border = shape_ratio < container_ratio;
330
- }
331
-
332
- if (
333
- width === old_width &&
334
- height === old_height &&
335
- old_container_height === container_height
336
- ) {
337
- return;
338
- }
339
- const dimensions = { width: width, height: height };
340
-
341
- const container_dimensions = {
342
- height: container_height,
343
- width: container_height * (dimensions.width / dimensions.height)
344
- };
345
-
346
- await Promise.all([
347
- set_canvas_size(canvas.interface, dimensions, container_dimensions),
348
- set_canvas_size(canvas.drawing, dimensions, container_dimensions),
349
- set_canvas_size(canvas.temp, dimensions, container_dimensions),
350
- set_canvas_size(canvas.mask, dimensions, container_dimensions, false)
351
- ]);
352
-
353
- if (!brush_radius) {
354
- brush_radius = 20 * (dimensions.width / container_dimensions.width);
355
- }
356
-
357
- loop({ once: true });
358
-
359
- setTimeout(() => {
360
- old_height = height;
361
- old_width = width;
362
- old_container_height = container_height;
363
- }, 10);
364
- await tick();
365
-
366
- clear();
367
- };
368
-
369
- $: {
370
- if (lazy) {
371
- init();
372
- lazy.setRadius(brush_radius * 0.05);
373
- }
374
- }
375
-
376
- $: {
377
- if (width || height) {
378
- handle_canvas_resize();
379
- }
380
- }
381
-
382
- let set_canvas_size = async (canvas, dimensions, container, scale = true) => {
383
- if (!mounted) return;
384
- await tick();
385
-
386
- const dpr = window.devicePixelRatio || 1;
387
- canvas.width = dimensions.width * (scale ? dpr : 1);
388
- canvas.height = dimensions.height * (scale ? dpr : 1);
389
-
390
- const ctx = canvas.getContext("2d");
391
- scale && ctx.scale(dpr, dpr);
392
-
393
- canvas.style.width = `${container.width}px`;
394
- canvas.style.height = `${container.height}px`;
395
- };
396
-
397
- let get_pointer_pos = (e) => {
398
- const rect = canvas.interface.getBoundingClientRect();
399
-
400
- let clientX = e.clientX;
401
- let clientY = e.clientY;
402
- if (e.changedTouches && e.changedTouches.length > 0) {
403
- clientX = e.changedTouches[0].clientX;
404
- clientY = e.changedTouches[0].clientY;
405
- }
406
-
407
- return {
408
- x: ((clientX - rect.left) / rect.width) * width,
409
- y: ((clientY - rect.top) / rect.height) * height
410
- };
411
- };
412
-
413
- let handle_pointer_move = (x, y) => {
414
- lazy.update({ x: x, y: y });
415
- const is_disabled = !lazy.isEnabled();
416
- if ((is_pressing && !is_drawing) || (is_disabled && is_pressing)) {
417
- is_drawing = true;
418
- points.push(lazy.brush.toObject());
419
- }
420
- if (is_drawing) {
421
- points.push(lazy.brush.toObject());
422
- draw_points({
423
- points: points,
424
- brush_color,
425
- brush_radius,
426
- mask: mode === "mask"
427
- });
428
- }
429
- mouse_has_moved = true;
430
- };
431
-
432
- let draw_points = ({ points, brush_color, brush_radius, mask }) => {
433
- if (!points || points.length < 2) return;
434
- let target_ctx = mask ? ctx.mask : ctx.temp;
435
- target_ctx.lineJoin = "round";
436
- target_ctx.lineCap = "round";
437
-
438
- target_ctx.strokeStyle = brush_color;
439
- target_ctx.lineWidth = brush_radius;
440
- let p1 = points[0];
441
- let p2 = points[1];
442
- target_ctx.moveTo(p2.x, p2.y);
443
- target_ctx.beginPath();
444
- for (var i = 1, len = points.length; i < len; i++) {
445
- var midPoint = mid_point(p1, p2);
446
- target_ctx.quadraticCurveTo(p1.x, p1.y, midPoint.x, midPoint.y);
447
- p1 = points[i];
448
- p2 = points[i + 1];
449
- }
450
-
451
- target_ctx.lineTo(p1.x, p1.y);
452
- target_ctx.stroke();
453
- };
454
-
455
- let save_mask_line = () => {
456
- if (points.length < 1) return;
457
- points.length = 0;
458
-
459
- trigger_on_change();
460
- };
461
-
462
- let saveLine = () => {
463
- if (points.length < 1) return;
464
-
465
- lines.push({
466
- points: points.slice(),
467
- brush_color: brush_color,
468
- brush_radius
469
- });
470
-
471
- if (mode !== "mask") {
472
- points.length = 0;
473
- }
474
-
475
- ctx.drawing.drawImage(canvas.temp, 0, 0, width, height);
476
-
477
- trigger_on_change();
478
- };
479
-
480
- let trigger_on_change = () => {
481
- const x = get_image_data();
482
- dispatch("change", x);
483
- };
484
-
485
- export function clear() {
486
- lines = [];
487
- clear_canvas();
488
- line_count = 0;
489
-
490
- return true;
491
- }
492
-
493
- function clear_canvas() {
494
- values_changed = true;
495
- ctx.temp.clearRect(0, 0, width, height);
496
-
497
- ctx.temp.fillStyle = mode === "mask" ? "transparent" : "#FFFFFF";
498
- ctx.temp.fillRect(0, 0, width, height);
499
-
500
- if (mode === "mask") {
501
- ctx.mask.clearRect(0, 0, canvas.mask.width, canvas.mask.height);
502
- }
503
- }
504
-
505
- let loop = ({ once = false } = {}) => {
506
- if (mouse_has_moved || values_changed) {
507
- const pointer = lazy.getPointerCoordinates();
508
- const brush = lazy.getBrushCoordinates();
509
- draw_interface(ctx.interface, pointer, brush);
510
- mouse_has_moved = false;
511
- values_changed = false;
512
- }
513
- if (!once) {
514
- window.requestAnimationFrame(() => {
515
- loop();
516
- });
517
- }
518
- };
519
-
520
- $: brush_dot = brush_radius * 0.075;
521
-
522
- let draw_interface = (ctx, pointer, brush) => {
523
- ctx.clearRect(0, 0, width, height);
524
-
525
- // brush preview
526
- ctx.beginPath();
527
- ctx.fillStyle = brush_color;
528
- ctx.arc(brush.x, brush.y, brush_radius / 2, 0, Math.PI * 2, true);
529
- ctx.fill();
530
-
531
- // tiny brush point dot
532
- ctx.beginPath();
533
- ctx.fillStyle = catenary_color;
534
- ctx.arc(brush.x, brush.y, brush_dot, 0, Math.PI * 2, true);
535
- ctx.fill();
536
- };
537
-
538
- export function get_image_data() {
539
- return mode === "mask"
540
- ? canvas.mask.toDataURL("image/png")
541
- : canvas.drawing.toDataURL("image/jpg");
542
- }
543
- </script>
544
-
545
- <div
546
- class="wrap"
547
- bind:this={canvas_container}
548
- bind:offsetWidth={canvas_width}
549
- bind:offsetHeight={canvas_height}
550
- >
551
- {#if line_count === 0}
552
- <div transition:fade={{ duration: 50 }} class="start-prompt">
553
- Start drawing
554
- </div>
555
- {/if}
556
- {#each canvas_types as { name, zIndex, opacity }}
557
- <canvas
558
- key={name}
559
- style=" z-index:{zIndex};"
560
- style:opacity
561
- class:lr={add_lr_border}
562
- class:tb={!add_lr_border}
563
- bind:this={canvas[name]}
564
- on:mousedown={name === "interface" ? handle_draw_start : undefined}
565
- on:mousemove={name === "interface" ? handle_draw_move : undefined}
566
- on:mouseup={name === "interface" ? handle_draw_end : undefined}
567
- on:mouseout={name === "interface" ? handle_draw_end : undefined}
568
- on:blur={name === "interface" ? handle_draw_end : undefined}
569
- on:touchstart={name === "interface" ? handle_draw_start : undefined}
570
- on:touchmove={name === "interface" ? handle_draw_move : undefined}
571
- on:touchend={name === "interface" ? handle_draw_end : undefined}
572
- on:touchcancel={name === "interface" ? handle_draw_end : undefined}
573
- on:click|stopPropagation
574
- />
575
- {/each}
576
- </div>
577
-
578
- <style>
579
- canvas {
580
- display: block;
581
- position: absolute;
582
- top: 0px;
583
- right: 0px;
584
- bottom: 0px;
585
- left: 0px;
586
- margin: auto;
587
- }
588
-
589
- .lr {
590
- border-right: 1px solid var(--border-color-primary);
591
- border-left: 1px solid var(--border-color-primary);
592
- }
593
-
594
- .tb {
595
- border-top: 1px solid var(--border-color-primary);
596
- border-bottom: 1px solid var(--border-color-primary);
597
- }
598
-
599
- canvas:hover {
600
- cursor: none;
601
- }
602
-
603
- .wrap {
604
- position: relative;
605
- width: var(--size-full);
606
- height: var(--size-full);
607
- touch-action: none;
608
- }
609
-
610
- .start-prompt {
611
- display: flex;
612
- position: absolute;
613
- top: 0px;
614
- right: 0px;
615
- bottom: 0px;
616
- left: 0px;
617
- justify-content: center;
618
- align-items: center;
619
- z-index: var(--layer-4);
620
- touch-action: none;
621
- pointer-events: none;
622
- color: var(--body-text-color-subdued);
623
- }
624
- </style>
@@ -1,77 +0,0 @@
1
- <script lang="ts">
2
- import { IconButton } from "@gradio/atoms";
3
- import { Brush, Color } from "@gradio/icons";
4
-
5
- let show_size = false;
6
- let show_col = false;
7
-
8
- export let brush_radius = 20;
9
- export let brush_color = "#000";
10
- export let container_height: number;
11
- export let img_width: number;
12
- export let img_height: number;
13
- export let mode: "mask" | "other" = "other";
14
-
15
- $: width = container_height * (img_width / img_height);
16
- </script>
17
-
18
- <div class="wrap">
19
- <span class="brush">
20
- <IconButton
21
- Icon={Brush}
22
- label="Use brush"
23
- on:click={() => (show_size = !show_size)}
24
- />
25
- {#if show_size}
26
- <input
27
- aria-label="Brush radius"
28
- bind:value={brush_radius}
29
- type="range"
30
- min={0.5 * (img_width / width)}
31
- max={75 * (img_width / width)}
32
- />
33
- {/if}
34
- </span>
35
-
36
- {#if mode !== "mask"}
37
- <span class="col">
38
- <IconButton
39
- Icon={Color}
40
- label="Select brush color"
41
- on:click={() => (show_col = !show_col)}
42
- />
43
- {#if show_col}
44
- <input aria-label="Brush color" bind:value={brush_color} type="color" />
45
- {/if}
46
- </span>
47
- {/if}
48
- </div>
49
-
50
- <style>
51
- .wrap {
52
- display: flex;
53
- position: absolute;
54
- top: var(--size-10);
55
- right: var(--size-2);
56
- flex-direction: column;
57
- justify-content: flex-end;
58
- gap: var(--spacing-sm);
59
- z-index: var(--layer-5);
60
- }
61
- .brush {
62
- top: 0;
63
- right: 0;
64
- }
65
-
66
- .brush input {
67
- position: absolute;
68
- top: 3px;
69
- right: calc(100% + 5px);
70
- }
71
-
72
- .col input {
73
- position: absolute;
74
- right: calc(100% + 5px);
75
- bottom: -4px;
76
- }
77
- </style>