@gradio/annotatedimage 0.7.2-beta.1
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 +620 -0
- package/Index.svelte +298 -0
- package/LICENSE +201 -0
- package/dist/Index.svelte +267 -0
- package/dist/Index.svelte.d.ts +43 -0
- package/package.json +38 -0
@@ -0,0 +1,267 @@
|
|
1
|
+
<script>import { onMount } from "svelte";
|
2
|
+
import { Block, BlockLabel, Empty, IconButton } from "@gradio/atoms";
|
3
|
+
import { Image, Maximize, Minimize } from "@gradio/icons";
|
4
|
+
import { StatusTracker } from "@gradio/statustracker";
|
5
|
+
import {} from "@gradio/client";
|
6
|
+
import { resolve_wasm_src } from "@gradio/wasm/svelte";
|
7
|
+
export let elem_id = "";
|
8
|
+
export let elem_classes = [];
|
9
|
+
export let visible = true;
|
10
|
+
export let value = null;
|
11
|
+
let old_value = null;
|
12
|
+
let _value = null;
|
13
|
+
export let gradio;
|
14
|
+
export let label = gradio.i18n("annotated_image.annotated_image");
|
15
|
+
export let show_label = true;
|
16
|
+
export let show_legend = true;
|
17
|
+
export let height;
|
18
|
+
export let width;
|
19
|
+
export let color_map;
|
20
|
+
export let container = true;
|
21
|
+
export let scale = null;
|
22
|
+
export let min_width = void 0;
|
23
|
+
let active = null;
|
24
|
+
export let loading_status;
|
25
|
+
export let show_fullscreen_button = true;
|
26
|
+
let is_full_screen = false;
|
27
|
+
let image_container;
|
28
|
+
onMount(() => {
|
29
|
+
document.addEventListener("fullscreenchange", () => {
|
30
|
+
is_full_screen = !!document.fullscreenElement;
|
31
|
+
});
|
32
|
+
});
|
33
|
+
const toggle_full_screen = async () => {
|
34
|
+
if (!is_full_screen) {
|
35
|
+
await image_container.requestFullscreen();
|
36
|
+
} else {
|
37
|
+
await document.exitFullscreen();
|
38
|
+
}
|
39
|
+
};
|
40
|
+
let latest_promise = null;
|
41
|
+
$: {
|
42
|
+
if (value !== old_value) {
|
43
|
+
old_value = value;
|
44
|
+
gradio.dispatch("change");
|
45
|
+
}
|
46
|
+
if (value) {
|
47
|
+
const normalized_value = {
|
48
|
+
image: value.image,
|
49
|
+
annotations: value.annotations.map((ann) => ({
|
50
|
+
image: ann.image,
|
51
|
+
label: ann.label
|
52
|
+
}))
|
53
|
+
};
|
54
|
+
_value = normalized_value;
|
55
|
+
const image_url_promise = resolve_wasm_src(normalized_value.image.url);
|
56
|
+
const annotation_urls_promise = Promise.all(
|
57
|
+
normalized_value.annotations.map(
|
58
|
+
(ann) => resolve_wasm_src(ann.image.url)
|
59
|
+
)
|
60
|
+
);
|
61
|
+
const current_promise = Promise.all([
|
62
|
+
image_url_promise,
|
63
|
+
annotation_urls_promise
|
64
|
+
]);
|
65
|
+
latest_promise = current_promise;
|
66
|
+
current_promise.then(([image_url, annotation_urls]) => {
|
67
|
+
if (latest_promise !== current_promise) {
|
68
|
+
return;
|
69
|
+
}
|
70
|
+
const async_resolved_value = {
|
71
|
+
image: {
|
72
|
+
...normalized_value.image,
|
73
|
+
url: image_url ?? void 0
|
74
|
+
},
|
75
|
+
annotations: normalized_value.annotations.map((ann, i) => ({
|
76
|
+
...ann,
|
77
|
+
image: {
|
78
|
+
...ann.image,
|
79
|
+
url: annotation_urls[i] ?? void 0
|
80
|
+
}
|
81
|
+
}))
|
82
|
+
};
|
83
|
+
_value = async_resolved_value;
|
84
|
+
});
|
85
|
+
} else {
|
86
|
+
_value = null;
|
87
|
+
}
|
88
|
+
}
|
89
|
+
function handle_mouseover(_label) {
|
90
|
+
active = _label;
|
91
|
+
}
|
92
|
+
function handle_mouseout() {
|
93
|
+
active = null;
|
94
|
+
}
|
95
|
+
function handle_click(i, value2) {
|
96
|
+
gradio.dispatch("select", {
|
97
|
+
value: label,
|
98
|
+
index: i
|
99
|
+
});
|
100
|
+
}
|
101
|
+
</script>
|
102
|
+
|
103
|
+
<Block
|
104
|
+
{visible}
|
105
|
+
{elem_id}
|
106
|
+
{elem_classes}
|
107
|
+
padding={false}
|
108
|
+
{height}
|
109
|
+
{width}
|
110
|
+
allow_overflow={false}
|
111
|
+
{container}
|
112
|
+
{scale}
|
113
|
+
{min_width}
|
114
|
+
>
|
115
|
+
<StatusTracker
|
116
|
+
autoscroll={gradio.autoscroll}
|
117
|
+
i18n={gradio.i18n}
|
118
|
+
{...loading_status}
|
119
|
+
/>
|
120
|
+
<BlockLabel
|
121
|
+
{show_label}
|
122
|
+
Icon={Image}
|
123
|
+
label={label || gradio.i18n("image.image")}
|
124
|
+
/>
|
125
|
+
|
126
|
+
<div class="container">
|
127
|
+
{#if _value == null}
|
128
|
+
<Empty size="large" unpadded_box={true}><Image /></Empty>
|
129
|
+
{:else}
|
130
|
+
<div class="image-container" bind:this={image_container}>
|
131
|
+
<div class="icon-buttons">
|
132
|
+
{#if !is_full_screen && show_fullscreen_button}
|
133
|
+
<IconButton
|
134
|
+
Icon={Maximize}
|
135
|
+
label="View in full screen"
|
136
|
+
on:click={toggle_full_screen}
|
137
|
+
/>
|
138
|
+
{/if}
|
139
|
+
|
140
|
+
{#if is_full_screen}
|
141
|
+
<IconButton
|
142
|
+
Icon={Minimize}
|
143
|
+
label="Exit full screen"
|
144
|
+
on:click={toggle_full_screen}
|
145
|
+
/>
|
146
|
+
{/if}
|
147
|
+
</div>
|
148
|
+
|
149
|
+
<img
|
150
|
+
class="base-image"
|
151
|
+
class:fit-height={height && !is_full_screen}
|
152
|
+
src={_value ? _value.image.url : null}
|
153
|
+
alt="the base file that is annotated"
|
154
|
+
/>
|
155
|
+
{#each _value ? _value?.annotations : [] as ann, i}
|
156
|
+
<img
|
157
|
+
alt="segmentation mask identifying {label} within the uploaded file"
|
158
|
+
class="mask fit-height"
|
159
|
+
class:fit-height={!is_full_screen}
|
160
|
+
class:active={active == ann.label}
|
161
|
+
class:inactive={active != ann.label && active != null}
|
162
|
+
src={ann.image.url}
|
163
|
+
style={color_map && ann.label in color_map
|
164
|
+
? null
|
165
|
+
: `filter: hue-rotate(${Math.round(
|
166
|
+
(i * 360) / _value?.annotations.length
|
167
|
+
)}deg);`}
|
168
|
+
/>
|
169
|
+
{/each}
|
170
|
+
</div>
|
171
|
+
{#if show_legend && _value}
|
172
|
+
<div class="legend">
|
173
|
+
{#each _value.annotations as ann, i}
|
174
|
+
<button
|
175
|
+
class="legend-item"
|
176
|
+
style="background-color: {color_map && ann.label in color_map
|
177
|
+
? color_map[ann.label] + '88'
|
178
|
+
: `hsla(${Math.round(
|
179
|
+
(i * 360) / _value.annotations.length
|
180
|
+
)}, 100%, 50%, 0.3)`}"
|
181
|
+
on:mouseover={() => handle_mouseover(ann.label)}
|
182
|
+
on:focus={() => handle_mouseover(ann.label)}
|
183
|
+
on:mouseout={() => handle_mouseout()}
|
184
|
+
on:blur={() => handle_mouseout()}
|
185
|
+
on:click={() => handle_click(i, ann.label)}
|
186
|
+
>
|
187
|
+
{ann.label}
|
188
|
+
</button>
|
189
|
+
{/each}
|
190
|
+
</div>
|
191
|
+
{/if}
|
192
|
+
{/if}
|
193
|
+
</div>
|
194
|
+
</Block>
|
195
|
+
|
196
|
+
<style>
|
197
|
+
.base-image {
|
198
|
+
display: block;
|
199
|
+
width: 100%;
|
200
|
+
height: auto;
|
201
|
+
}
|
202
|
+
.container {
|
203
|
+
display: flex;
|
204
|
+
position: relative;
|
205
|
+
flex-direction: column;
|
206
|
+
justify-content: center;
|
207
|
+
align-items: center;
|
208
|
+
width: var(--size-full);
|
209
|
+
height: var(--size-full);
|
210
|
+
}
|
211
|
+
.image-container {
|
212
|
+
position: relative;
|
213
|
+
top: 0;
|
214
|
+
left: 0;
|
215
|
+
flex-grow: 1;
|
216
|
+
width: 100%;
|
217
|
+
overflow: hidden;
|
218
|
+
}
|
219
|
+
.fit-height {
|
220
|
+
top: 0;
|
221
|
+
left: 0;
|
222
|
+
width: 100%;
|
223
|
+
height: 100%;
|
224
|
+
object-fit: contain;
|
225
|
+
}
|
226
|
+
.mask {
|
227
|
+
opacity: 0.85;
|
228
|
+
transition: all 0.2s ease-in-out;
|
229
|
+
position: absolute;
|
230
|
+
}
|
231
|
+
.image-container:hover .mask {
|
232
|
+
opacity: 0.3;
|
233
|
+
}
|
234
|
+
.mask.active {
|
235
|
+
opacity: 1;
|
236
|
+
}
|
237
|
+
.mask.inactive {
|
238
|
+
opacity: 0;
|
239
|
+
}
|
240
|
+
.legend {
|
241
|
+
display: flex;
|
242
|
+
flex-direction: row;
|
243
|
+
flex-wrap: wrap;
|
244
|
+
align-content: center;
|
245
|
+
justify-content: center;
|
246
|
+
align-items: center;
|
247
|
+
gap: var(--spacing-sm);
|
248
|
+
padding: var(--spacing-sm);
|
249
|
+
}
|
250
|
+
.legend-item {
|
251
|
+
display: flex;
|
252
|
+
flex-direction: row;
|
253
|
+
align-items: center;
|
254
|
+
cursor: pointer;
|
255
|
+
border-radius: var(--radius-sm);
|
256
|
+
padding: var(--spacing-sm);
|
257
|
+
}
|
258
|
+
|
259
|
+
.icon-buttons {
|
260
|
+
display: flex;
|
261
|
+
position: absolute;
|
262
|
+
top: 6px;
|
263
|
+
right: 6px;
|
264
|
+
gap: var(--size-1);
|
265
|
+
z-index: 1;
|
266
|
+
}
|
267
|
+
</style>
|
@@ -0,0 +1,43 @@
|
|
1
|
+
import { SvelteComponent } from "svelte";
|
2
|
+
import type { Gradio, SelectData } from "@gradio/utils";
|
3
|
+
import type { LoadingStatus } from "@gradio/statustracker";
|
4
|
+
import { type FileData } from "@gradio/client";
|
5
|
+
declare const __propDef: {
|
6
|
+
props: {
|
7
|
+
elem_id?: string | undefined;
|
8
|
+
elem_classes?: string[] | undefined;
|
9
|
+
visible?: boolean | undefined;
|
10
|
+
value?: ({
|
11
|
+
image: FileData;
|
12
|
+
annotations: {
|
13
|
+
image: FileData;
|
14
|
+
label: string;
|
15
|
+
}[] | [];
|
16
|
+
} | null) | undefined;
|
17
|
+
gradio: Gradio<{
|
18
|
+
change: undefined;
|
19
|
+
select: SelectData;
|
20
|
+
}>;
|
21
|
+
label?: any;
|
22
|
+
show_label?: boolean | undefined;
|
23
|
+
show_legend?: boolean | undefined;
|
24
|
+
height: number | undefined;
|
25
|
+
width: number | undefined;
|
26
|
+
color_map: Record<string, string>;
|
27
|
+
container?: boolean | undefined;
|
28
|
+
scale?: (number | null) | undefined;
|
29
|
+
min_width?: number | undefined;
|
30
|
+
loading_status: LoadingStatus;
|
31
|
+
show_fullscreen_button?: boolean | undefined;
|
32
|
+
};
|
33
|
+
events: {
|
34
|
+
[evt: string]: CustomEvent<any>;
|
35
|
+
};
|
36
|
+
slots: {};
|
37
|
+
};
|
38
|
+
export type IndexProps = typeof __propDef.props;
|
39
|
+
export type IndexEvents = typeof __propDef.events;
|
40
|
+
export type IndexSlots = typeof __propDef.slots;
|
41
|
+
export default class Index extends SvelteComponent<IndexProps, IndexEvents, IndexSlots> {
|
42
|
+
}
|
43
|
+
export {};
|
package/package.json
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
{
|
2
|
+
"name": "@gradio/annotatedimage",
|
3
|
+
"version": "0.7.2-beta.1",
|
4
|
+
"description": "Gradio UI packages",
|
5
|
+
"type": "module",
|
6
|
+
"author": "",
|
7
|
+
"license": "ISC",
|
8
|
+
"private": false,
|
9
|
+
"main_changeset": true,
|
10
|
+
"exports": {
|
11
|
+
".": {
|
12
|
+
"gradio": "./Index.svelte",
|
13
|
+
"svelte": "./dist/Index.svelte",
|
14
|
+
"types": "./dist/Index.svelte.d.ts"
|
15
|
+
},
|
16
|
+
"./package.json": "./package.json"
|
17
|
+
},
|
18
|
+
"devDependencies": {
|
19
|
+
"@gradio/preview": "^0.11.1-beta.0"
|
20
|
+
},
|
21
|
+
"peerDependencies": {
|
22
|
+
"svelte": "^4.0.0"
|
23
|
+
},
|
24
|
+
"dependencies": {
|
25
|
+
"@gradio/atoms": "^0.8.1-beta.1",
|
26
|
+
"@gradio/icons": "^0.8.0-beta.1",
|
27
|
+
"@gradio/upload": "^0.12.4-beta.1",
|
28
|
+
"@gradio/client": "^1.6.0-beta.1",
|
29
|
+
"@gradio/statustracker": "^0.8.0-beta.1",
|
30
|
+
"@gradio/wasm": "^0.13.1-beta.1",
|
31
|
+
"@gradio/utils": "^0.7.0-beta.1"
|
32
|
+
},
|
33
|
+
"repository": {
|
34
|
+
"type": "git",
|
35
|
+
"url": "git+https://github.com/gradio-app/gradio.git",
|
36
|
+
"directory": "js/annotatedimage"
|
37
|
+
}
|
38
|
+
}
|