You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Gradio应用上传GIF后无法获取多帧图像对象的问题

问题:Gradio中无法获取上传GIF的完整多帧对象

我用Gradio开发Web版GIF编辑器,用户上传GIF后能在界面正常显示动画,但代码里拿到的只是第一帧的静态Image对象,没法像直接用PIL打开GIF那样,通过.seek()切换帧、访问n_frames属性。现在多数Gradio资料都聚焦静态图和AI场景,找不到相关解决办法,我需要在Python脚本里拿到完整的多帧GIF对象。


main.py

from imageEditUI.main_webui import *

# Press the green button in the gutter to run the script.
if __name__ == '__main__':
    app()

main_webui.py

import gradio as gr
import numpy as np
from imageEditUI.z_image_editing import *
from imageEditUI.z_gif_handler import *


def app():
    def sepia_image(input_img):
        # choose: sepia, bw, or negative (so far)
        return color_filters(input_img, 'sepia')

    def flip_image(x):
        return np.fliplr(x)

    def rembg_image(input_img, rgb_high, rgb_low):
        rgb_high = rgb_high.lstrip('#')
        rgb_low = rgb_low.lstrip('#')
        high = tuple(int(rgb_high[i:i + 2], 16) for i in (0, 2, 4))
        low = tuple(int(rgb_low[i:i + 2], 16) for i in (0, 2, 4))
        return remColor(input_img, high, low)

    def rembg_gif(input_img, rgb_high, rgb_low):
        rgb_high = rgb_high.lstrip('#')
        rgb_low = rgb_low.lstrip('#')
        high = tuple(int(rgb_high[i:i + 2], 16) for i in (0, 2, 4))
        low = tuple(int(rgb_low[i:i + 2], 16) for i in (0, 2, 4))
        return master(input_img, high, low)

    def floodFill_ui(image_input_remBGCol):
        return floodFill(image_input_remBGCol)

    def gif_rembgcolor(image_input_remBGCol, high, low):
        print(type(image_input_remBGCol))
        return gif_main(image_input_remBGCol, high, low)

    with gr.Blocks() as demo:
        gr.Markdown("Select your edits below:")
        # set output image height var:
        output_height = 400
        with gr.Tab("GIF"):
            with gr.Row():
                gif_input = gr.Image(type='pil', interactive=True)
                gif_output = gr.Image(height=output_height)
            with gr.Row():
                high_gif = gr.ColorPicker(label="Choose high color")
                low_gif = gr.ColorPicker(label="Choose low color")
            gif_button = gr.Button("Remove Background Color")
            gif_button2 = gr.Button("Remove Background Color v2")
        with gr.Tab("Color"):
            with gr.Row():
                image_input_remBGCol = gr.Image()
                image_output_remBGCol = gr.Image(height=output_height)
            with gr.Row():
                rgb_high = gr.ColorPicker(label="Choose high color")
                rgb_low = gr.ColorPicker(label="Choose low color")
            remBGCol_button = gr.Button("Remove Background Color")
            selectArea_button = gr.Button("Select area of image")
        with gr.Tab("Flip Image"):
            # filter: FLIP
            with gr.Row():
                image_input = gr.Image()
                image_output = gr.Image(height=output_height)
            image_button = gr.Button("Flip")

        remBGCol_button.click(rembg_image,
                              inputs=[image_input_remBGCol, rgb_high, rgb_low],
                              outputs=image_output_remBGCol)
        selectArea_button.click(floodFill_ui, inputs=image_input_remBGCol, outputs=image_output_remBGCol)
        image_button.click(flip_image, inputs=image_input, outputs=image_output)
        gif_button.click(rembg_gif, inputs=[gif_input, high_gif, low_gif], outputs=gif_output)
        gif_button2.click(gif_rembgcolor, inputs=[gif_input, high_gif, low_gif], outputs=gif_output)
    demo.launch()

z_gif_handler.py

from PIL import Image, ImageFile
########################################################################################################################
# Manages the splitting of gifs into images, delivering individual images to the image editor
# module, and recompiling gifs before sending back to webui
########################################################################################################################


def split_gif(im):
    # loop through frames saving each to bytesio
    myImages = []
    i = 0
    for i in range(i, im.n_frames):
        im.seek(i)
        myImages.append(im)

    return myImages


def deliver_to_editor(gif_frames, tool_selection):
    if tool_selection == 'chroma':
        return


def gif_main(input_image, choice, high=(165, 253, 171), low=(1, 77, 0)):
    gif_frames = split_gif(input_image)
    gif_frames[0].save('assets/images/final.gif', save_all=True, append_images=gif_frames[1:], duration=100, loop=0)

报错信息

C:\Users\Admin\PycharmProjects\ImageEditUI\venv\Scripts\python.exe C:\Users\Admin\PycharmProjects\ImageEditUI\imageEditUI\main.py 
Running on local URL:  http://127.0.0.1:7860

To create a public link, set `share=True` in `launch()`.
<class 'PIL.Image.Image'>
Traceback (most recent call last):
  File "C:\Users\Admin\PycharmProjects\ImageEditUI\venv\Lib\site-packages\gradio\routes.py", line 437, in run_predict
    output = await app.get_blocks().process_api(
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Admin\PycharmProjects\ImageEditUI\venv\Lib\site-packages\gradio\blocks.py", line 1352, in process_api
    result = await self.call_function(
             ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Admin\PycharmProjects\ImageEditUI\venv\Lib\site-packages\gradio\blocks.py", line 1077, in call_function
    prediction = await anyio.to_thread.run_sync(
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Admin\PycharmProjects\ImageEditUI\venv\Lib\site-packages\anyio\to_thread.py", line 33, in run_sync
    return await get_asynclib().run_sync_in_worker_thread(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Admin\PycharmProjects\ImageEditUI\venv\Lib\site-packages\anyio\_backends\_asyncio.py", line 877, in run_sync_in_worker_thread
    return await future
           ^^^^^^^^^^^^
  File "C:\Users\Admin\PycharmProjects\ImageEditUI\venv\Lib\site-packages\anyio\_backends\_asyncio.py", line 807, in run
    result = context.run(func, *args)
             ^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Admin\PycharmProjects\ImageEditUI\imageEditUI\main_webui.py", line 38, in gif_rembgcolor
    return gif_main(image_input_remBGCol, high, low)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Admin\PycharmProjects\ImageEditUI\imageEditUI\z_gif_handler.py", line 40, in gif_main
    gif_frames = split_gif(input_image)
                 ^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Admin\PycharmProjects\ImageEditUI\imageEditUI\z_gif_handler.py", line 21, in split_gif
    for i in range(i, im.n_frames):
                      ^^^^^^^^^^^
  File "C:\Users\Admin\PycharmProjects\ImageEditUI\venv\Lib\site-packages\PIL\Image.py", line 528, in __getattr__
    raise AttributeError(name)
AttributeError: n_frames

内容的提问来源于stack exchange,提问作者Logan Price

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 08:40:04