【问题标题】:Getting the first frame of GIF image in Python?在 Python 中获取 GIF 图像的第一帧?
【发布时间】:2019-08-15 02:09:03
【问题描述】:

Getting the first frame of a GIF image without downloading all the other frames

↑ 这个帖子几乎是我想知道的同一个问题。 但就我而言,我使用的是 Python 3.6 和 urllib。

import urllib
import requests

img_file = urllib.request.urlopen(img_url, timeout=10)

f = open('/img/' + img_name, 'wb')
f.write(img_file.read())
f.close()

我正在使用此代码来获取图像文件。但是对于 GIF 或动 jpg(带有 jpg 文件扩展名的 GIF)文件,下载时间太长了。

有没有办法只下载动画的第一帧?

【问题讨论】:

    标签: python python-3.x request urllib gif


    【解决方案1】:

    我不会为你写完整的东西,这将涉及解析 GIF 文件的二进制内容,但这里有一个使用流行的第三方 requests module 增量下载文件的示例(使用信息在这个section 的文档)。希望这将为您提供一个良好的起点。

    import requests
    
    img_url = 'https://upload.wikimedia.org/wikipedia/commons/d/d3/Newtons_cradle_animation_book_2.gif'
    #img_filename = 'test.gif'
    
    response = requests.get(img_url, stream=True)
    if response.status_code != 200:
        print('Error:', response.status_code)
    else:
        header = response.raw.read(6)
        print(header)  # b'GIF89a'
    
    #    # Download whole file in chunks and save locally.
    #    with open(img_filename, 'wb') as f:
    #        for chunk in response.iter_content(chunk_size=128):
    #            f.write(chunk)
    
    print('done')
    

    【讨论】:

    • 只是添加答案:here 我有一个不错的小库,能够从 GIF 图像中读取单独的帧,并带有 Python 使用示例。
    • @hidefromkgb:如果我没记错的话,您的库看起来需要一个完整下载的文件可用,我认为这个问题的重点是避免下载整个内容只是为了获得第一帧。也就是说,OP 可能能够读取您的 C 源代码,以帮助弄清楚如何解析增量下载的文件。
    • 它没有。引用文档:> 也支持部分 GIF,但仅支持一帧的粒度。
    • @hidefromkgb:在Python usage example 部分,代码执行file = open(file, "rb"),然后在随后的GIF_Load(file.read(), size, ...) 调用中读取整个文件的内容,因此尚不清楚它如何用于一种增量方式——如何知道一帧数据的大小?如果您有可以解决此问题所需的答案,请发布。
    • 在读取 GIF 数据之前无法知道压缩的帧大小,所以唯一简单的方法是读取接下来的几个(千)字节然后尝试加载 GIF,如果没有则重复图像已生成。
    【解决方案2】:

    按照@martineau 的建议发布我的答案。

    1. 构建GIF库,如图here
    2. 执行下面的代码,等待result.png被写入磁盘:
    from PIL import Image
    from platform import system
    from ctypes import string_at, Structure, c_long as cl, c_ubyte, \
                       py_object, pointer, POINTER as PT, CFUNCTYPE, CDLL
    import requests
    
    class GIF_WHDR(Structure): _fields_ = \
       [("xdim", cl), ("ydim", cl), ("clrs", cl), ("bkgd", cl),
        ("tran", cl), ("intr", cl), ("mode", cl), ("frxd", cl), ("fryd", cl),
        ("frxo", cl), ("fryo", cl), ("time", cl), ("ifrm", cl), ("nfrm", cl),
        ("bptr", PT(c_ubyte)), ("cpal", PT(c_ubyte))]
    
    def GIF_Load(lgif, file, size):
        def WriteFunc(d, w):
            list = d.contents.value
            if (len(list) == 0):
                list.append(Image.frombytes("L", (w[0].frxd, w[0].fryd),
                                  string_at(w[0].bptr, w[0].frxd * w[0].fryd)))
                list[0].putpalette(string_at(w[0].cpal, w[0].clrs * 3))
        list = []
        lgif.GIF_Load(file, size,
                      CFUNCTYPE(None, PT(py_object), PT(GIF_WHDR))(WriteFunc),
                      None, pointer(py_object(list)), 0)
        return list
    
    chunk = 32768
    img = "wikipedia/commons/d/d3/Newtons_cradle_animation_book_2.gif"
    
    lgif = CDLL(("%s.so", "%s.dll")[system() == "Windows"] % "./gif_load")
    
    size = -1
    file = b""
    response = requests.get("https://upload.wikimedia.org/" + img, stream = True)
    if response.status_code != 200:
        print('Error:', response.status_code)
    else:
        while size < len(file):
            size = len(file)
            file += response.raw.read(chunk)
            list = GIF_Load(lgif, file, len(file))
            if (len(list) == 1):
                list[0].save("result.png")
                break
        print("Read %d bytes\n" % len(file))
    

    请记住,这只是一个说明性示例;它不支持现代 GIF 中存在的许多东西,例如隔行扫描和透明。如需完全兼容的版本,请参阅 [1] 中的示例。

    【讨论】:

      猜你喜欢
      • 2012-03-19
      • 2014-12-01
      • 2019-04-21
      • 2021-12-05
      • 1970-01-01
      • 1970-01-01
      • 2014-04-15
      • 2010-10-31
      • 2019-03-02
      相关资源
      最近更新 更多