Skip to content

Commit

Permalink
Add placeholder param to Image and ImageEditor to replace upload im…
Browse files Browse the repository at this point in the history
…age text (#8930)
  • Loading branch information
hannahblair authored Aug 20, 2024
1 parent 747013b commit 41d5ab9
Show file tree
Hide file tree
Showing 16 changed files with 147 additions and 26 deletions.
9 changes: 9 additions & 0 deletions .changeset/hip-apes-help.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"@gradio/atoms": minor
"@gradio/image": minor
"@gradio/imageeditor": minor
"@gradio/simpleimage": minor
"gradio": minor
---

feat:Add `placeholder` param to Image and ImageEditor to replace upload image text
3 changes: 3 additions & 0 deletions gradio/components/image.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ def __init__(
key: int | str | None = None,
mirror_webcam: bool = True,
show_share_button: bool | None = None,
placeholder: str | None = None,
show_fullscreen_button: bool = True,
):
"""
Expand Down Expand Up @@ -102,6 +103,7 @@ def __init__(
key: if assigned, will be used to assume identity across a re-render. Components that have the same key across a re-render will have their value preserved.
mirror_webcam: If True webcam will be mirrored. Default is True.
show_share_button: If True, will show a share icon in the corner of the component that allows user to share outputs to Hugging Face Spaces Discussions. If False, icon does not appear. If set to None (default behavior), then the icon appears if this Gradio app is launched on Spaces, but not otherwise.
placeholder: Custom text for the upload area. Overrides default upload messages when provided. Accepts new lines and `#` to designate a heading.
show_fullscreen_button: If True, will show a fullscreen icon in the corner of the component that allows user to view the image in fullscreen mode. If False, icon does not appear.
"""
self.format = format
Expand Down Expand Up @@ -141,6 +143,7 @@ def __init__(
else show_share_button
)
self.show_fullscreen_button = show_fullscreen_button
self.placeholder = placeholder
super().__init__(
label=label,
every=every,
Expand Down
3 changes: 3 additions & 0 deletions gradio/components/image_editor.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ def __init__(
elem_classes: list[str] | str | None = None,
render: bool = True,
key: int | str | None = None,
placeholder: str | None = None,
mirror_webcam: bool = True,
show_share_button: bool | None = None,
_selectable: bool = False,
Expand Down Expand Up @@ -205,6 +206,7 @@ def __init__(
elem_classes: An optional list of strings that are assigned as the classes of this component in the HTML DOM. Can be used for targeting CSS styles.
render: If False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later.
key: if assigned, will be used to assume identity across a re-render. Components that have the same key across a re-render will have their value preserved.
placeholder: Custom text for the upload area. Overrides default upload messages when provided. Accepts new lines and `#` to designate a heading.
mirror_webcam: If True webcam will be mirrored. Default is True.
show_share_button: If True, will show a share icon in the corner of the component that allows user to share outputs to Hugging Face Spaces Discussions. If False, icon does not appear. If set to None (default behavior), then the icon appears if this Gradio app is launched on Spaces, but not otherwise.
crop_size: The size of the crop box in pixels. If a tuple, the first value is the width and the second value is the height. If a string, the value must be a ratio in the form `width:height` (e.g. "16:9").
Expand Down Expand Up @@ -257,6 +259,7 @@ def __init__(
self.layers = layers
self.canvas_size = canvas_size
self.show_fullscreen_button = show_fullscreen_button
self.placeholder = placeholder

super().__init__(
label=label,
Expand Down
6 changes: 6 additions & 0 deletions gradio/templates.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ def __init__(
elem_classes: list[str] | str | None = None,
render: bool = True,
key: int | str | None = None,
placeholder: str | None = None,
mirror_webcam: bool = True,
show_share_button: bool | None = None,
_selectable: bool = False,
Expand Down Expand Up @@ -150,6 +151,7 @@ def __init__(
elem_classes=elem_classes,
render=render,
key=key,
placeholder=placeholder,
mirror_webcam=mirror_webcam,
show_share_button=show_share_button,
_selectable=_selectable,
Expand Down Expand Up @@ -210,6 +212,7 @@ def __init__(
layers: bool = True,
canvas_size: tuple[int, int] | None = None,
show_fullscreen_button: bool = True,
placeholder: str | None = None,
):
super().__init__(
value=value,
Expand Down Expand Up @@ -243,6 +246,7 @@ def __init__(
layers=layers,
canvas_size=canvas_size,
show_fullscreen_button=show_fullscreen_button,
placeholder=placeholder,
)


Expand Down Expand Up @@ -285,6 +289,7 @@ def __init__(
elem_classes: list[str] | str | None = None,
render: bool = True,
key: int | str | None = None,
placeholder: str | None = None,
mirror_webcam: bool = True,
show_share_button: bool | None = None,
_selectable: bool = False,
Expand Down Expand Up @@ -320,6 +325,7 @@ def __init__(
elem_classes=elem_classes,
render=render,
key=key,
placeholder=placeholder,
mirror_webcam=mirror_webcam,
show_share_button=show_share_button,
_selectable=_selectable,
Expand Down
33 changes: 29 additions & 4 deletions js/atoms/src/UploadText.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<script lang="ts">
import type { I18nFormatter } from "@gradio/utils";
import { Upload as UploadIcon, ImagePaste } from "@gradio/icons";
import { inject } from "./utils/parse_placeholder";
export let type:
| "video"
| "image"
Expand All @@ -13,6 +15,7 @@
export let message: string | undefined = undefined;
export let mode: "full" | "short" = "full";
export let hovered = false;
export let placeholder: string | undefined = undefined;
const defs = {
image: "upload_text.drop_image",
Expand All @@ -23,6 +26,8 @@
gallery: "upload_text.drop_gallery",
clipboard: "upload_text.paste_clipboard"
};
$: [heading, paragraph] = placeholder ? inject(placeholder) : [false, false];
</script>

<div class="wrap">
Expand All @@ -34,15 +39,33 @@
{/if}
</span>

{i18n(defs[type] || defs.file)}
{#if heading || paragraph}
{#if heading}
<h2>{heading}</h2>
{/if}
{#if paragraph}
<p>{paragraph}</p>
{/if}
{:else}
{i18n(defs[type] || defs.file)}

{#if mode !== "short"}
<span class="or">- {i18n("common.or")} -</span>
{message || i18n("upload_text.click_to_upload")}
{#if mode !== "short"}
<span class="or">- {i18n("common.or")} -</span>
{message || i18n("upload_text.click_to_upload")}
{/if}
{/if}
</div>

<style>
h2 {
font-size: var(--text-xl) !important;
}
p,
h2 {
white-space: pre-line;
}
.wrap {
display: flex;
flex-direction: column;
Expand All @@ -53,6 +76,8 @@
line-height: var(--line-md);
height: 100%;
padding-top: var(--size-3);
text-align: center;
margin: auto var(--spacing-lg);
}
.or {
Expand Down
27 changes: 27 additions & 0 deletions js/atoms/src/utils/parse_placeholder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
const RE_HEADING = /^(#\s*)(.+)$/m;

export function inject(text: string): [string | false, string | false] {
const trimmed_text = text.trim();

const heading_match = trimmed_text.match(RE_HEADING);
if (!heading_match) {
return [false, trimmed_text || false];
}

const [full_match, , heading_content] = heading_match;
const _heading = heading_content.trim();

if (trimmed_text === full_match) {
return [_heading, false];
}

const heading_end_index =
heading_match.index !== undefined
? heading_match.index + full_match.length
: 0;
const remaining_text = trimmed_text.substring(heading_end_index).trim();

const _paragraph = remaining_text || false;

return [_heading, _paragraph];
}
3 changes: 2 additions & 1 deletion js/dropdown/Dropdown.stories.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@
["swim", "swim"],
["jump", "jump"]
],
label: "Single-select Dropdown"
label: "Single-select Dropdown",
info: "This is a single-select dropdown"
}}
/>
<Story
Expand Down
21 changes: 6 additions & 15 deletions js/image/Image.stories.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
}
}
};
let md = `# a heading! /n a new line! `;
</script>

<Template let:args>
Expand All @@ -28,27 +30,15 @@
</Template>

<Story
name="static with label and download button"
args={{
value: {
path: "https://gradio-builds.s3.amazonaws.com/demo-files/ghepardo-primo-piano.jpg",
url: "https://gradio-builds.s3.amazonaws.com/demo-files/ghepardo-primo-piano.jpg",
orig_name: "cheetah.jpg"
},
show_label: true,
show_download_button: true
}}
/>

<Story
name="static with label and download button"
name="static with label, info and download button"
args={{
value: {
path: "https://gradio-builds.s3.amazonaws.com/demo-files/ghepardo-primo-piano.jpg",
url: "https://gradio-builds.s3.amazonaws.com/demo-files/ghepardo-primo-piano.jpg",
orig_name: "cheetah.jpg"
},
show_label: true,
placeholder: "This is a cheetah",
show_download_button: true
}}
play={async ({ canvasElement }) => {
Expand Down Expand Up @@ -85,7 +75,8 @@
},
show_label: false,
show_download_button: false,
interactive: true
interactive: true,
placeholder: md
}}
play={async ({ canvasElement }) => {
const canvas = within(canvasElement);
Expand Down
3 changes: 2 additions & 1 deletion js/image/Index.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
export let streaming: boolean;
export let pending: boolean;
export let mirror_webcam: boolean;
export let placeholder: string | undefined = undefined;
export let show_fullscreen_button: boolean;
export let gradio: Gradio<{
Expand Down Expand Up @@ -201,7 +202,7 @@
stream_handler={gradio.client.stream}
>
{#if active_source === "upload" || !active_source}
<UploadText i18n={gradio.i18n} type="image" />
<UploadText i18n={gradio.i18n} type="image" {placeholder} />
{:else if active_source === "clipboard"}
<UploadText i18n={gradio.i18n} type="clipboard" mode="short" />
{:else}
Expand Down
1 change: 1 addition & 0 deletions js/imageeditor/ImageEditor.stories.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@
orig_name: "cheetah.jpg"
},
type: "pil",
placeholder: "Upload an image of a cat",
sources: ["upload", "webcam"],
interactive: "true",
brush: {
Expand Down
2 changes: 2 additions & 0 deletions js/imageeditor/Index.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
"webcam"
];
export let interactive: boolean;
export let placeholder: string | undefined;
export let brush: Brush;
export let eraser: Eraser;
Expand Down Expand Up @@ -214,6 +215,7 @@
status={loading_status?.status}
upload={gradio.client.upload}
stream_handler={gradio.client.stream}
{placeholder}
></InteractiveImageEditor>
</Block>
{/if}
30 changes: 26 additions & 4 deletions js/imageeditor/shared/InteractiveImageEditor.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import { Tools, Crop, Brush, Sources } from "./tools";
import { BlockLabel } from "@gradio/atoms";
import { Image as ImageIcon } from "@gradio/icons";
import { inject } from "./utils/parse_placeholder";
export let brush: IBrush | null;
export let eraser: Eraser | null;
Expand All @@ -49,6 +50,7 @@
export let upload: Client["upload"];
export let stream_handler: Client["stream"];
export let dragging: boolean;
export let placeholder: string | undefined = undefined;
const dispatch = createEventDispatcher<{
clear?: never;
Expand Down Expand Up @@ -197,6 +199,8 @@
let active_mode: "webcam" | "color" | null = null;
let editor_height = 0;
$: [heading, paragraph] = placeholder ? inject(placeholder) : [false, false];
</script>

<BlockLabel
Expand Down Expand Up @@ -254,20 +258,38 @@
{#if !bg && !history && active_mode !== "webcam" && status !== "error"}
<div class="empty wrap" style:height={`${editor_height}px`}>
{#if sources && sources.length}
<div>Upload an image</div>
{#if heading || paragraph}
{#if heading}
<h2>{heading}</h2>
{/if}
{#if paragraph}
<p>{paragraph}</p>
{/if}
{:else}
<div>Upload an image</div>
{/if}
{/if}

{#if sources && sources.length && brush}
{#if sources && sources.length && brush && !placeholder}
<div class="or">or</div>
{/if}
{#if brush}
{#if brush && !placeholder}
<div>select the draw tool to start</div>
{/if}
</div>
{/if}
</ImageEditor>

<style>
h2 {
font-size: var(--text-xl);
}
p,
h2 {
white-space: pre-line;
}
.empty {
display: flex;
flex-direction: column;
Expand All @@ -292,7 +314,7 @@
align-items: center;
color: var(--block-label-text-color);
line-height: var(--line-md);
font-size: var(--text-lg);
font-size: var(--text-md);
pointer-events: none;
}
Expand Down
Loading

0 comments on commit 41d5ab9

Please sign in to comment.