@gradio/image 0.16.8 → 0.18.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 CHANGED
@@ -1,5 +1,25 @@
1
1
  # @gradio/image
2
2
 
3
+ ## 0.18.0
4
+
5
+ ### Features
6
+
7
+ - [#10099](https://github.com/gradio-app/gradio/pull/10099) [`8530b6e`](https://github.com/gradio-app/gradio/commit/8530b6e2f986421adceda98f972e6b843bc03fbe) - Redesign pending bubble in Chatbot. Thanks @hannahblair!
8
+ - [#10032](https://github.com/gradio-app/gradio/pull/10032) [`e450674`](https://github.com/gradio-app/gradio/commit/e450674ce41ca28f1f37a27fb149c728593a6ddf) - add `webcam_height` and `webcam_width` to specify the resolution of the Webcam. Thanks @yinsumirage!
9
+
10
+ ## 0.17.0
11
+
12
+ ### Features
13
+
14
+ - [#10054](https://github.com/gradio-app/gradio/pull/10054) [`458941c`](https://github.com/gradio-app/gradio/commit/458941c508f11d43debf1cef6950f330145e336d) - Allow full screen mode in interactive gr.Image. Thanks @hannahblair!
15
+
16
+ ### Dependency updates
17
+
18
+ - @gradio/atoms@0.11.2
19
+ - @gradio/utils@0.9.0
20
+ - @gradio/statustracker@0.9.6
21
+ - @gradio/upload@0.14.2
22
+
3
23
  ## 0.16.8
4
24
 
5
25
  ### Dependency updates
package/Index.svelte CHANGED
@@ -65,6 +65,7 @@
65
65
  export let placeholder: string | undefined = undefined;
66
66
  export let show_fullscreen_button: boolean;
67
67
  export let input_ready: boolean;
68
+ export let webcam_constraints: { [key: string]: any } | undefined = undefined;
68
69
  let uploading = false;
69
70
  $: input_ready = !uploading;
70
71
  export let gradio: Gradio<{
@@ -218,6 +219,7 @@
218
219
  {stream_every}
219
220
  bind:modify_stream={_modify_stream}
220
221
  bind:set_time_limit
222
+ {webcam_constraints}
221
223
  max_file_size={gradio.max_file_size}
222
224
  i18n={gradio.i18n}
223
225
  upload={(...args) => gradio.client.upload(...args)}
package/dist/Index.svelte CHANGED
@@ -54,6 +54,7 @@ export let mirror_webcam;
54
54
  export let placeholder = void 0;
55
55
  export let show_fullscreen_button;
56
56
  export let input_ready;
57
+ export let webcam_constraints = void 0;
57
58
  let uploading = false;
58
59
  $:
59
60
  input_ready = !uploading;
@@ -190,6 +191,7 @@ const handle_drop = (event) => {
190
191
  {stream_every}
191
192
  bind:modify_stream={_modify_stream}
192
193
  bind:set_time_limit
194
+ {webcam_constraints}
193
195
  max_file_size={gradio.max_file_size}
194
196
  i18n={gradio.i18n}
195
197
  upload={(...args) => gradio.client.upload(...args)}
@@ -38,6 +38,9 @@ declare const __propDef: {
38
38
  placeholder?: string | undefined;
39
39
  show_fullscreen_button: boolean;
40
40
  input_ready: boolean;
41
+ webcam_constraints?: {
42
+ [key: string]: any;
43
+ } | undefined;
41
44
  gradio: Gradio<{
42
45
  input: never;
43
46
  change: never;
@@ -148,6 +151,13 @@ export default class Index extends SvelteComponent<IndexProps, IndexEvents, Inde
148
151
  get input_ready(): boolean;
149
152
  /**accessor*/
150
153
  set input_ready(_: boolean);
154
+ get webcam_constraints(): {
155
+ [key: string]: any;
156
+ } | undefined;
157
+ /**accessor*/
158
+ set webcam_constraints(_: {
159
+ [key: string]: any;
160
+ } | undefined);
151
161
  get gradio(): Gradio<{
152
162
  input: never;
153
163
  change: never;
@@ -103,6 +103,7 @@ const toggle_full_screen = async () => {
103
103
  .image-container {
104
104
  height: 100%;
105
105
  position: relative;
106
+ min-width: var(--size-20);
106
107
  }
107
108
 
108
109
  .image-container button {
@@ -1,13 +1,12 @@
1
1
  <script>import { createEventDispatcher, tick } from "svelte";
2
- import { BlockLabel } from "@gradio/atoms";
3
- import { Image as ImageIcon } from "@gradio/icons";
2
+ import { BlockLabel, IconButtonWrapper, IconButton } from "@gradio/atoms";
3
+ import { Clear, Image as ImageIcon, Maximize, Minimize } from "@gradio/icons";
4
4
  import {
5
5
  } from "@gradio/utils";
6
6
  import { get_coordinates_of_clicked_image } from "./utils";
7
7
  import Webcam from "./Webcam.svelte";
8
8
  import { Upload } from "@gradio/upload";
9
9
  import { FileData } from "@gradio/client";
10
- import ClearImage from "./ClearImage.svelte";
11
10
  import { SelectSource } from "@gradio/atoms";
12
11
  import Image from "./Image.svelte";
13
12
  export let value = null;
@@ -26,9 +25,11 @@ export let stream_handler;
26
25
  export let stream_every;
27
26
  export let modify_stream;
28
27
  export let set_time_limit;
28
+ export let show_fullscreen_button = true;
29
29
  let upload_input;
30
30
  export let uploading = false;
31
31
  export let active_source = null;
32
+ export let webcam_constraints = void 0;
32
33
  function handle_upload({ detail }) {
33
34
  if (!streaming) {
34
35
  value = detail;
@@ -87,19 +88,48 @@ async function handle_select_source(source) {
87
88
  break;
88
89
  }
89
90
  }
91
+ let is_full_screen = false;
92
+ let image_container;
93
+ const toggle_full_screen = async () => {
94
+ if (!is_full_screen) {
95
+ await image_container.requestFullscreen();
96
+ } else {
97
+ await document.exitFullscreen();
98
+ is_full_screen = !is_full_screen;
99
+ }
100
+ };
90
101
  </script>
91
102
 
92
103
  <BlockLabel {show_label} Icon={ImageIcon} label={label || "Image"} />
93
104
 
94
- <div data-testid="image" class="image-container">
95
- {#if value?.url && !active_streaming}
96
- <ClearImage
97
- on:remove_image={() => {
98
- value = null;
99
- dispatch("clear");
100
- }}
101
- />
102
- {/if}
105
+ <div data-testid="image" class="image-container" bind:this={image_container}>
106
+ <IconButtonWrapper>
107
+ {#if value?.url && !active_streaming}
108
+ {#if !is_full_screen && show_fullscreen_button}
109
+ <IconButton
110
+ Icon={Maximize}
111
+ label={is_full_screen ? "Exit full screen" : "View in full screen"}
112
+ on:click={toggle_full_screen}
113
+ />
114
+ {/if}
115
+ {#if is_full_screen && show_fullscreen_button}
116
+ <IconButton
117
+ Icon={Minimize}
118
+ label={is_full_screen ? "Exit full screen" : "View in full screen"}
119
+ on:click={toggle_full_screen}
120
+ />
121
+ {/if}
122
+ <IconButton
123
+ Icon={Clear}
124
+ label="Remove Image"
125
+ on:click={(event) => {
126
+ value = null;
127
+ dispatch("clear");
128
+ event.stopPropagation();
129
+ }}
130
+ />
131
+ {/if}
132
+ </IconButtonWrapper>
103
133
  <div
104
134
  class="upload-container"
105
135
  class:reduced-height={sources.length > 1}
@@ -142,6 +172,7 @@ async function handle_select_source(source) {
142
172
  {upload}
143
173
  bind:modify_stream
144
174
  bind:set_time_limit
175
+ {webcam_constraints}
145
176
  />
146
177
  {:else if value !== null && !streaming}
147
178
  <!-- svelte-ignore a11y-click-events-have-key-events-->
@@ -20,8 +20,12 @@ declare const __propDef: {
20
20
  stream_every: number;
21
21
  modify_stream: (state: "open" | "closed" | "waiting") => void;
22
22
  set_time_limit: (arg0: number) => void;
23
+ show_fullscreen_button?: boolean | undefined;
23
24
  uploading?: boolean | undefined;
24
25
  active_source?: ("clipboard" | "upload" | "microphone" | "webcam" | null) | undefined;
26
+ webcam_constraints?: {
27
+ [key: string]: any;
28
+ } | undefined;
25
29
  dragging?: boolean | undefined;
26
30
  };
27
31
  events: {
@@ -43,6 +43,7 @@ export let stream_every = 1;
43
43
  export let mode = "image";
44
44
  export let mirror_webcam;
45
45
  export let include_audio;
46
+ export let webcam_constraints = null;
46
47
  export let i18n;
47
48
  export let upload;
48
49
  export let value = null;
@@ -60,19 +61,22 @@ onMount(() => {
60
61
  const handle_device_change = async (event) => {
61
62
  const target = event.target;
62
63
  const device_id = target.value;
63
- await get_video_stream(include_audio, video_source, device_id).then(
64
- async (local_stream) => {
65
- stream = local_stream;
66
- selected_device = available_video_devices.find(
67
- (device) => device.deviceId === device_id
68
- ) || null;
69
- options_open = false;
70
- }
71
- );
64
+ await get_video_stream(
65
+ include_audio,
66
+ video_source,
67
+ webcam_constraints,
68
+ device_id
69
+ ).then(async (local_stream) => {
70
+ stream = local_stream;
71
+ selected_device = available_video_devices.find(
72
+ (device) => device.deviceId === device_id
73
+ ) || null;
74
+ options_open = false;
75
+ });
72
76
  };
73
77
  async function access_webcam() {
74
78
  try {
75
- get_video_stream(include_audio, video_source).then(async (local_stream) => {
79
+ get_video_stream(include_audio, video_source, webcam_constraints).then(async (local_stream) => {
76
80
  webcam_accessed = true;
77
81
  available_video_devices = await get_devices();
78
82
  stream = local_stream;
@@ -13,6 +13,9 @@ declare const __propDef: {
13
13
  mode?: ("image" | "video") | undefined;
14
14
  mirror_webcam: boolean;
15
15
  include_audio: boolean;
16
+ webcam_constraints?: ({
17
+ [key: string]: any;
18
+ } | null) | undefined;
16
19
  i18n: I18nFormatter;
17
20
  upload: Client["upload"];
18
21
  value?: FileData | null | Base64File;
@@ -1,5 +1,7 @@
1
1
  export declare function get_devices(): Promise<MediaDeviceInfo[]>;
2
2
  export declare function handle_error(error: string): void;
3
3
  export declare function set_local_stream(local_stream: MediaStream | null, video_source: HTMLVideoElement): void;
4
- export declare function get_video_stream(include_audio: boolean, video_source: HTMLVideoElement, device_id?: string): Promise<MediaStream>;
4
+ export declare function get_video_stream(include_audio: boolean, video_source: HTMLVideoElement, webcam_constraints: {
5
+ [key: string]: any;
6
+ } | null, device_id?: string): Promise<MediaStream>;
5
7
  export declare function set_available_devices(devices: MediaDeviceInfo[]): MediaDeviceInfo[];
@@ -9,14 +9,15 @@ export function set_local_stream(local_stream, video_source) {
9
9
  video_source.muted = true;
10
10
  video_source.play();
11
11
  }
12
- export async function get_video_stream(include_audio, video_source, device_id) {
13
- const size = {
14
- width: { ideal: 1920 },
15
- height: { ideal: 1440 }
16
- };
12
+ export async function get_video_stream(include_audio, video_source, webcam_constraints, device_id) {
17
13
  const constraints = {
18
- video: device_id ? { deviceId: { exact: device_id }, ...size } : size,
19
- audio: include_audio
14
+ video: device_id
15
+ ? { deviceId: { exact: device_id }, ...webcam_constraints?.video }
16
+ : webcam_constraints?.video || {
17
+ width: { ideal: 1920 },
18
+ height: { ideal: 1440 }
19
+ },
20
+ audio: include_audio && (webcam_constraints?.audio ?? true) // Defaults to true if not specified
20
21
  };
21
22
  return navigator.mediaDevices
22
23
  .getUserMedia(constraints)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gradio/image",
3
- "version": "0.16.8",
3
+ "version": "0.18.0",
4
4
  "description": "Gradio UI packages",
5
5
  "type": "module",
6
6
  "author": "",
@@ -10,12 +10,12 @@
10
10
  "cropperjs": "^1.5.12",
11
11
  "lazy-brush": "^1.0.1",
12
12
  "resize-observer-polyfill": "^1.5.1",
13
- "@gradio/atoms": "^0.11.1",
13
+ "@gradio/atoms": "^0.11.2",
14
14
  "@gradio/icons": "^0.8.1",
15
- "@gradio/statustracker": "^0.9.5",
16
- "@gradio/upload": "^0.14.1",
17
- "@gradio/utils": "^0.8.0",
18
15
  "@gradio/client": "^1.8.0",
16
+ "@gradio/statustracker": "^0.9.6",
17
+ "@gradio/upload": "^0.14.2",
18
+ "@gradio/utils": "^0.9.0",
19
19
  "@gradio/wasm": "^0.15.0"
20
20
  },
21
21
  "devDependencies": {
@@ -116,6 +116,7 @@
116
116
  .image-container {
117
117
  height: 100%;
118
118
  position: relative;
119
+ min-width: var(--size-20);
119
120
  }
120
121
 
121
122
  .image-container button {
@@ -1,7 +1,7 @@
1
1
  <script lang="ts">
2
2
  import { createEventDispatcher, tick } from "svelte";
3
- import { BlockLabel } from "@gradio/atoms";
4
- import { Image as ImageIcon } from "@gradio/icons";
3
+ import { BlockLabel, IconButtonWrapper, IconButton } from "@gradio/atoms";
4
+ import { Clear, Image as ImageIcon, Maximize, Minimize } from "@gradio/icons";
5
5
  import {
6
6
  type SelectData,
7
7
  type I18nFormatter,
@@ -12,7 +12,6 @@
12
12
 
13
13
  import { Upload } from "@gradio/upload";
14
14
  import { FileData, type Client } from "@gradio/client";
15
- import ClearImage from "./ClearImage.svelte";
16
15
  import { SelectSource } from "@gradio/atoms";
17
16
  import Image from "./Image.svelte";
18
17
  import type { Base64File } from "./types";
@@ -37,11 +36,14 @@
37
36
 
38
37
  export let modify_stream: (state: "open" | "closed" | "waiting") => void;
39
38
  export let set_time_limit: (arg0: number) => void;
39
+ export let show_fullscreen_button = true;
40
40
 
41
41
  let upload_input: Upload;
42
42
  export let uploading = false;
43
43
  export let active_source: source_type = null;
44
44
 
45
+ export let webcam_constraints: { [key: string]: any } | undefined = undefined;
46
+
45
47
  function handle_upload({ detail }: CustomEvent<FileData>): void {
46
48
  // only trigger streaming event if streaming
47
49
  if (!streaming) {
@@ -119,19 +121,50 @@
119
121
  break;
120
122
  }
121
123
  }
124
+
125
+ let is_full_screen = false;
126
+ let image_container: HTMLElement;
127
+
128
+ const toggle_full_screen = async (): Promise<void> => {
129
+ if (!is_full_screen) {
130
+ await image_container.requestFullscreen();
131
+ } else {
132
+ await document.exitFullscreen();
133
+ is_full_screen = !is_full_screen;
134
+ }
135
+ };
122
136
  </script>
123
137
 
124
138
  <BlockLabel {show_label} Icon={ImageIcon} label={label || "Image"} />
125
139
 
126
- <div data-testid="image" class="image-container">
127
- {#if value?.url && !active_streaming}
128
- <ClearImage
129
- on:remove_image={() => {
130
- value = null;
131
- dispatch("clear");
132
- }}
133
- />
134
- {/if}
140
+ <div data-testid="image" class="image-container" bind:this={image_container}>
141
+ <IconButtonWrapper>
142
+ {#if value?.url && !active_streaming}
143
+ {#if !is_full_screen && show_fullscreen_button}
144
+ <IconButton
145
+ Icon={Maximize}
146
+ label={is_full_screen ? "Exit full screen" : "View in full screen"}
147
+ on:click={toggle_full_screen}
148
+ />
149
+ {/if}
150
+ {#if is_full_screen && show_fullscreen_button}
151
+ <IconButton
152
+ Icon={Minimize}
153
+ label={is_full_screen ? "Exit full screen" : "View in full screen"}
154
+ on:click={toggle_full_screen}
155
+ />
156
+ {/if}
157
+ <IconButton
158
+ Icon={Clear}
159
+ label="Remove Image"
160
+ on:click={(event) => {
161
+ value = null;
162
+ dispatch("clear");
163
+ event.stopPropagation();
164
+ }}
165
+ />
166
+ {/if}
167
+ </IconButtonWrapper>
135
168
  <div
136
169
  class="upload-container"
137
170
  class:reduced-height={sources.length > 1}
@@ -174,6 +207,7 @@
174
207
  {upload}
175
208
  bind:modify_stream
176
209
  bind:set_time_limit
210
+ {webcam_constraints}
177
211
  />
178
212
  {:else if value !== null && !streaming}
179
213
  <!-- svelte-ignore a11y-click-events-have-key-events-->
@@ -18,6 +18,7 @@
18
18
  set_available_devices
19
19
  } from "./stream_utils";
20
20
  import type { Base64File } from "./types";
21
+ import type { int } from "babylonjs";
21
22
 
22
23
  let video_source: HTMLVideoElement;
23
24
  let available_video_devices: MediaDeviceInfo[] = [];
@@ -52,6 +53,7 @@
52
53
  export let mode: "image" | "video" = "image";
53
54
  export let mirror_webcam: boolean;
54
55
  export let include_audio: boolean;
56
+ export let webcam_constraints: { [key: string]: any } | null = null;
55
57
  export let i18n: I18nFormatter;
56
58
  export let upload: Client["upload"];
57
59
  export let value: FileData | null | Base64File = null;
@@ -80,21 +82,24 @@
80
82
  const target = event.target as HTMLInputElement;
81
83
  const device_id = target.value;
82
84
 
83
- await get_video_stream(include_audio, video_source, device_id).then(
84
- async (local_stream) => {
85
- stream = local_stream;
86
- selected_device =
87
- available_video_devices.find(
88
- (device) => device.deviceId === device_id
89
- ) || null;
90
- options_open = false;
91
- }
92
- );
85
+ await get_video_stream(
86
+ include_audio,
87
+ video_source,
88
+ webcam_constraints,
89
+ device_id
90
+ ).then(async (local_stream) => {
91
+ stream = local_stream;
92
+ selected_device =
93
+ available_video_devices.find(
94
+ (device) => device.deviceId === device_id
95
+ ) || null;
96
+ options_open = false;
97
+ });
93
98
  };
94
99
 
95
100
  async function access_webcam(): Promise<void> {
96
101
  try {
97
- get_video_stream(include_audio, video_source)
102
+ get_video_stream(include_audio, video_source, webcam_constraints)
98
103
  .then(async (local_stream) => {
99
104
  webcam_accessed = true;
100
105
  available_video_devices = await get_devices();
@@ -18,16 +18,17 @@ export function set_local_stream(
18
18
  export async function get_video_stream(
19
19
  include_audio: boolean,
20
20
  video_source: HTMLVideoElement,
21
+ webcam_constraints: { [key: string]: any } | null,
21
22
  device_id?: string
22
23
  ): Promise<MediaStream> {
23
- const size = {
24
- width: { ideal: 1920 },
25
- height: { ideal: 1440 }
26
- };
27
-
28
- const constraints = {
29
- video: device_id ? { deviceId: { exact: device_id }, ...size } : size,
30
- audio: include_audio
24
+ const constraints: MediaStreamConstraints = {
25
+ video: device_id
26
+ ? { deviceId: { exact: device_id }, ...webcam_constraints?.video }
27
+ : webcam_constraints?.video || {
28
+ width: { ideal: 1920 },
29
+ height: { ideal: 1440 }
30
+ },
31
+ audio: include_audio && (webcam_constraints?.audio ?? true) // Defaults to true if not specified
31
32
  };
32
33
 
33
34
  return navigator.mediaDevices
@@ -1,16 +0,0 @@
1
- <script>import { createEventDispatcher } from "svelte";
2
- import { IconButton, IconButtonWrapper } from "@gradio/atoms";
3
- import { Clear } from "@gradio/icons";
4
- const dispatch = createEventDispatcher();
5
- </script>
6
-
7
- <IconButtonWrapper>
8
- <IconButton
9
- Icon={Clear}
10
- label="Remove Image"
11
- on:click={(event) => {
12
- dispatch("remove_image");
13
- event.stopPropagation();
14
- }}
15
- />
16
- </IconButtonWrapper>
@@ -1,18 +0,0 @@
1
- import { SvelteComponent } from "svelte";
2
- declare const __propDef: {
3
- props: {
4
- [x: string]: never;
5
- };
6
- events: {
7
- remove_image: CustomEvent<any>;
8
- } & {
9
- [evt: string]: CustomEvent<any>;
10
- };
11
- slots: {};
12
- };
13
- export type ClearImageProps = typeof __propDef.props;
14
- export type ClearImageEvents = typeof __propDef.events;
15
- export type ClearImageSlots = typeof __propDef.slots;
16
- export default class ClearImage extends SvelteComponent<ClearImageProps, ClearImageEvents, ClearImageSlots> {
17
- }
18
- export {};
@@ -1,18 +0,0 @@
1
- <script lang="ts">
2
- import { createEventDispatcher } from "svelte";
3
- import { IconButton, IconButtonWrapper } from "@gradio/atoms";
4
- import { Clear } from "@gradio/icons";
5
-
6
- const dispatch = createEventDispatcher();
7
- </script>
8
-
9
- <IconButtonWrapper>
10
- <IconButton
11
- Icon={Clear}
12
- label="Remove Image"
13
- on:click={(event) => {
14
- dispatch("remove_image");
15
- event.stopPropagation();
16
- }}
17
- />
18
- </IconButtonWrapper>