Free Lossless Image Format (FLIF)


Added support for up to 16-bit color depth (per channel, so up to 64 bit per pixel). I just commited it to github.

I didn't really test it much yet, I only tried it on one image, this one:
http://www.brucelindbloom.com/index.html?ReferenceImages.html
(DeltaE_16bit_gamma2.2.tif)

The uncompressed PPM file is 36,864 kilobytes (3072x2048 pixels at 6 bytes per pixel).
The PNG file ImageMagick's "convert" produces is 7,607,128 bytes. Brute-force PNG crushing brings that down to 6,409,406 bytes.
With Adam7 interlacing ("convert -interlace PNG") it is 9,142,487 bytes. Brute-force PNG crushing brings that down to 7,850,138 bytes.

The FLIF file is 4,490,024 bytes.
The FLIF file without interlacing ("flif -ni") is 4,177,291 bytes.

Oh and one other silly little change I made: you can now drop the "-d" when decoding a FLIF file. And I changed the ASCII art again, but you only see that if you use at least two -v. By default it is silent now, as long as everything is OK, which is how command line programs should behave :) .
 
 
If you want to make it behave more like other unix/linux tools, why not implement the GNU interface standard.  I only mention because I just tried -vv to make it double verbose (so I could see your new ASCII art of course) and it took me a moment to notice that my -ni didn't have a double dash in front, so you clearly don't support option bundling (or whatever it's officially called).

I've just created a 16-bit PNG of a 12-bit camera file (plus interpolation and exposure compensation etc.).  So far it's processing though FLIF fine.
 
Yes, 65535x65535 is the maximum image resolution. If this ever becomes a problem, then it is easily solved by handling 0x0000 as a special size marker (which would be a 0x0 image, which does not make sense anyway), followed by the actual size as two 32 bit ints, or something like that.

I'm not sure that you're gonna have a problem for a while, but they are heading that way:

http://arstechnica.co.uk/gadgets/2015/09/canon-unveils-250-megapixel-prototype-dslr-camera-sensor/

That's 19580×12600, which you're still covered for and it's not even released in a product as yet. One day soon though...

D.
 
Hmm, something went wrong with the process there.  Converting the 16-bit png to FLIF took ten minutes, converting it back took four.  But the resulting PNG file, despite being the right resolution and still 16-bit per channel, appeared to be plain black.  It's also only about 2/3rds the size of the input png.

Are you planning to make a viewer, so I can see what the FLIF file looks like unconverted via an intermediate format, and which could also exhibit the flif format's progressive loading of files?
 
Try decoding to .pnm instead of .png...

An image looking too black could be because of missing metadata (FLIF only encodes the pixels). E.g. if only the 12 least significant bits out of 16 are used, then without additional info, that looks very dark...
 
If you want to make it behave more like other unix/linux tools, why not implement the GNU interface standard.  I only mention because I just tried -vv to make it double verbose (so I could see your new ASCII art of course) and it took me a moment to notice that my -ni didn't have a double dash in front, so you clearly don't support option bundling (or whatever it's officially called).

Right. Using getopt() now so option parsing is more flexible and more standard now.

Are you planning to make a viewer, so I can see what the FLIF file looks like unconverted via an intermediate format, and which could also exhibit the flif format's progressive loading of files?

Well, PNM is just uncompressed image data, so if you decode to that (e.g. to a file that is actually in RAM), you can use any viewer. Too bad PNM does not support alpha. You can try the progressive loading by using --quality and/or --scale.
 
 
Try decoding to .pnm instead of .png...

An image looking too black could be because of missing metadata (FLIF only encodes the pixels). E.g. if only the 12 least significant bits out of 16 are used, then without additional info, that looks very dark...

My pnm file also appears to be totally black.  I've tried brightening it to +127 (percent I guess, but I don't know what GIMP uses) and +127 contrast, but I only get a mid-grey image with no visible detail still.

I'll try regenerating the flif file and seeing if it converted back to pnm looks any different.  Just rebuilding flif with the most recent change, so I'll see how that goes.
 
The new cli is cool - now I can type '-nvv' as my options rather than the rather long-winded '-ni -v -v'.

Unfortunately though, the generated flif file is binary identical.  So unsurprisingly it results in the same black pnm file on processing.

I can PM you the flif file if you'd like.
 
The new cli is cool - now I can type '-nvv' as my options rather than the rather long-winded '-ni -v -v'.

Unfortunately though, the generated flif file is binary identical.  So unsurprisingly it results in the same black pnm file on processing.

I can PM you the flif file if you'd like.

Can you send me the original as a png file instead? And what happens if you use ImageMagick to convert the png to pnm?
 
There was a bug in my PNG loading code for 16-bit PNGs, so they just got misread. That probably explains the problems you got. I only tested PNM input and PNM and PNG output, not PNG input. It should work now.
 
Hmm, did my post get lost?

But yeah, that seems to have fixed it - thanks for the quick fix!

FWIW, the FLIF file is 24MB versus 29MB for the PNG (and 36MB for the PNM).
 
Well done!
Hope that FLIF will spread to the world.
 
Last edited by a moderator:
I'm adding rudimentary support for animation to FLIF.

Every frame has to be the same size as the first frame, and each frame completely replaces the previous frame.
(maybe later I'll add support for frames which are smaller and have an offset, and frames that combine with the previous frame)

The delay between frames can any integer number of milliseconds between 0 and 60000 (one minute). At the moment there's no way yet to tell the encoder what delay to use, so it just uses an arbitrary number (100ms).

I don't know if I should encode a number for "number of loops" (where 0 would be "loops forever"). I have never encountered an animation that does anything else than loop forever.

The frames get encoded in an interlaced way, so any prefix of the file gives a low-res, chroma subsampled version of the entire animation. So the animation doesn't get loaded frame by frame. I'm assuming here that animations are going to be short and there's enough memory to store all the frames. If you would use this to encode entire movies, a sensible thing to do would be to start a new FLIF file every second or so.

At the moment, the pixel estimation and MANIAC context model don't take animation into account yet. Still, the animated FLIF file will tend to be somewhat smaller than the sum of the sizes of FLIF-compressed individual frames, because the MANIAC trees are shared between the frames, so if the frames are "similar", that does help a bit.

Perhaps compression could be further improved by taking the previous frame(s) into account in the pixel estimation and MANIAC model. Inter frame prediction would turn it into a "real" video codec, but I don't want to go there at the moment -- it would complicate things quite a bit.

Anyway, here are some preliminary results:

https://en.wikipedia.org/wiki/GIF#/media/File:Rotating_earth_(large).gif
1,429,302  GIF file
1,325,714  lossless BPG file
1,300,226  MNG file
908,882     APNG file (using zlib)
852,690     APNG file (using 7zip)
837,838     APNG file (using Zopfli)
821,984     FLIF file
748,510     FLIF file without interlacing (no progressive decoding possible)

 
 
Last edited by a moderator:
I wonder how much work it would be to add support for this to upstream common utilities and libraries, like imagemagick and such.
 
I wonder how much work it would be to add support for this to upstream common utilities and libraries, like imagemagick and such.

Probably not that much work in terms of actual programming effort, but it would take some time to get there: first I need to understand the code and conventions of the target program/community (e.g. ImageMagick, GIMP, SDL, browsers), then I have to do the actual integration (which should be relatively easy), and then I have to get my contribution accepted -- probably not always trivial for an external contributor.

The best way to do it would probably to first make a library, say libflif, with an API that is easy to use, maybe similar to that of libjpeg or libpng. That way improvements to the implementation would immediately become available to any application.

Before any of this can be done, the file format first has to be finalized. Once it becomes "really" public (i.e. not just a prototype on github but something that is available in common utilities), I'll have to make sure that backwards compatibility is ensured so newer versions can still decode FLIF files created by older versions (and older versions gracefully decode or refuse to decode newer FLIF files). At the moment, I still want to have the "luxury" of being able to change anything without risking to break stuff.

Anyway, all in all, adding support for FLIF to all applications will be quite a lot of effort. Not just coding effort, but mostly convincing other teams to accept it. The full encoding/decoding of single images should be relatively easy, and in some cases (e.g. a GIMP export/import plugin) that's all that's needed. The progressive decoding thing, especially if it's supposed to be clever and stops reading the file as soon as enough detail is known, that would be much trickier. It cannot really be done in an isolated plugin, it would have to be quite tightly integrated with the application (web browsers and image viewers, I guess) and require non-trivial code changes in other parts of the program than just the image decoding routines -- I would guess that most web browsers always try to completely download all files they need, so this "stop the download, we have enough data to decode a reasonable image!" functionality would have to be added.

I am actually half considering to do something like what they did for APNG:
https://www.kickstarter.com/projects/374397522/apngasm-foss-animated-png-tools-and-apng-standardi/description
 
 
Here are some more preliminary results:

http://davidmz.github.io/apng-canvas/images/APNG-Icos4D.png
991,744      original APNG file
1,010,113   re-encoded APNG file (using zlib)
961,921      re-encoded APNG file (using 7lib)
960,443      re-encoded APNG file (using Zopfli)
866,483      lossless BPG file
597,273      FLIF file
466,861      FLIF file without interlacing
1,175,176   sum of PNG files

http://davidmz.github.io/apng-canvas/images/pyani.png
1,016,499   APNG file
733,760      lossless BPG file
597,150      FLIF file
567,793      FLIF file without interlacing
987,310      sum of PNG files

http://davidmz.github.io/apng-canvas/images/APNG-cube.png
996,020    original APNG file
1,154,497 re-encoded APNG file (using zlib)
1,078,420 re-encoded APNG file (using Zopfli)
1,064,263  lossless BPG file
887,901    FLIF file
801,539    FLIF file without interlacing
1,186,916   sum of PNG files

So far, so good.
However, if only part of the image changes in each frame (which the other formats can handle using frames that are smaller than the first frame, and/or by using "combining" frames), then FLIF does not perform that well:

http://davidmz.github.io/apng-canvas/images/clock.png
23,680    APNG file
32,174    lossless BPG file
74,276    FLIF file
51,470    FLIF file without interlacing
326,904  sum of PNG files

https://media.giphy.com/media/nLfEVuqqk9puw/giphy.gif
727,686   GIF file
490,895   APNG file (using zlib)
459,967   APNG file (using 7lib)
456,932   APNG file (using Zopfli)
1,020,851   lossless BPG file
554,810    FLIF file
488,830    FLIF file without interlacing
578,499    sum of PNG files


So I guess there is some room for improvement, but it looks quite good already. Especially if you take into account that progressive decoding is possible with FLIF, and with none of the existing formats. I'll try to show an example of that later.
 
It was to be expected for partial updates. There are so many tricks you can use for video, even more if you allow multiple pass encoding.
 
In terms of animation, webm is the one to match. It enjoys some popularity, and also features sound.
http://i.4cdn.org/wsg/1442933145986.webm

Its a video codec, but it scales down into gif territory. With these low framerates, maybe FLIF can cover that use-case.

Btw, is there any way of getting hardware-decoding going for FLIF? Maybe with DSP chips or somesuch.
 
Last edited by a moderator:
Back
Top