LoginSignup
5
6

More than 5 years have passed since last update.

PythonのPILで書き出したGIF画像をつなげて動画GIFを作る

Last updated at Posted at 2013-01-30

参考URL
[http://pastebin.com/Rr7dAxbF]
[http://www.tohoho-web.com/wwwgif.htm]
[http://www.marguerite.jp/Nihongo/Labo/Image/GIF.html]

agif.py

# -*- coding: utf-8 -*-
import struct
import math
from cStringIO import StringIO
from PIL import Image, GifImagePlugin


class AGIF(object):
    """
    >>> from PIL import ImageDraw, ImageFont
    >>> agif = AGIF(4)
    >>> size = (80, 15)
    >>> img = Image.new("RGB", size, "white")
    >>> draw = ImageDraw.Draw(img)
    >>> text = "Hello, world!"
    >>> for i in range(len(text)):
    ...     draw.rectangle((0, 0) + size, fill="white")
    ...     draw.text((0, 0), text[:i], fill="black")
    ...     agif.paste(img, duration=0.2)
    >>> agif.save("example1.gif")


    >>> import urllib
    >>> from cStringIO import StringIO
    >>> from PIL import ImageOps
    >>> url = "http://www.python.org/community/logos/python-powered-h-140x182.png"
    >>> istream = StringIO(urllib.urlopen(url).read())
    >>> image = Image.open(istream)
    >>> square = ImageOps.fit(image, (240, 240))

    >>> agif = AGIF(128)
    >>> for i in range(0, 360, 5):
    ...     agif.paste(square.rotate(i), 0.03)
    >>> agif.save("example2.gif")
    """

    def __init__(self, colors, loop=0):
        assert colors in [2, 4, 8, 16, 32, 64, 128, 256]
        self.colors = colors
        self.loop   = loop
        self.buf    = StringIO()
        self.pasted = False


    def paste(self, image, duration=0.1):
        image = self._convert_to_gif(image)
        if not self.pasted:
            self._write_header(image)
        self._write_image(image, duration)
        self.pasted = True


    def save(self, file):
        if isinstance(file, basestring):
            file = open(file, "w")
        self.buf.seek(0)
        file.writelines(self.buf)
        file.write("\x3b")


    def _convert_to_gif(self, image):
        """半透明なPNG画像を白色の背景とマージする"""
        if image.mode == "RGBA":
            merged = Image.new("RGBA", image.size, (255, 255, 255, 0))
            merged.paste(image, (0, 0) + image.size, image)
            image = merged.convert("RGB")
        return image.convert("P", palette=Image.ADAPTIVE, colors=self.colors)


    def _write_header(self, image):
        buf = self.buf
        buf.write("GIF89a")
        width, height = image.size
        buf.write(struct.pack("< H", width))
        buf.write(struct.pack("< H", height))
        buf.write(chr(0xe0 | int(math.log(self.colors, 2) - 1)))
        buf.write("\x00\x00")

        buf.write(GifImagePlugin.getheader(image)[1][:self.colors*3])
        buf.write("\x21\xff\x0bNETSCAPE2.0")
        if self.loop == 0:
            buf.write("\x03\x01\x00\x00")
        elif self.loop != 1:
            buf.write("\x03\x01")
            buf.write(struct.pack("< H", self.loop-1))
        buf.write("\x00")


    def _write_image(self, image, duration):
        buf = self.buf
        buf.write("\x21\xf9\x04\x08")
        buf.write(struct.pack("< H", duration * 100))
        buf.write("\x00\x00")

        if self.pasted:
            data = GifImagePlugin.getdata(image)
            header = list(data[0])
            header[-2] = chr(128 | int(math.log(self.colors, 2) - 1))
            buf.write("".join(header)[:-1])
            buf.write(GifImagePlugin.getheader(image)[1][:self.colors*3])
            buf.write(header[-1])
            for d in data[1:]:
                buf.write(d)
        else:
            for d in GifImagePlugin.getdata(image):
                buf.write(d)

if __name__ == '__main__':
    import doctest
    doctest.testmod()
5
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
6