Spaces:
Running
Running
File size: 7,808 Bytes
8497828 ff8cc66 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 |
import gradio as gr
from typing import List, Any, Literal
from gradio_imagemeta import ImageMeta
from gradio_imagemeta.helpers import add_metadata, transfer_metadata
from gradio_propertysheet import PropertySheet
from gradio_propertysheet.helpers import flatten_dataclass_with_labels
from pathlib import Path
from ui_config import PropertyConfig
output_dir = Path("outputs")
output_dir.mkdir(exist_ok=True)
def load_default_image():
return "src/examples/image_with_meta.png"
def handle_load_metadata(image_data: gr.EventData) -> List[Any]:
"""
Processes image metadata by calling the agnostic `transfer_metadata` helper.
"""
if not image_data or not hasattr(image_data, "_data"):
return [gr.skip()] * len(output_fields)
metadata = image_data._data
if not metadata:
return [gr.skip()] * len(output_fields)
# --- UI-Specific Configuration ---
# Define the map that tells the helper how to process the PropertySheet.
sheet_map = {
id(property_sheet): {
"type": property_sheet._dataclass_type,
"prefixes": [] # No prefixes needed for this simple case
}
}
gradio_map = {
id(component): label
for label, component in input_fields.items()
}
# Call the agnostic helper function to do the heavy lifting.
return transfer_metadata(
output_fields=output_fields,
metadata=metadata,
propertysheet_map=sheet_map,
gradio_component_map=gradio_map,
remove_prefix_from_keys=False
)
def save_image_with_metadata(
image_data: Any,
format: Literal[".png", ".png"],
sheet_state: PropertyConfig,
model: str,
f_number: str,
iso: str,
s_churn_val: float,
description: str
) -> str | None:
"""
Saves an image with updated metadata, merging data from the PropertySheet
and individual UI components.
This example deals with the PropertySheet component and the individual gradio components.
Since they have the same labels here, we'll simply replace the metadata with each other's values.
"""
if not image_data:
return None
metadata = flatten_dataclass_with_labels(sheet_state)
individual_component_values = {
"Model": model,
"FNumber": f_number,
"ISOSpeedRatings": iso,
"Schurn": s_churn_val,
"Description": description
}
metadata["Image Settings - Model"] = individual_component_values["Model"]
metadata["Image Settings - FNumber"] = individual_component_values["FNumber"]
metadata["Image Settings - ISOSpeedRatings"] = individual_component_values["ISOSpeedRatings"]
metadata["Image Settings - Schurn"] = individual_component_values["Schurn"]
metadata["Description"] = individual_component_values["Description"]
final_metadata = {str(key): value for key, value in metadata.items()}
new_filepath = output_dir / f"image_with_meta{format}"
add_metadata(image_data, new_filepath, final_metadata)
return str(new_filepath)
initial_property_from_meta_config = PropertyConfig()
with gr.Blocks(theme=gr.themes.Ocean()) as demo:
gr.Markdown("# ImageMeta Component Demo")
gr.Markdown("""
2. Upload demo image or an image with EXIF or PNG metadata using either the "Upload Imagem (Custom metadata only)" component or the "Upload Imagem (all metadata)" component.
3. Click the 'Info' icon (ⓘ) in the top-left of the image component to view the metadata panel.
4. Click 'Load Metadata' in the popup to populate the fields below with metadata values (`Model`, `FNumber`, `ISOSpeedRatings`, `Schurn`, `Description`).
5. The section below displays how metadata is rendered in components and the `PropertySheet` custom component, showing the hierarchical structure of the image settings.
6. In the "Metadata Viewer" section, you can add field values as metadata to a previously uploaded image in "Upload Image (Custom metadata only)." Then click 'Add metadata and save image' to save a new image with the metadata.
"""
)
property_sheet_state = gr.State(value=initial_property_from_meta_config)
with gr.Row():
img_custom = ImageMeta(
label="Upload Image (Custom metadata only)",
type="filepath",
width=600,
height=400,
popup_metadata_height=350,
popup_metadata_width=550,
interactive=True,
only_custom_metadata=True
)
img_all = ImageMeta(
label="Upload Image (All metadata)",
only_custom_metadata=False,
type="filepath",
width=600,
height=400,
popup_metadata_height=350,
popup_metadata_width=550,
interactive=True
)
gr.Markdown("## Metadata Viewer")
gr.Markdown("### Individual Components")
with gr.Row():
model_box = gr.Textbox(label="Model")
fnumber_box = gr.Textbox(label="FNumber")
iso_box = gr.Textbox(label="ISOSpeedRatings")
s_churn = gr.Slider(label="Schurn", value=1.0, minimum=0.0, maximum=1.0, step=0.1)
description_box = gr.Textbox(label="Description", lines=2)
gr.Markdown("### PropertySheet Component")
with gr.Row():
property_sheet = PropertySheet(
value=initial_property_from_meta_config,
label="Image Settings",
width=400,
height=550,
visible=True,
root_label="General"
)
gr.Markdown("## Metadata Editor")
with gr.Row():
save_format = gr.Radio(label="Image Format", choices=[".png", ".jpg"], value=".png")
save_button = gr.Button("Add Metadata and Save Image")
saved_file_output = gr.File(label="Download Image")
input_fields = {
"Model": model_box,
"FNumber": fnumber_box,
"ISOSpeedRatings": iso_box,
"Schurn": s_churn,
"Description": description_box
}
output_fields = [
property_sheet,
model_box,
fnumber_box,
iso_box,
s_churn,
description_box
]
img_custom.load_metadata(handle_load_metadata, inputs=None, outputs=output_fields)
img_all.load_metadata(handle_load_metadata, inputs=None, outputs=output_fields)
def handle_render_change(updated_config: PropertyConfig, current_state: PropertyConfig):
"""
Updates the PropertySheet state when its configuration changes.
Args:
updated_config: The new PropertyConfig instance from the PropertySheet.
current_state: The current PropertyConfig state.
Returns:
A tuple of (updated_config, updated_config) or (current_state, current_state) if updated_config is None.
"""
if updated_config is None:
return current_state, current_state
return updated_config, updated_config
property_sheet.change(
fn=handle_render_change,
inputs=[property_sheet, property_sheet_state],
outputs=[property_sheet, property_sheet_state]
)
save_button.click(
save_image_with_metadata,
inputs=[img_custom, save_format, property_sheet, *input_fields.values()],
outputs=[saved_file_output]
)
demo.load(
fn=load_default_image,
inputs=None,
outputs=img_custom
)
if __name__ == "__main__":
demo.launch() |