在Python中获取GIF图像的第一帧?

时间:2019-03-24 19:17:27

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

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)文件,下载时间太长。

有什么方法可以只下载动画的第一帧?

2 个答案:

答案 0 :(得分:3)

我不会为您写全部内容,这将涉及解析GIF文件的二进制内容,但这是一个使用受欢迎的第三方requests module(使用section文档中的信息)。希望这会为您提供一个良好的起点。

@property
def allowed_methods(self):
    allowed_methods = super().allowed_methods
    allowed_methods.remove('GET')
    return allowed_methods

答案 1 :(得分:1)

按照@martineau的建议张贴我的答案。

  1. 按照here
  2. 所示构建GIF库。
  3. 执行以下代码,然后等待将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]中的示例。