Avaiga / taipy

Turns Data and AI algorithms into production-ready web applications in no time.
https://www.taipy.io
Apache License 2.0
15.51k stars 1.86k forks source link

Issue with using file_selector to upload an image file second time around. #2103

Open taupirho opened 1 month ago

taupirho commented 1 month ago

What went wrong? 🤔

I use a file selecter control to allow the user to upload an image file. I also have a CLEAR button that clears the images. If I try and re-upload the same image after clicking CLEAR it doesn't work. I'm running this on a Jupyter Notebook. If I choose a different named image ile, second time around it loads OK

Expected Behavior

Would expect to be able to upload the same image twice in a row in between calls to CLEAR

Steps to Reproduce Issue

I added this function to your existing bg removal tool example

def clear_images(state): """ Clears the currently displayed images by setting original_image and fixed_image to None. """ state.original_image = None state.fixed_image = None state.fixed = False state.image = None state.path_upload = "" print("Images cleared.") notify(state, "info", "Images have been cleared.")

Then added a CLEAR button in the main GUI like this

               tgb.button(
                label="Clear Images",
                on_action=clear_images,
                active="{original_image is not None}",
            )

Now click Upload File button and choose an image. All works OK. Now click CLEAR button. Images are removed as expected. Now click File Upload button again and choose the same image file as before. Nothing happens

Code

from taipy.gui import Gui, notify, download
from PIL import Image
from io import BytesIO
import os
import taipy.gui.builder as tgb
import signal
from textwrap import dedent

path_upload = ""
original_image = None
image = None
fixed_image = None
fixed = False

def clear_images(state):
    """
    Clears the currently displayed images by setting `original_image` and `fixed_image` to None.
    """
    state.original_image = None
    state.fixed_image = None
    state.fixed = False
    state.image = None
    state.path_upload = None 
    print("Images cleared.")
    notify(state, "info", "Images have been cleared.")
    # Removed the problematic lines
    # state.original_image = Image.open(None)
    # reload()

def convert_webp_to_png(state):
    """
    Converts an image (WEBP, PNG, JPG) to PNG format.
    Updates the state.fixed_image with the converted image.
    """
    try:
        print(f"Converting image at path: {state.path_upload}")
        with Image.open(state.path_upload) as img:
            # Convert the image to PNG format
            buffer = BytesIO()
            img.convert("RGBA").save(buffer, format="PNG")
            buffer.seek(0)
            state.fixed_image = buffer.getvalue()
            state.fixed = True
            print("Image converted to PNG.")
            notify(state, "success", "Image converted to PNG successfully!")
    except Exception as e:
        print(f"Error in convert_webp_to_png: {e}")
        notify(state, "error", f"Error converting image: {e}")

def upload_image(state):
    """
    Handles image upload and prepares the state for displaying the image.
    Resets variables to ensure the new upload is recognized.
    """
    state.original_image = Image.open(state.path_upload)
    state.fixed = False
    print(f"Image successfully loaded from {state.path_upload}.")
    notify(state, "success", "Image uploaded successfully!")

def download_image(state):
    """
    Allows the user to download the converted PNG image.
    """
    if state.fixed_image:
        print("Initiating download of the converted image.")
        download(state, content=state.fixed_image, name="converted_image.png")

# Define common styles for a better look
common_styles = "text-align: center; width: 200px; min-height: 40px; margin: 5px 0; display: block;"

# Create the Taipy GUI layout
with tgb.Page() as page:
    tgb.toggle(theme=True)
    with tgb.layout("20 80", columns__mobile="1"):
        with tgb.part("sidebar"):
            tgb.text("### Converting **WEBP Image** to PNG", mode="md")
            with tgb.part("flex flex-col items-center"):

                tgb.file_selector(
                    "{path_upload}",
                    extensions=".webp", drop_message="Drop Image here",
                    label="Upload image",
                    on_action=upload_image,
                    style=common_styles
                )

                tgb.button(
                    label="Convert to PNG",
                    on_action=convert_webp_to_png,
                    active="{original_image is not None}",
                    style=common_styles
                )

                tgb.button(
                    label="Download PNG",
                    on_action=download_image,
                    active="{fixed_image is not None}",
                    style=common_styles
                )                

                tgb.button(
                    label="Clear Images",
                    on_action=clear_images,
                    active="{original_image is not None}",
                    style=common_styles
                )

        with tgb.part("container"):
            tgb.text("# Image **Converter**", mode="md")
            tgb.text(dedent("""
                         Upload a WEBP, JPG, or PNG image, then click the Convert button on the sidebar. When it's done, you can download the processed image from the sidebar.
                     """), mode="md",
            )
            with tgb.layout("1 1"):
                with tgb.part("card text-center", render="{path_upload is not None and os.path.isfile(path_upload)}"):
                    tgb.text("### Original WEBP Image", mode="md")
                    print(f"Rendering original image from: {path_upload}")
                    tgb.image("{path_upload}")  # Directly show the uploaded image from path
                with tgb.part("card text-center", render="{fixed_image is not None}"):
                    tgb.text("### Converted PNG Image", mode="md")
                    tgb.image("{fixed_image}")

if __name__ == "__main__":
    print("Starting the WebP to PNG Converter...")
    Gui(page=page).run(margin="0px", title="WebP to PNG Converter")
    print("WebP to PNG Converter has stopped.")

Runtime Environment

WSL2 Ubuntu for Window on a Jupyter notebook

Browsers

Chrome

Version of Taipy

3.1.1

Acceptance Criteria

Code of Conduct

sravan1946 commented 1 month ago

could you provide the full code required to reproduce this issue

taupirho commented 1 month ago
from taipy.gui import Gui, notify, download
from PIL import Image
from io import BytesIO
import os
import taipy.gui.builder as tgb
import signal
from textwrap import dedent

path_upload = ""
original_image = None
image = None
fixed_image = None
fixed = False

def clear_images(state):
    """
    Clears the currently displayed images by setting `original_image` and `fixed_image` to None.
    """
    state.original_image = None
    state.fixed_image = None
    state.fixed = False
    state.image = None
    state.path_upload = None 
    print("Images cleared.")
    notify(state, "info", "Images have been cleared.")
    # Removed the problematic lines
    # state.original_image = Image.open(None)
    # reload()

def convert_webp_to_png(state):
    """
    Converts an image (WEBP, PNG, JPG) to PNG format.
    Updates the state.fixed_image with the converted image.
    """
    try:
        print(f"Converting image at path: {state.path_upload}")
        with Image.open(state.path_upload) as img:
            # Convert the image to PNG format
            buffer = BytesIO()
            img.convert("RGBA").save(buffer, format="PNG")
            buffer.seek(0)
            state.fixed_image = buffer.getvalue()
            state.fixed = True
            print("Image converted to PNG.")
            notify(state, "success", "Image converted to PNG successfully!")
    except Exception as e:
        print(f"Error in convert_webp_to_png: {e}")
        notify(state, "error", f"Error converting image: {e}")

def upload_image(state):
    """
    Handles image upload and prepares the state for displaying the image.
    Resets variables to ensure the new upload is recognized.
    """
    state.original_image = Image.open(state.path_upload)
    state.fixed = False
    print(f"Image successfully loaded from {state.path_upload}.")
    notify(state, "success", "Image uploaded successfully!")

def download_image(state):
    """
    Allows the user to download the converted PNG image.
    """
    if state.fixed_image:
        print("Initiating download of the converted image.")
        download(state, content=state.fixed_image, name="converted_image.png")

# Define common styles for a better look
common_styles = "text-align: center; width: 200px; min-height: 40px; margin: 5px 0; display: block;"

# Create the Taipy GUI layout
with tgb.Page() as page:
    tgb.toggle(theme=True)
    with tgb.layout("20 80", columns__mobile="1"):
        with tgb.part("sidebar"):
            tgb.text("### Converting **WEBP Image** to PNG", mode="md")
            with tgb.part("flex flex-col items-center"):

                tgb.file_selector(
                    "{path_upload}",
                    extensions=".webp", drop_message="Drop Image here",
                    label="Upload image",
                    on_action=upload_image,
                    style=common_styles
                )

                tgb.button(
                    label="Convert to PNG",
                    on_action=convert_webp_to_png,
                    active="{original_image is not None}",
                    style=common_styles
                )

                tgb.button(
                    label="Download PNG",
                    on_action=download_image,
                    active="{fixed_image is not None}",
                    style=common_styles
                )                

                tgb.button(
                    label="Clear Images",
                    on_action=clear_images,
                    active="{original_image is not None}",
                    style=common_styles
                )

        with tgb.part("container"):
            tgb.text("# Image **Converter**", mode="md")
            tgb.text(dedent("""
                         Upload a WEBP, JPG, or PNG image, then click the Convert button on the sidebar. When it's done, you can download the processed image from the sidebar.
                     """), mode="md",
            )
            with tgb.layout("1 1"):
                with tgb.part("card text-center", render="{path_upload is not None and os.path.isfile(path_upload)}"):
                    tgb.text("### Original WEBP Image", mode="md")
                    print(f"Rendering original image from: {path_upload}")
                    tgb.image("{path_upload}")  # Directly show the uploaded image from path
                with tgb.part("card text-center", render="{fixed_image is not None}"):
                    tgb.text("### Converted PNG Image", mode="md")
                    tgb.image("{fixed_image}")

if __name__ == "__main__":
    print("Starting the WebP to PNG Converter...")
    Gui(page=page).run(margin="0px", title="WebP to PNG Converter")
    print("WebP to PNG Converter has stopped.")
sravan1946 commented 1 month ago

please use codeblocks when sharing code

taupirho commented 1 month ago

Can you use what I provided or do you want me to re-send

sravan1946 commented 1 month ago

you can edit or re-send it as all the indentation and formatting is gone

taupirho commented 1 month ago
from taipy.gui import Gui, notify, download
from PIL import Image
from io import BytesIO
import os
import taipy.gui.builder as tgb
import signal
from textwrap import dedent

path_upload = ""
original_image = None
image = None
fixed_image = None
fixed = False

def clear_images(state):
    """
    Clears the currently displayed images by setting `original_image` and `fixed_image` to None.
    """
    state.original_image = None
    state.fixed_image = None
    state.fixed = False
    state.image = None
    state.path_upload = None 
    print("Images cleared.")
    notify(state, "info", "Images have been cleared.")
    # Removed the problematic lines
    # state.original_image = Image.open(None)
    # reload()

def convert_webp_to_png(state):
    """
    Converts an image (WEBP, PNG, JPG) to PNG format.
    Updates the state.fixed_image with the converted image.
    """
    try:
        print(f"Converting image at path: {state.path_upload}")
        with Image.open(state.path_upload) as img:
            # Convert the image to PNG format
            buffer = BytesIO()
            img.convert("RGBA").save(buffer, format="PNG")
            buffer.seek(0)
            state.fixed_image = buffer.getvalue()
            state.fixed = True
            print("Image converted to PNG.")
            notify(state, "success", "Image converted to PNG successfully!")
    except Exception as e:
        print(f"Error in convert_webp_to_png: {e}")
        notify(state, "error", f"Error converting image: {e}")

def upload_image(state):
    """
    Handles image upload and prepares the state for displaying the image.
    Resets variables to ensure the new upload is recognized.
    """
    state.original_image = Image.open(state.path_upload)
    state.fixed = False
    print(f"Image successfully loaded from {state.path_upload}.")
    notify(state, "success", "Image uploaded successfully!")

def download_image(state):
    """
    Allows the user to download the converted PNG image.
    """
    if state.fixed_image:
        print("Initiating download of the converted image.")
        download(state, content=state.fixed_image, name="converted_image.png")

# Define common styles for a better look
common_styles = "text-align: center; width: 200px; min-height: 40px; margin: 5px 0; display: block;"

# Create the Taipy GUI layout
with tgb.Page() as page:
    tgb.toggle(theme=True)
    with tgb.layout("20 80", columns__mobile="1"):
        with tgb.part("sidebar"):
            tgb.text("### Converting **WEBP Image** to PNG", mode="md")
            with tgb.part("flex flex-col items-center"):

                tgb.file_selector(
                    "{path_upload}",
                    extensions=".webp", drop_message="Drop Image here",
                    label="Upload image",
                    on_action=upload_image,
                    style=common_styles
                )

                tgb.button(
                    label="Convert to PNG",
                    on_action=convert_webp_to_png,
                    active="{original_image is not None}",
                    style=common_styles
                )

                tgb.button(
                    label="Download PNG",
                    on_action=download_image,
                    active="{fixed_image is not None}",
                    style=common_styles
                )                

                tgb.button(
                    label="Clear Images",
                    on_action=clear_images,
                    active="{original_image is not None}",
                    style=common_styles
                )

        with tgb.part("container"):
            tgb.text("# Image **Converter**", mode="md")
            tgb.text(dedent("""
                         Upload a WEBP, JPG, or PNG image, then click the Convert button on the sidebar. When it's done, you can download the processed image from the sidebar.
                     """), mode="md",
            )
            with tgb.layout("1 1"):
                with tgb.part("card text-center", render="{path_upload is not None and os.path.isfile(path_upload)}"):
                    tgb.text("### Original WEBP Image", mode="md")
                    print(f"Rendering original image from: {path_upload}")
                    tgb.image("{path_upload}")  # Directly show the uploaded image from path
                with tgb.part("card text-center", render="{fixed_image is not None}"):
                    tgb.text("### Converted PNG Image", mode="md")
                    tgb.image("{fixed_image}")

if __name__ == "__main__":
    print("Starting the WebP to PNG Converter...")
    Gui(page=page).run(margin="0px", title="WebP to PNG Converter")
    print("WebP to PNG Converter has stopped.")
taupirho commented 1 month ago

Done

On Sun, Oct 20, 2024 at 2:25 PM sravan @.***> wrote:

you can edit or re-send it as all the indentation and formatting is gone

— Reply to this email directly, view it on GitHub https://github.com/Avaiga/taipy/issues/2103#issuecomment-2424960280, or unsubscribe https://github.com/notifications/unsubscribe-auth/AFHMTFIUAVC4RA6ZSUZWLWDZ4OVMBAVCNFSM6AAAAABQIPPDQ2VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDIMRUHE3DAMRYGA . You are receiving this because you authored the thread.Message ID: @.***>

taupirho commented 1 month ago

Hi there, just wondering if this is a confirmed bug or is there something wrong with the code on my Clear button?

On Sun, 20 Oct 2024, 14:34 Thomas Reid, @.***> wrote:

Done

On Sun, Oct 20, 2024 at 2:25 PM sravan @.***> wrote:

you can edit or re-send it as all the indentation and formatting is gone

— Reply to this email directly, view it on GitHub https://github.com/Avaiga/taipy/issues/2103#issuecomment-2424960280, or unsubscribe https://github.com/notifications/unsubscribe-auth/AFHMTFIUAVC4RA6ZSUZWLWDZ4OVMBAVCNFSM6AAAAABQIPPDQ2VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDIMRUHE3DAMRYGA . You are receiving this because you authored the thread.Message ID: @.***>

FlorianJacta commented 4 weeks ago

Hi @taupirho, we are looking through your issue. I have reproduced it like this:

from taipy.gui import Gui, notify
from PIL import Image
import taipy.gui.builder as tgb

path_upload = ""
original_image = None
image = None
fixed_image = None
fixed = False

def clear_images(state):
    """
    Clears the currently displayed images by setting `original_image` and `fixed_image` to None.
    """
    state.original_image = None
    state.fixed_image = None
    state.fixed = False
    state.image = None
    state.path_upload = ""
    print("Images cleared.")
    notify(state, "info", "Images have been cleared.")

def upload_image(state):
    """
    Handles image upload and prepares the state for displaying the image.
    Resets variables to ensure the new upload is recognized.
    """
    state.original_image = Image.open(state.path_upload)
    state.fixed = False
    print(f"Image successfully loaded from {state.path_upload}.")
    notify(state, "success", "Image uploaded successfully!")

# Create the Taipy GUI layout
with tgb.Page() as page:
    tgb.text(
        lambda original_image: f"Is there an image? " + str(original_image is not None)
    )
    tgb.file_selector(
        "{path_upload}",
        extensions=".webp",
        drop_message="Drop Image here",
        label="Upload image",
        on_action=upload_image,
    )

    tgb.button(
        label="Clear Images",
        on_action=clear_images,
        active="{original_image is not None}",
    )

if __name__ == "__main__":
    Gui(page=page).run(margin="0px", title="WebP to PNG Converter")

There seems to be a proper issue here.

C:\Users\jacta\.conda\envs\4.0\Lib\site-packages\taipy\gui\utils\_attributes.py:58: ResourceWarning: unclosed file <_io.BufferedReader name='C:\\Users\\jacta\\AppData\\Local\\Temp\\DALLE_2024-06-18_14.09.50_-_A_minimalist_illustration_showcasing_the_concept_of_long-running_callbacks_in_a_web_application._The_image_should_depict_a_web_browser_window_with_a_r.2.webp'>
  setattr(obj, var_name_split[-1], value)
FlorianJacta commented 1 week ago

We encountered this issue with a client