开发者

Saving animated GIFs using PIL (image saved does not animate)

开发者 https://www.devze.com 2023-02-03 03:34 出处:网络
I have Apache2 + PIL + Django + X-sendfile. My problem is that when I save an animated GIF, it won\'t \"animate\" when I output through the browser.

I have Apache2 + PIL + Django + X-sendfile. My problem is that when I save an animated GIF, it won't "animate" when I output through the browser.

Here is my code to display the image located outside the public accessible directory.

def raw(request,uuid):
    target = str(uuid).split('.')[:-1][0]
    image = Uploads.objects.get(uuid=target)

    path = image.path
    filepath = os.path.join(path,"%s.%s" % (image.uuid,image.ext))

    response = HttpResponse(mimetype=mimetypes.guess_type(filepath)) 
    response['Content-Disposition']='filename="%s"'\
                                    %smart_str(image.filename)
    response["X-Sendfile"] = filepath
    response['Content-length'] = os.stat(filepath).st_si开发者_开发技巧ze

    return response

UPDATE

It turns out that it works. My problem is when I try to upload an image via URL. It probably doesn't save the entire GIF?

def handle_url_file(request):
    """
    Open a file from a URL.
    Split the file to get the filename and extension.
    Generate a random uuid using rand1()
    Then save the file.
    Return the UUID when successful.
    """

    try:
        file = urllib.urlopen(request.POST['url'])
        randname = rand1(settings.RANDOM_ID_LENGTH)
        newfilename = request.POST['url'].split('/')[-1]
        ext = str(newfilename.split('.')[-1]).lower()
        im = cStringIO.StringIO(file.read()) # constructs a StringIO holding the image
        img = Image.open(im)

        filehash = checkhash(im)

        image = Uploads.objects.get(filehash=filehash)
        uuid = image.uuid

        return "%s" % (uuid)

    except Uploads.DoesNotExist:

        img.save(os.path.join(settings.UPLOAD_DIRECTORY,(("%s.%s")%(randname,ext))))
        del img

        filesize = os.stat(os.path.join(settings.UPLOAD_DIRECTORY,(("%s.%s")%(randname,ext)))).st_size
        upload = Uploads(
            ip          = request.META['REMOTE_ADDR'],
            filename    = newfilename,
            uuid        = randname,
            ext         = ext,
            path        = settings.UPLOAD_DIRECTORY,
            views       = 1,
            bandwidth   = filesize,
            source      = request.POST['url'],
            size        = filesize,
            filehash    = filehash,
        )

        upload.save()
        #return uuid
        return "%s" % (upload.uuid)
    except IOError, e:
        raise e

Any ideas?

Thanks!

Wenbert


Where does that Image class come from and what does Image.open do?

My guess is that it does some sanitizing of the image data (which is a good thing), but does only save the first frame of the Gif.

Edit:

I'm convinced this is an issue with PIL. The PIL documentation on GIF says:

PIL reads GIF87a and GIF89a versions of the GIF file format. The library writes run-length encoded GIF87a files.

To verify, you can write the contents of im directly to disk and compare with the source image.


The problem is saving a PIL-opened version of the image. When you save it out via PIL, it will only save the first frame.

However, there's an easy workaround: Make a temp copy of the file, open that with PIL, and then if you detect that it's an animated GIF, then just save the original file, not the PIL-opened version.

If you save the original animated GIF file and then stream it back into your HTTP response, it will come through animated to the browser.

Example code to detect if your PIL object is an animated GIF:

def image_is_animated_gif(image):
    # verify image format
    if image.format.lower() != 'gif':
        return False

    # verify GIF is animated by attempting to seek beyond the initial frame
    try:
        image.seek(1)
    except EOFError:
        return False
    else:
        return True
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号