Page 1 of 1

gifload, a GIF image loader in pure LuaJIT+FFI

Posted: Mon Aug 01, 2016 3:11 pm
by pgimeno
Inspired by this thread, I've decided to create a GIF decoder in pure LuaJIT+FFI.

It comes with a demo .love file that displays a (possibly animated) GIF. The demo is designed to be used from the command line.

Command-line freaks like me may wish to create a fused executable and modify the for loop in the getopts function so that it starts in 1 rather than 2 [Edit: since version 1.0.2, this is now done automatically by reading love.filesystem.isFused()]

The project:

https://notabug.org/pgimeno/gifload

The releases page contains a download of the demo.

I've tested it as much as I could, but if you find any problems, please report them in the issue tracker at https://notabug.org/pgimeno/gifload/issues

Re: gifload, a GIF image loader in pure LuaJIT+FFI

Posted: Mon Aug 01, 2016 4:11 pm
by airstruck
Whoa, you really went for it there! :shock:

Do you plan to include some kind of mid- or high-level API, like some convenience functions to wrap all the stuff that looks like gif.imgs[prevframe*5-1] and gif.imgs[nframe*5-2], or something like DoFrame from the example? The example code in main.lua pretty much made my head spin the whole way through. It seems like a lot of it could be moved off into the library somehow, though.

Re: gifload, a GIF image loader in pure LuaJIT+FFI

Posted: Mon Aug 01, 2016 5:22 pm
by zorg
Exactly what i thought at first, something like a gif:draw() to be used in love.draw (or even lg.draw), but since this is mostly a loader lib, from what i can tell, seems like the users can do whatever they want to with the information it loaded in. :D

Re: gifload, a GIF image loader in pure LuaJIT+FFI

Posted: Mon Aug 01, 2016 8:07 pm
by pgimeno
Yes, it's intended to be a loader library. It's true that the gif.imgs[ ] format is somewhat inconvenient. I'm going to include a method to simplify obtaining the frame data, along the lines of:

Code: Select all

function gif:frame(n)
  n = (n-1) % self.nframes + 1
  return self.imgs[n*5-2], self.imgs[n*5-1], self.imgs[n*5], self.imgs[n*5-3], self.imgs[n*5-4]
end
so you can do:

Code: Select all

  local img, x, y, delay, disposal = gif:frame(n)
I'm also pondering on whether to add a flag to "flatten" the images on load. By that I mean to apply the disposal method to each image, generating the actual frames that can be drawn directly without needing to handle disposal (all frames would have disposal=0).

The problem is that it's going to be slow. I can use canvases and obtain the data with [wiki]Canvas:newImageData[/wiki] (slow), adding another dependency, or I can operate on ImageData directly, having a "hidden" screen to handle certain disposal methods.

It makes the most sense to have the GIF images flattened rather than having to handle disposal, but I'm concerned about performance.

Re: gifload, a GIF image loader in pure LuaJIT+FFI

Posted: Mon Aug 01, 2016 8:23 pm
by airstruck
I'm definitely in favor of the gif:frame(n) thing, it will improve readability. Even if it's "just" a loader (maybe especially if it's just a loader), I think the accessibility and understandability of the format is important. After all, if getting it into a convenient format weren't important, you could just load the raw data, maybe uncompress it, and call that a GIF loader.
I'm also pondering on whether to add a flag to "flatten" the images on load. By that I mean to apply the disposal method to each image, generating the actual frames that can be drawn directly without needing to handle disposal (all frames would have disposal=0).
What about a separate companion module for drawing gifs in your format? Leave them "un-flat" and have a "gifdraw" module with a few methods that draw things loaded by the "gifload" module. I think ideally your main.lua example could mostly just use those two modules and be pretty simple, to the point where someone who comes across the library because they just want to slap a dancing banana into a cutscene or something will think "hey, this looks easy" instead of fleeing in terror ;)

I'm imagining it looking something like this:

Code: Select all

local GifLoad = require 'gifload'
local GifDraw = require 'gifdraw'

-- GifLoad.read is a wrapper for everything under "Example: loading a GIF file"
-- or maybe it's part of GifDraw so you don't need to require 'gifload' at all in user code.
local bananaGif = GifLoad.read('assets/banana.gif')
local banana = GifDraw(bananaGif)

function love.update (dt)
    banana:update(dt) -- this just lets the GifDraw instance figure out what frame it's on.
end

function love.draw ()
    local x = 400 - bananaGif.width * 0.5 -- or maybe copy width and height to the GifDraw instance
    local y = 300 - bananaGif.height * 0.5
    banana:draw(x, y)
end
All the low-level stuff would still be there, this would just make it more approachable for the most common use cases. GifDraw instances could have more methods for stuff like changing the time scale or resetting the animation.

Re: gifload, a GIF image loader in pure LuaJIT+FFI

Posted: Tue Aug 02, 2016 2:05 pm
by bobbyjones
Do you have a gif of love playing a gif? Maybe you can use gifcat to record a gif of love playing a gif.

Re: gifload, a GIF image loader in pure LuaJIT+FFI

Posted: Tue Aug 02, 2016 11:06 pm
by pgimeno
airstruck wrote:What about a separate companion module for drawing gifs in your format? Leave them "un-flat" and have a "gifdraw" module with a few methods that draw things loaded by the "gifload" module. I think ideally your main.lua example could mostly just use those two modules and be pretty simple, to the point where someone who comes across the library because they just want to slap a dancing banana into a cutscene or something will think "hey, this looks easy" instead of fleeing in terror ;)
Hm, food for thought.

In my mind, the main uses of this library are (1) an HTML browser, in which case the complications of rendering the GIF pale in comparison to rendering the HTML, and (2) an animation loader for animated sprites, in which case typically the coder will have control over the GIF and will be able to flatten it (e.g. using "Unoptimize" in GIMP), making everything but the images themselves irrelevant. A possible third use would be to load single-frame GIFs for whatever purpose, like in the thread that inspired me. It was not really intended as a video player; that's what LÖVE's Theora support is for.

With these two main use cases in mind, I thought that it would be enough to provide the loader and just in case, the frame information, and let implementers deal with what the timing/disposal issues.

But given that it shouldn't be too time-consuming to create a companion animation rendering library, I might just do that. The only problem is that I already want to move on to other projects... attention span and all that, you know. This project had a bunch of unforeseen hurdles to jump that caused me some burnout.

Re: gifload, a GIF image loader in pure LuaJIT+FFI

Posted: Wed Aug 03, 2016 1:01 am
by airstruck
Yeah, it's definitely not worth the burnout! I might actually take a crack at it just for fun. You pretty much did all the work already, so I'd just be wrapping that up in another module. If I fork that repo some time this weekend, you'll know why. :)

Re: gifload, a GIF image loader in pure LuaJIT+FFI

Posted: Tue Jan 02, 2018 9:23 pm
by ReFreezed
Thanks for making this! It's been useful in one of my utility programs.

Re: gifload, a GIF image loader in pure LuaJIT+FFI

Posted: Sat Apr 07, 2018 10:53 pm
by pgimeno
There's been a minor fix to the demo program, to make the command line work correctly with 11.0 when not fused. The library itself is already compatible with 11.0 and needs no changes.