[aseprite] 29/250: New FLI/FLC encoder/decoder (fix #7)

Tobias Hansen thansen at moszumanska.debian.org
Sun Dec 20 15:27:08 UTC 2015


This is an automated email from the git hooks/post-receive script.

thansen pushed a commit to branch master
in repository aseprite.

commit 3d700ab94c1f261a17c554c8dc3b59d8474d9f1a
Author: David Capello <davidcapello at gmail.com>
Date:   Thu Sep 10 16:10:31 2015 -0300

    New FLI/FLC encoder/decoder (fix #7)
---
 .gitmodules                 |   3 +
 README.md                   |   1 -
 src/CMakeLists.txt          |   1 +
 src/README.md               |   1 +
 src/app/CMakeLists.txt      |   2 +-
 src/app/file/fli/README     |  35 ---
 src/app/file/fli/fli.cpp    | 725 --------------------------------------------
 src/app/file/fli/fli.h      | 103 -------
 src/app/file/fli_format.cpp | 278 ++++++++---------
 src/flic                    |   1 +
 10 files changed, 131 insertions(+), 1019 deletions(-)

diff --git a/.gitmodules b/.gitmodules
index 83da9fb..bcc6806 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -13,3 +13,6 @@
 [submodule "third_party/libwebp"]
 	path = third_party/libwebp
 	url = https://chromium.googlesource.com/webm/libwebp
+[submodule "src/flic"]
+	path = src/flic
+	url = https://github.com/aseprite/flic.git
diff --git a/README.md b/README.md
index 81076bd..6e42528 100644
--- a/README.md
+++ b/README.md
@@ -73,7 +73,6 @@ of the following projects created by third-parties:
 * [Google Test](http://code.google.com/p/googletest/) - [gtest license](https://github.com/aseprite/aseprite/tree/master/docs/licenses/gtest-LICENSE.txt)
 * [XFree86](http://www.x.org/) - [XFree86 license](https://github.com/aseprite/aseprite/tree/master/docs/licenses/XFree86-LICENSE.txt)
 * [curl](http://curl.haxx.se/) - [curl license](https://github.com/aseprite/aseprite/tree/master/docs/licenses/curl-LICENSE.txt)
-* [gfli](https://github.com/aseprite/aseprite/blob/master/src/app/file/fli/README) - [GPL license](https://github.com/aseprite/aseprite/tree/master/docs/licenses/GPL.txt)
 * [giflib](http://sourceforge.net/projects/giflib/) - [giflib license](https://github.com/aseprite/aseprite/tree/master/docs/licenses/giflib-LICENSE.txt)
 * [libjpeg](http://www.ijg.org/) - [libjpeg license](https://github.com/aseprite/aseprite/tree/master/docs/licenses/libjpeg-LICENSE.txt)
 * [libpng](http://www.libpng.org/pub/png/) - [libpng license](https://github.com/aseprite/aseprite/tree/master/docs/licenses/libpng-LICENSE.txt)
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index e4f7bd7..dd1d794 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -91,6 +91,7 @@ add_subdirectory(base)
 include_directories(${BASE_INCLUDE_DIR})
 
 add_subdirectory(cfg)
+add_subdirectory(flic)
 add_subdirectory(css)
 add_subdirectory(doc)
 add_subdirectory(render)
diff --git a/src/README.md b/src/README.md
index 18b4a57..9c13f29 100644
--- a/src/README.md
+++ b/src/README.md
@@ -16,6 +16,7 @@ because they don't depend on any other component.
   * [allegro](allegro/): Modified version of [Allegro](http://alleg.sourceforge.net/) library, used for keyboard/mouse input, and drawing 2D graphics on screen.
   * [base](base/): Core/basic stuff, multithreading, utf8, sha1, file system, memory, etc.
   * [css](css/): Pseudo-style sheet library.
+  * [flic](flic/): Library to load/save FLI/FLC files
   * [gfx](gfx/): Abstract graphics structures like point, size, rectangle, region, color, etc.
   * [scripting](scripting/): JavaScript engine ([V8](https://code.google.com/p/v8/)).
   * [undo](undo/): Generic library to manage a history of undoable commands.
diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt
index 3d1ab30..51617f5 100644
--- a/src/app/CMakeLists.txt
+++ b/src/app/CMakeLists.txt
@@ -280,7 +280,6 @@ add_library(app-lib
   file/file.cpp
   file/file_format.cpp
   file/file_formats_manager.cpp
-  file/fli/fli.cpp
   file/palette_file.cpp
   file/split_filename.cpp
   ${file_formats}
@@ -411,6 +410,7 @@ target_link_libraries(app-lib
   doc-lib
   filters-lib
   fixmath-lib
+  flic-lib
   gfx-lib
   net-lib
   render-lib
diff --git a/src/app/file/fli/README b/src/app/file/fli/README
deleted file mode 100644
index 655cfd8..0000000
--- a/src/app/file/fli/README
+++ /dev/null
@@ -1,35 +0,0 @@
-GFLI
-----
-
-This is the second version of my FLI plugin for "The GIMP". It now adds
-saving, and the fli load/save functions are separated from the GIMP
-interface, to allow them to be reused for other projects.
-
-The saving supports currently only BRUN and LC chunks. LC2 chunks may
-be added in the future. You should make a backup as an animated GIF if
-possible, because saving is not tested very much.
-
-gfli.c: Gimp wrapper for fli.c
-fli.c: functions to load/save FLI movies
-
-Please write me about your experiences with this plug-in:
-<jchrr at hrz.uni-bielefeld.de>
-
-This is another idea I had recently:
-The FLI format allows to add chunks with new data to a frame, that are
-skipped by readers that don't understand them.
-They will require a special reader. This is easy to write, because all the
-fli handling is in "fli.c", and can be reused for other programs.
-- MIDI events: Background musik ! (I'd need to recycle some code from
-"playmidi" and "timidity")
-- Text events (subtitles)
-- CD-Audio synchronisation
-- Trigger playback of external PCM files (digitized speech)
-
-Known limitations:
-- The FLI format allows to change the palette from frame to frame. This does
-not work in Gimp, because Gimp allows only one palette per image. I'd have
-to translate the image to True-Color while loading.
-- Animations consume a lot of memory and swapping will slow the playback
-down.
-                        Jens Ch. Restemeier
diff --git a/src/app/file/fli/fli.cpp b/src/app/file/fli/fli.cpp
deleted file mode 100644
index aec4402..0000000
--- a/src/app/file/fli/fli.cpp
+++ /dev/null
@@ -1,725 +0,0 @@
-/*
- * Written 1998 Jens Ch. Restemeier <jchrr at hrz.uni-bielefeld.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-/* Modified by David Capello to use with Aseprite (2001-2012). */
-
-#include <cstdio>
-#include <cstdlib>
-#include <cstring>
-
-#include "fli.h"
-
-using namespace std;
-
-/*
- * To avoid endian-problems I wrote these functions:
- */
-static unsigned char fli_read_char(FILE *f)
-{
-        unsigned char b;
-        fread(&b,1,1,f);
-        return b;
-}
-
-static unsigned short fli_read_short(FILE *f)
-{
-        unsigned char b[2];
-        fread(&b,1,2,f);
-        return (unsigned short)(b[1]<<8) | b[0];
-}
-
-static unsigned long fli_read_long(FILE *f)
-{
-        unsigned char b[4];
-        fread(&b,1,4,f);
-        return (unsigned long)(b[3]<<24) | (b[2]<<16) | (b[1]<<8) | b[0];
-}
-
-static void fli_write_char(FILE *f, unsigned char b)
-{
-        fwrite(&b,1,1,f);
-}
-
-static void fli_write_short(FILE *f, unsigned short w)
-{
-        unsigned char b[2];
-        b[0]=w&255;
-        b[1]=(w>>8)&255;
-        fwrite(&b,1,2,f);
-}
-
-static void fli_write_long(FILE *f, unsigned long l)
-{
-        unsigned char b[4];
-        b[0]=l&255;
-        b[1]=(l>>8)&255;
-        b[2]=(l>>16)&255;
-        b[3]=(l>>24)&255;
-        fwrite(&b,1,4,f);
-}
-
-void fli_read_header(FILE *f, s_fli_header *fli_header)
-{
-        fli_header->filesize=fli_read_long(f);  /* 0 */
-        fli_header->magic=fli_read_short(f);    /* 4 */
-        fli_header->frames=fli_read_short(f);   /* 6 */
-        fli_header->width=fli_read_short(f);    /* 8 */
-        fli_header->height=fli_read_short(f);   /* 10 */
-        fli_header->depth=fli_read_short(f);    /* 12 */
-        fli_header->flags=fli_read_short(f);    /* 14 */
-        if (fli_header->magic == HEADER_FLI) {
-                /* FLI saves speed in 1/70s */
-                fli_header->speed=fli_read_short(f)*14;         /* 16 */
-        } else {
-                if (fli_header->magic == HEADER_FLC) {
-                        /* FLC saves speed in 1/1000s */
-                        fli_header->speed=fli_read_long(f);     /* 16 */
-                } else {
-                        fprintf(stderr, "error: magic number is wrong !\n");
-                        fli_header->magic = NO_HEADER;
-                }
-        }
-
-        if (fli_header->width == 0)
-          fli_header->width = 320;
-
-        if (fli_header->height == 0)
-          fli_header->height = 200;
-}
-
-void fli_write_header(FILE *f, s_fli_header *fli_header)
-{
-        fli_header->filesize=ftell(f);
-        fseek(f, 0, SEEK_SET);
-        fli_write_long(f, fli_header->filesize);        /* 0 */
-        fli_write_short(f, fli_header->magic);  /* 4 */
-        fli_write_short(f, fli_header->frames); /* 6 */
-        fli_write_short(f, fli_header->width);  /* 8 */
-        fli_write_short(f, fli_header->height); /* 10 */
-        fli_write_short(f, fli_header->depth);  /* 12 */
-        fli_write_short(f, fli_header->flags);  /* 14 */
-        if (fli_header->magic == HEADER_FLI) {
-                /* FLI saves speed in 1/70s */
-                fli_write_short(f, (unsigned short)fli_header->speed / 14);     /* 16 */
-        } else {
-                if (fli_header->magic == HEADER_FLC) {
-                        /* FLC saves speed in 1/1000s */
-                        fli_write_long(f, fli_header->speed);   /* 16 */
-                        fseek(f, 80, SEEK_SET);
-                        fli_write_long(f, fli_header->oframe1); /* 80 */
-                        fli_write_long(f, fli_header->oframe2); /* 84 */
-                } else {
-                        fprintf(stderr, "error: magic number in header is wrong !\n");
-                }
-        }
-}
-
-void fli_read_frame(FILE *f, s_fli_header *fli_header, unsigned char *old_framebuf, unsigned char *old_cmap, unsigned char *framebuf, unsigned char *cmap)
-{
-        s_fli_frame fli_frame;
-        unsigned long framepos;
-        int c;
-        framepos=ftell(f);
-
-        fli_frame.size=fli_read_long(f);
-        fli_frame.magic=fli_read_short(f);
-        fli_frame.chunks=fli_read_short(f);
-
-        if (fli_frame.magic == FRAME) {
-                fseek(f, framepos+16, SEEK_SET);
-                for (c=0;c<fli_frame.chunks;c++) {
-                        s_fli_chunk chunk;
-                        unsigned long chunkpos;
-                        chunkpos = ftell(f);
-                        chunk.size=fli_read_long(f);
-                        chunk.magic=fli_read_short(f);
-                        switch (chunk.magic) {
-                                case FLI_COLOR:   fli_read_color(f, fli_header, old_cmap, cmap); break;
-                                case FLI_COLOR_2: fli_read_color_2(f, fli_header, old_cmap, cmap); break;
-                                case FLI_BLACK:   fli_read_black(f, fli_header, framebuf); break;
-                                case FLI_BRUN:    fli_read_brun(f, fli_header, framebuf); break;
-                                case FLI_COPY:    fli_read_copy(f, fli_header, framebuf); break;
-                                case FLI_LC:      fli_read_lc(f, fli_header, old_framebuf, framebuf); break;
-                                case FLI_LC_2:    fli_read_lc_2(f, fli_header, old_framebuf, framebuf); break;
-                                case FLI_MINI:    /* unused, skip */ break;
-                                default: /* unknown, skip */ break;
-                        }
-                        if (chunk.size & 1) chunk.size++;
-                        fseek(f,chunkpos+chunk.size,SEEK_SET);
-                }
-        } /* else: unknown, skip */
-        fseek(f, framepos+fli_frame.size, SEEK_SET);
-}
-
-void fli_write_frame(FILE *f, s_fli_header *fli_header, unsigned char *old_framebuf, unsigned char *old_cmap, unsigned char *framebuf, unsigned char *cmap, unsigned short codec_mask)
-{
-        s_fli_frame fli_frame;
-        unsigned long framepos, frameend;
-        framepos=ftell(f);
-        fseek(f, framepos+16, SEEK_SET);
-
-        switch (fli_header->frames) {
-                case 0: fli_header->oframe1=framepos; break;
-                case 1: fli_header->oframe2=framepos; break;
-        }
-
-        fli_frame.size=0;
-        fli_frame.magic=FRAME;
-        fli_frame.chunks=0;
-
-        /*
-         * create color chunk
-         */
-        if (fli_header->magic == HEADER_FLI) {
-                if (fli_write_color(f, fli_header, old_cmap, cmap)) fli_frame.chunks++;
-        } else {
-                if (fli_header->magic == HEADER_FLC) {
-                        if (fli_write_color_2(f, fli_header, old_cmap, cmap)) fli_frame.chunks++;
-                } else {
-                        fprintf(stderr, "error: magic number in header is wrong !\n");
-                }
-        }
-
-#if 0
-        if (codec_mask & W_COLOR) {
-                if (fli_write_color(f, fli_header, old_cmap, cmap)) fli_frame.chunks++;
-        }
-        if (codec_mask & W_COLOR_2) {
-                if (fli_write_color_2(f, fli_header, old_cmap, cmap)) fli_frame.chunks++;
-        }
-#endif
-        /* create bitmap chunk */
-        if (old_framebuf==NULL) {
-                fli_write_brun(f, fli_header, framebuf);
-        } else {
-                fli_write_lc(f, fli_header, old_framebuf, framebuf);
-        }
-        fli_frame.chunks++;
-
-        frameend=ftell(f);
-        fli_frame.size=frameend-framepos;
-        fseek(f, framepos, SEEK_SET);
-        fli_write_long(f, fli_frame.size);
-        fli_write_short(f, fli_frame.magic);
-        fli_write_short(f, fli_frame.chunks);
-        fseek(f, frameend, SEEK_SET);
-        fli_header->frames++;
-}
-
-/*
- * palette chunks from the classical Autodesk Animator.
- */
-void fli_read_color(FILE *f, s_fli_header *fli_header, unsigned char *old_cmap, unsigned char *cmap)
-{
-        unsigned short num_packets, cnt_packets, col_pos;
-        col_pos=0;
-        num_packets=fli_read_short(f);
-        for (cnt_packets=num_packets; cnt_packets>0; cnt_packets--) {
-                unsigned short skip_col, num_col, col_cnt;
-                skip_col=fli_read_char(f);
-                num_col=fli_read_char(f);
-                if (num_col==0) {
-                        for (col_pos=0; col_pos<768; col_pos++) {
-                                cmap[col_pos]=fli_read_char(f)<<2;
-                        }
-                        return;
-                }
-                for (col_cnt=skip_col; (col_cnt>0) && (col_pos<768); col_cnt--) {
-                        cmap[col_pos]=old_cmap[col_pos];col_pos++;
-                        cmap[col_pos]=old_cmap[col_pos];col_pos++;
-                        cmap[col_pos]=old_cmap[col_pos];col_pos++;
-                }
-                for (col_cnt=num_col; (col_cnt>0) && (col_pos<768); col_cnt--) {
-                        cmap[col_pos++]=fli_read_char(f)<<2;
-                        cmap[col_pos++]=fli_read_char(f)<<2;
-                        cmap[col_pos++]=fli_read_char(f)<<2;
-                }
-        }
-}
-
-int fli_write_color(FILE *f, s_fli_header *fli_header, unsigned char *old_cmap, unsigned char *cmap)
-{
-        unsigned long chunkpos;
-        unsigned short num_packets;
-        s_fli_chunk chunk;
-        chunkpos=ftell(f);
-        fseek(f, chunkpos+8, SEEK_SET);
-        num_packets=0;
-        if (old_cmap==NULL) {
-                unsigned short col_pos;
-                num_packets=1;
-                fli_write_char(f, 0); /* skip no color */
-                fli_write_char(f, 0); /* 256 color */
-                for (col_pos=0; col_pos<768; col_pos++) {
-                        fli_write_char(f, cmap[col_pos]>>2);
-                }
-        } else {
-                unsigned short cnt_skip, cnt_col, col_pos, col_start;
-                col_pos=0;
-                do {
-                        cnt_skip=0;
-                        while ((col_pos<256) && (old_cmap[col_pos*3+0]==cmap[col_pos*3+0]) && (old_cmap[col_pos*3+1]==cmap[col_pos*3+1]) && (old_cmap[col_pos*3+2]==cmap[col_pos*3+2])) {
-                                cnt_skip++; col_pos++;
-                        }
-                        col_start=col_pos*3;
-                        cnt_col=0;
-                        while ((col_pos<256) && !((old_cmap[col_pos*3+0]==cmap[col_pos*3+0]) && (old_cmap[col_pos*3+1]==cmap[col_pos*3+1]) && (old_cmap[col_pos*3+2]==cmap[col_pos*3+2]))) {
-                                cnt_col++; col_pos++;
-                        }
-                        if (cnt_col>0) {
-                                num_packets++;
-                                fli_write_char(f, cnt_skip & 255);
-                                fli_write_char(f, cnt_col & 255);
-                                while (cnt_col>0) {
-                                        fli_write_char(f, cmap[col_start++]>>2);
-                                        fli_write_char(f, cmap[col_start++]>>2);
-                                        fli_write_char(f, cmap[col_start++]>>2);
-                                        cnt_col--;
-                                }
-                        }
-                } while (col_pos<256);
-        }
-
-        if (num_packets>0) {
-                chunk.size=ftell(f)-chunkpos;
-                chunk.magic=FLI_COLOR;
-
-                fseek(f, chunkpos, SEEK_SET);
-                fli_write_long(f, chunk.size);
-                fli_write_short(f, chunk.magic);
-                fli_write_short(f, num_packets);
-
-                if (chunk.size & 1) chunk.size++;
-                fseek(f,chunkpos+chunk.size,SEEK_SET);
-                return 1;
-        }
-        fseek(f,chunkpos, SEEK_SET);
-        return 0;
-}
-
-/*
- * palette chunks from Autodesk Animator pro
- */
-void fli_read_color_2(FILE *f, s_fli_header *fli_header, unsigned char *old_cmap, unsigned char *cmap)
-{
-        unsigned short num_packets, cnt_packets, col_pos;
-        num_packets=fli_read_short(f);
-        col_pos=0;
-        for (cnt_packets=num_packets; cnt_packets>0; cnt_packets--) {
-                unsigned short skip_col, num_col, col_cnt;
-                skip_col=fli_read_char(f);
-                num_col=fli_read_char(f);
-                if (num_col == 0) {
-                        for (col_pos=0; col_pos<768; col_pos++) {
-                                cmap[col_pos]=fli_read_char(f);
-                        }
-                        return;
-                }
-                for (col_cnt=skip_col; (col_cnt>0) && (col_pos<768); col_cnt--) {
-                        cmap[col_pos]=old_cmap[col_pos];col_pos++;
-                        cmap[col_pos]=old_cmap[col_pos];col_pos++;
-                        cmap[col_pos]=old_cmap[col_pos];col_pos++;
-                }
-                for (col_cnt=num_col; (col_cnt>0) && (col_pos<768); col_cnt--) {
-                        cmap[col_pos++]=fli_read_char(f);
-                        cmap[col_pos++]=fli_read_char(f);
-                        cmap[col_pos++]=fli_read_char(f);
-                }
-        }
-}
-
-int fli_write_color_2(FILE *f, s_fli_header *fli_header, unsigned char *old_cmap, unsigned char *cmap)
-{
-        unsigned long chunkpos;
-        unsigned short num_packets;
-        s_fli_chunk chunk;
-        chunkpos=ftell(f);
-        fseek(f, chunkpos+8, SEEK_SET);
-        num_packets=0;
-        if (old_cmap==NULL) {
-                unsigned short col_pos;
-                num_packets=1;
-                fli_write_char(f, 0); /* skip no color */
-                fli_write_char(f, 0); /* 256 color */
-                for (col_pos=0; col_pos<768; col_pos++) {
-                        fli_write_char(f, cmap[col_pos]);
-                }
-        } else {
-                unsigned short cnt_skip, cnt_col, col_pos, col_start;
-                col_pos=0;
-                do {
-                        cnt_skip=0;
-                        while ((col_pos<256) && (old_cmap[col_pos*3+0]==cmap[col_pos*3+0]) && (old_cmap[col_pos*3+1]==cmap[col_pos*3+1]) && (old_cmap[col_pos*3+2]==cmap[col_pos*3+2])) {
-                                cnt_skip++; col_pos++;
-                        }
-                        col_start=col_pos*3;
-                        cnt_col=0;
-                        while ((col_pos<256) && !((old_cmap[col_pos*3+0]==cmap[col_pos*3+0]) && (old_cmap[col_pos*3+1]==cmap[col_pos*3+1]) && (old_cmap[col_pos*3+2]==cmap[col_pos*3+2]))) {
-                                cnt_col++; col_pos++;
-                        }
-                        if (cnt_col>0) {
-                                num_packets++;
-                                fli_write_char(f, (unsigned char)cnt_skip);
-                                fli_write_char(f, (unsigned char)cnt_col);
-                                while (cnt_col>0) {
-                                        fli_write_char(f, cmap[col_start++]);
-                                        fli_write_char(f, cmap[col_start++]);
-                                        fli_write_char(f, cmap[col_start++]);
-                                        cnt_col--;
-                                }
-                        }
-                } while (col_pos<256);
-        }
-
-        if (num_packets>0) {
-                chunk.size=ftell(f)-chunkpos;
-                chunk.magic=FLI_COLOR_2;
-
-                fseek(f, chunkpos, SEEK_SET);
-                fli_write_long(f, chunk.size);
-                fli_write_short(f, chunk.magic);
-                fli_write_short(f, num_packets);
-
-                if (chunk.size & 1) chunk.size++;
-                fseek(f,chunkpos+chunk.size,SEEK_SET);
-                return 1;
-        }
-        fseek(f,chunkpos, SEEK_SET);
-        return 0;
-}
-
-/*
- * completely black frame
- */
-void fli_read_black(FILE *f, s_fli_header *fli_header, unsigned char *framebuf)
-{
-        memset(framebuf, 0, fli_header->width * fli_header->height);
-}
-
-void fli_write_black(FILE *f, s_fli_header *fli_header, unsigned char *framebuf)
-{
-        s_fli_chunk chunk;
-
-        chunk.size=6;
-        chunk.magic=FLI_BLACK;
-
-        fli_write_long(f, chunk.size);
-        fli_write_short(f, chunk.magic);
-}
-
-/*
- * Uncompressed frame
- */
-void fli_read_copy(FILE *f, s_fli_header *fli_header, unsigned char *framebuf)
-{
-        fread(framebuf, fli_header->width, fli_header->height, f);
-}
-
-void fli_write_copy(FILE *f, s_fli_header *fli_header, unsigned char *framebuf)
-{
-
-        unsigned long chunkpos;
-        s_fli_chunk chunk;
-        chunkpos=ftell(f);
-        fseek(f, chunkpos+6, SEEK_SET);
-        fwrite(framebuf, fli_header->width, fli_header->height, f);
-        chunk.size=ftell(f)-chunkpos;
-        chunk.magic=FLI_COPY;
-
-        fseek(f, chunkpos, SEEK_SET);
-        fli_write_long(f, chunk.size);
-        fli_write_short(f, chunk.magic);
-
-        if (chunk.size & 1) chunk.size++;
-        fseek(f,chunkpos+chunk.size,SEEK_SET);
-}
-
-/*
- * This is a RLE algorithm, used for the first image of an animation
- */
-void fli_read_brun(FILE *f, s_fli_header *fli_header, unsigned char *framebuf)
-{
-        unsigned short yc;
-        unsigned char *pos;
-        for (yc=0; yc < fli_header->height; yc++) {
-                unsigned short xc, pc, pcnt;
-                pc=fli_read_char(f);
-                xc=0;
-                pos=framebuf+(fli_header->width * yc);
-                for (pcnt=pc; pcnt>0; pcnt--) {
-                        unsigned short ps;
-                        ps=fli_read_char(f);
-                        if (ps & 0x80) {
-                                unsigned short len;
-                                for (len=-(signed char)ps; len>0; len--) {
-                                        pos[xc++]=fli_read_char(f);
-                                }
-                        } else {
-                                unsigned char val;
-                                val=fli_read_char(f);
-                                memset(&(pos[xc]), val, ps);
-                                xc+=ps;
-                        }
-                }
-        }
-}
-
-void fli_write_brun(FILE *f, s_fli_header *fli_header, unsigned char *framebuf)
-{
-        unsigned long chunkpos;
-        s_fli_chunk chunk;
-        unsigned short yc;
-        unsigned char *linebuf;
-
-        chunkpos=ftell(f);
-        fseek(f, chunkpos+6, SEEK_SET);
-
-        for (yc=0; yc < fli_header->height; yc++) {
-                unsigned short xc, t1, pc, tc;
-                unsigned long linepos, lineend, bc;
-                linepos=ftell(f); bc=0;
-                fseek(f, 1, SEEK_CUR);
-                linebuf=framebuf + (yc*fli_header->width);
-                xc=0; tc=0; t1=0;
-                while (xc < fli_header->width) {
-                        pc=1;
-                        while ((pc<120) && ((xc+pc)<fli_header->width) && (linebuf[xc+pc] == linebuf[xc])) {
-                                pc++;
-                        }
-                        if (pc>2) {
-                                if (tc>0) {
-                                        bc++;
-                                        fli_write_char(f, (tc-1)^0xFF);
-                                        fwrite(linebuf+t1, 1, tc, f);
-                                        tc=0;
-                                }
-                                bc++;
-                                fli_write_char(f, (unsigned char)pc);
-                                fli_write_char(f, linebuf[xc]);
-                                t1=xc+pc;
-                        } else {
-                                tc+=pc;
-                                if (tc>120) {
-                                        bc++;
-                                        fli_write_char(f, (tc-1)^0xFF);
-                                        fwrite(linebuf+t1, 1, tc, f);
-                                        tc=0;
-                                        t1=xc+pc;
-                                }
-                        }
-                        xc+=pc;
-                }
-                if (tc>0) {
-                        bc++;
-                        fli_write_char(f, (tc-1)^0xFF);
-                        fwrite(linebuf+t1, 1, tc, f);
-                        tc=0;
-                }
-                lineend=ftell(f);
-                fseek(f, linepos, SEEK_SET);
-                fli_write_char(f, (unsigned char)bc);
-                fseek(f, lineend, SEEK_SET);
-        }
-
-        chunk.size=ftell(f)-chunkpos;
-        chunk.magic=FLI_BRUN;
-
-        fseek(f, chunkpos, SEEK_SET);
-        fli_write_long(f, chunk.size);
-        fli_write_short(f, chunk.magic);
-
-        if (chunk.size & 1) chunk.size++;
-        fseek(f,chunkpos+chunk.size,SEEK_SET);
-}
-
-/*
- * This is the delta-compression method from the classic Autodesk Animator.
- * It's basically the RLE method from above, but it allows to skip unchanged
- * lines at the beginning and end of an image, and unchanged pixels in a line
- * This chunk is used in FLI files.
- */
-void fli_read_lc(FILE *f, s_fli_header *fli_header, unsigned char *old_framebuf, unsigned char *framebuf)
-{
-        unsigned short yc, firstline, numline;
-        unsigned char *pos;
-        memcpy(framebuf, old_framebuf, fli_header->width * fli_header->height);
-        firstline = fli_read_short(f);
-        numline = fli_read_short(f);
-        for (yc=0; yc < numline; yc++) {
-                unsigned short xc, pc, pcnt;
-                pc=fli_read_char(f);
-                xc=0;
-                pos=framebuf+(fli_header->width * (firstline+yc));
-                for (pcnt=pc; pcnt>0; pcnt--) {
-                        unsigned short ps,skip;
-                        skip=fli_read_char(f);
-                        ps=fli_read_char(f);
-                        xc+=skip;
-                        if (ps & 0x80) {
-                                unsigned char val;
-                                ps=-(signed char)ps;
-                                val=fli_read_char(f);
-                                memset(&(pos[xc]), val, ps);
-                                xc+=ps;
-                        } else {
-                                fread(&(pos[xc]), ps, 1, f);
-                                xc+=ps;
-                        }
-                }
-        }
-}
-
-void fli_write_lc(FILE *f, s_fli_header *fli_header, unsigned char *old_framebuf, unsigned char *framebuf)
-{
-        unsigned long chunkpos;
-        s_fli_chunk chunk;
-        unsigned short yc, firstline, numline, lastline;
-        unsigned char *linebuf, *old_linebuf;
-
-        chunkpos=ftell(f);
-        fseek(f, chunkpos+6, SEEK_SET);
-
-        /* first check, how many lines are unchanged at the beginning */
-        firstline=0;
-        while ((memcmp(old_framebuf+(firstline*fli_header->width), framebuf+(firstline*fli_header->width), fli_header->width)==0) && (firstline<fli_header->height)) firstline++;
-
-        /* then check from the end, how many lines are unchanged */
-        if (firstline<fli_header->height) {
-                lastline=fli_header->height-1;
-                while ((memcmp(old_framebuf+(lastline*fli_header->width), framebuf+(lastline*fli_header->width), fli_header->width)==0) && (lastline>firstline)) lastline--;
-                numline=(lastline-firstline)+1;
-        } else {
-                numline=0;
-        }
-        if (numline==0) firstline=0;
-
-        fli_write_short(f, firstline);
-        fli_write_short(f, numline);
-
-        for (yc=0; yc < numline; yc++) {
-                unsigned short xc, sc, cc, tc;
-                unsigned long linepos, lineend, bc;
-                linepos=ftell(f); bc=0;
-                fseek(f, 1, SEEK_CUR);
-
-                linebuf=framebuf + ((firstline+yc)*fli_header->width);
-                old_linebuf=old_framebuf + ((firstline+yc)*fli_header->width);
-                xc=0;
-                while (xc < fli_header->width) {
-                        sc=0;
-                        while ((linebuf[xc]==old_linebuf[xc]) && (xc<fli_header->width) && (sc<255)) {
-                                xc++; sc++;
-                        }
-                        fli_write_char(f, (unsigned char)sc);
-                        cc=1;
-                        while ((linebuf[xc]==linebuf[xc+cc]) && ((xc+cc)<fli_header->width) && (cc<120)) {
-                                cc++;
-                        }
-                        if (cc>2) {
-                                bc++;
-                                fli_write_char(f, (cc-1)^0xFF);
-                                fli_write_char(f, linebuf[xc]);
-                                xc+=cc;
-                        } else {
-                                tc=0;
-                                do {
-                                        sc=0;
-                                        while ((linebuf[tc+xc+sc]==old_linebuf[tc+xc+sc]) && ((tc+xc+sc)<fli_header->width) && (sc<5)) {
-                                                sc++;
-                                        }
-                                        cc=1;
-                                        while ((linebuf[tc+xc]==linebuf[tc+xc+cc]) && ((tc+xc+cc)<fli_header->width) && (cc<10)) {
-                                                cc++;
-                                        }
-                                        tc++;
-                                } while ((tc<120) && (cc<9) && (sc<4) && ((xc+tc)<fli_header->width));
-                                bc++;
-                                fli_write_char(f, (unsigned char)tc);
-                                fwrite(linebuf+xc, tc, 1, f);
-                                xc+=tc;
-                        }
-                }
-                lineend=ftell(f);
-                fseek(f, linepos, SEEK_SET);
-                fli_write_char(f, (unsigned char)bc);
-                fseek(f, lineend, SEEK_SET);
-        }
-
-        chunk.size=ftell(f)-chunkpos;
-        chunk.magic=FLI_LC;
-
-        fseek(f, chunkpos, SEEK_SET);
-        fli_write_long(f, chunk.size);
-        fli_write_short(f, chunk.magic);
-
-        if (chunk.size & 1) chunk.size++;
-        fseek(f,chunkpos+chunk.size,SEEK_SET);
-}
-
-
-/*
- * This is an enhanced version of the old delta-compression used by
- * the autodesk animator pro. It's word-oriented, and allows to skip
- * larger parts of the image. This chunk is used in FLC files.
- */
-void fli_read_lc_2(FILE *f, s_fli_header *fli_header, unsigned char *old_framebuf, unsigned char *framebuf)
-{
-        unsigned short yc, lc, numline;
-        unsigned char *pos;
-        memcpy(framebuf, old_framebuf, fli_header->width * fli_header->height);
-        yc=0;
-        numline = fli_read_short(f);
-        for (lc=0; lc < numline; lc++) {
-                unsigned short xc, pc, pcnt, lpf, lpn;
-                pc=fli_read_short(f);
-                lpf=0; lpn=0;
-                while (pc & 0x8000) {
-                        if (pc & 0x4000) {
-                                yc+=-(signed short)pc;
-                        } else {
-                                lpf=1;lpn=pc&0xFF;
-                        }
-                        pc=fli_read_short(f);
-                }
-                xc=0;
-                pos=framebuf+(fli_header->width * yc);
-                for (pcnt=pc; pcnt>0; pcnt--) {
-                        unsigned short ps,skip;
-                        skip=fli_read_char(f);
-                        ps=fli_read_char(f);
-                        xc+=skip;
-                        if (ps & 0x80) {
-                                unsigned char v1,v2;
-                                ps=-(signed char)ps;
-                                v1=fli_read_char(f);
-                                v2=fli_read_char(f);
-                                while (ps>0) {
-                                        pos[xc++]=v1;
-                                        pos[xc++]=v2;
-                                        ps--;
-                                }
-                        } else {
-                                fread(&(pos[xc]), ps, 2, f);
-                                xc+=ps << 1;
-                        }
-                }
-                if (lpf) pos[xc]=(unsigned char)lpn;
-                yc++;
-        }
-}
diff --git a/src/app/file/fli/fli.h b/src/app/file/fli/fli.h
deleted file mode 100644
index b3ed3e4..0000000
--- a/src/app/file/fli/fli.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Written 1998 Jens Ch. Restemeier <jchrr at hrz.uni-bielefeld.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-#ifndef APP_FILE_FLI_FLI_H_INCLUDED
-#define APP_FILE_FLI_FLI_H_INCLUDED
-#pragma once
-
-/** structures */
-
-typedef struct _fli_header {
-        unsigned long filesize;
-        unsigned short magic;
-        unsigned short frames;
-        unsigned short width;
-        unsigned short height;
-        unsigned short depth;
-        unsigned short flags;
-        unsigned long speed;
-        unsigned long created;
-        unsigned long creator;
-        unsigned long updated;
-        unsigned short aspect_x, aspect_y;
-        unsigned long oframe1, oframe2;
-} s_fli_header;
-
-typedef struct _fli_frame {
-        unsigned long size;
-        unsigned short magic;
-        unsigned short chunks;
-} s_fli_frame;
-
-typedef struct _fli_chunk {
-        unsigned long size;
-        unsigned short magic;
-        unsigned char *data;
-} s_fli_chunk;
-
-/** chunk magics */
-#define NO_HEADER       0
-#define HEADER_FLI      0xAF11
-#define HEADER_FLC      0xAF12
-#define FRAME           0xF1FA
-
-/** codec magics */
-#define FLI_COLOR       11
-#define FLI_BLACK       13
-#define FLI_BRUN        15
-#define FLI_COPY        16
-#define FLI_LC          12
-#define FLI_LC_2        7
-#define FLI_COLOR_2     4
-#define FLI_MINI        18
-
-/** codec masks */
-#define W_COLOR         0x0001
-#define W_BLACK         0x0002
-#define W_BRUN          0x0004
-#define W_COPY          0x0008
-#define W_LC            0x0010
-#define W_LC_2          0x0020
-#define W_COLOR_2       0x0040
-#define W_MINI          0x0080
-#define W_ALL           0xFFFF
-
-/** functions */
-void fli_read_header(FILE *f, s_fli_header *fli_header);
-void fli_read_frame(FILE *f, s_fli_header *fli_header, unsigned char *old_framebuf, unsigned char *old_cmap, unsigned char *framebuf, unsigned char *cmap);
-
-void fli_read_color(FILE *f, s_fli_header *fli_header, unsigned char *old_cmap, unsigned char *cmap);
-void fli_read_color_2(FILE *f, s_fli_header *fli_header, unsigned char *old_cmap, unsigned char *cmap);
-void fli_read_black(FILE *f, s_fli_header *fli_header, unsigned char *framebuf);
-void fli_read_brun(FILE *f, s_fli_header *fli_header, unsigned char *framebuf);
-void fli_read_copy(FILE *f, s_fli_header *fli_header, unsigned char *framebuf);
-void fli_read_lc(FILE *f, s_fli_header *fli_header, unsigned char *old_framebuf, unsigned char *framebuf);
-void fli_read_lc_2(FILE *f, s_fli_header *fli_header, unsigned char *old_framebuf, unsigned char *framebuf);
-
-void fli_write_header(FILE *f, s_fli_header *fli_header);
-void fli_write_frame(FILE *f, s_fli_header *fli_header, unsigned char *old_framebuf, unsigned char *old_cmap, unsigned char *framebuf, unsigned char *cmap, unsigned short codec_mask);
-
-int fli_write_color(FILE *f, s_fli_header *fli_header, unsigned char *old_cmap, unsigned char *cmap);
-int fli_write_color_2(FILE *f, s_fli_header *fli_header, unsigned char *old_cmap, unsigned char *cmap);
-void fli_write_black(FILE *f, s_fli_header *fli_header, unsigned char *framebuf);
-void fli_write_brun(FILE *f, s_fli_header *fli_header, unsigned char *framebuf);
-void fli_write_copy(FILE *f, s_fli_header *fli_header, unsigned char *framebuf);
-void fli_write_lc(FILE *f, s_fli_header *fli_header, unsigned char *old_framebuf, unsigned char *framebuf);
-void fli_write_lc_2(FILE *f, s_fli_header *fli_header, unsigned char *old_framebuf, unsigned char *framebuf);
-
-#endif
diff --git a/src/app/file/fli_format.cpp b/src/app/file/fli_format.cpp
index 618af25..919eb77 100644
--- a/src/app/file/fli_format.cpp
+++ b/src/app/file/fli_format.cpp
@@ -12,11 +12,11 @@
 #include "app/document.h"
 #include "app/file/file.h"
 #include "app/file/file_format.h"
-#include "app/file/fli/fli.h"
 #include "app/file/format_options.h"
 #include "app/modules/palettes.h"
 #include "base/file_handle.h"
 #include "doc/doc.h"
+#include "flic/flic.h"
 #include "render/render.h"
 
 #include <cstdio>
@@ -25,8 +25,6 @@ namespace app {
 
 using namespace base;
 
-static int get_time_precision(Sprite *sprite);
-
 class FliFormat : public FileFormat {
   const char* onGetName() const { return "flc"; }
   const char* onGetExtensions() const { return "flc,fli"; }
@@ -52,223 +50,195 @@ FileFormat* CreateFliFormat()
 
 bool FliFormat::onLoad(FileOp* fop)
 {
-#define SETPAL()                                                \
-  do {                                                          \
-      for (c=0; c<256; c++) {                                   \
-        pal->setEntry(c, rgba(cmap[c*3],                       \
-                               cmap[c*3+1],                     \
-                               cmap[c*3+2], 255));              \
-      }                                                         \
-      pal->setFrame(frpos_out);                                 \
-      sprite->setPalette(pal, true);                            \
-    } while (0)
-
-  unsigned char cmap[768];
-  unsigned char omap[768];
-  s_fli_header fli_header;
-  int c, w, h;
-  frame_t frpos_in;
-  frame_t frpos_out;
-#ifdef USE_LINK
-  int index = 0;                // TODO this is used to create linked cels
-#endif
-
   // Open the file to read in binary mode
   FileHandle handle(open_file_with_exception(fop->filename, "rb"));
   FILE* f = handle.get();
+  flic::StdioFileInterface finterface(f);
+  flic::Decoder decoder(&finterface);
 
-  fli_read_header(f, &fli_header);
-  fseek(f, 128, SEEK_SET);
-
-  if (fli_header.magic == NO_HEADER) {
+  flic::Header header;
+  if (!decoder.readHeader(header)) {
     fop_error(fop, "The file doesn't have a FLIC header\n");
     return false;
   }
 
   // Size by frame
-  w = fli_header.width;
-  h = fli_header.height;
+  int w = header.width;
+  int h = header.height;
 
-  // Create the bitmaps
-  base::UniquePtr<Image> bmp(Image::create(IMAGE_INDEXED, w, h));
-  base::UniquePtr<Image> old(Image::create(IMAGE_INDEXED, w, h));
-  base::UniquePtr<Palette> pal(new Palette(frame_t(0), 256));
+  // Create a temporal bitmap
+  ImageRef bmp(Image::create(IMAGE_INDEXED, w, h));
+  Palette pal(0, 1);
+  Cel* prevCel = nullptr;
 
-  // Create the image
+  // Create the sprite
   Sprite* sprite = new Sprite(IMAGE_INDEXED, w, h, 256);
   LayerImage* layer = new LayerImage(sprite);
   sprite->folder()->addLayer(layer);
   layer->configureAsBackground();
 
   // Set frames and speed
-  sprite->setTotalFrames(frame_t(fli_header.frames));
-  sprite->setDurationForAllFrames(fli_header.speed);
-
-  // Write frame by frame
-  for (frpos_in = frpos_out = frame_t(0);
-       frpos_in < sprite->totalFrames();
-       ++frpos_in) {
+  sprite->setTotalFrames(frame_t(header.frames));
+  sprite->setDurationForAllFrames(header.speed);
+
+  flic::Frame fliFrame;
+  flic::Colormap oldFliColormap;
+  fliFrame.pixels = bmp->getPixelAddress(0, 0);
+  fliFrame.rowstride = IndexedTraits::getRowStrideBytes(bmp->width());
+
+  frame_t frame_out = 0;
+  for (frame_t frame_in=0;
+       frame_in<sprite->totalFrames();
+       ++frame_in) {
     // Read the frame
-    fli_read_frame(f, &fli_header,
-                   (unsigned char *)old->getPixelAddress(0, 0), omap,
-                   (unsigned char *)bmp->getPixelAddress(0, 0), cmap);
-
-    // First frame, or the frames changes, or the palette changes
-    if ((frpos_in == 0) ||
-        (count_diff_between_images(old, bmp))
-#ifndef USE_LINK /* TODO this should be configurable through a check-box */
-        || (memcmp(omap, cmap, 768) != 0)
-#endif
-        ) {
-      // The image changes?
-      if (frpos_in != 0)
-        ++frpos_out;
+    if (!decoder.readFrame(fliFrame)) {
+      fop_error(fop, "Error reading frame %d\n", frame_in);
+      continue;
+    }
+
+    // Palette change
+    bool palChange = false;
+    if (frame_out == 0 || oldFliColormap != fliFrame.colormap) {
+      oldFliColormap = fliFrame.colormap;
+
+      pal.resize(fliFrame.colormap.size());
+      for (int c=0; c<int(fliFrame.colormap.size()); c++) {
+        pal.setEntry(c, rgba(fliFrame.colormap[c].r,
+                             fliFrame.colormap[c].g,
+                             fliFrame.colormap[c].b, 255));
+      }
+      pal.setFrame(frame_out);
+      sprite->setPalette(&pal, true);
+
+      palChange = true;
+    }
 
+    // First frame, or the frame changes
+    if (!prevCel ||
+        (count_diff_between_images(prevCel->image(), bmp.get()))) {
       // Add the new frame
-      ImageRef image(Image::createCopy(bmp));
-      Cel* cel = new Cel(frpos_out, image);
+      ImageRef image(Image::createCopy(bmp.get()));
+      Cel* cel = new Cel(frame_out, image);
       layer->addCel(cel);
 
-      // First frame or the palette changes
-      if ((frpos_in == 0) || (memcmp(omap, cmap, 768) != 0))
-        SETPAL();
+      prevCel = cel;
+      ++frame_out;
     }
-#ifdef USE_LINK
-    // The palette changes
-    else if (memcmp(omap, cmap, 768) != 0) {
-      ++frpos_out;
-      SETPAL();
-
-      // Add link
-      Cel* cel = new Cel(frpos_out, index);
-      layer_add_cel(layer, cel);
+    else if (palChange) {
+      Cel* cel = Cel::createLink(prevCel);
+      cel->setFrame(frame_out);
+      layer->addCel(cel);
+
+      ++frame_out;
     }
-#endif
     // The palette and the image don't change: add duration to the last added frame
     else {
-      sprite->setFrameDuration(frpos_out,
-                               sprite->frameDuration(frpos_out)+fli_header.speed);
+      sprite->setFrameDuration(
+        frame_out-1, sprite->frameDuration(frame_out-1) + header.speed);
     }
 
-    // Update the old image and color-map to the new ones to compare later
-    copy_image(old, bmp);
-    memcpy(omap, cmap, 768);
+    if (header.frames > 0)
+      fop_progress(fop, (float)(frame_in+1) / (float)(header.frames));
 
-    // Update progress
-    fop_progress(fop, (float)(frpos_in+1) / (float)(sprite->totalFrames()));
     if (fop_is_stop(fop))
       break;
 
-    // Just one frame?
     if (fop->oneframe)
       break;
   }
 
-  // Update number of frames
-  sprite->setTotalFrames(frpos_out+1);
+  if (frame_out > 0)
+    sprite->setTotalFrames(frame_out);
 
   fop->createDocument(sprite);
   return true;
 }
 
 #ifdef ENABLE_SAVE
+
+static int get_time_precision(Sprite *sprite)
+{
+  // Check if all frames have the same duration
+  bool constantFrameRate = true;
+  for (frame_t c(1); c < sprite->totalFrames(); ++c) {
+    if (sprite->frameDuration(c-1) != sprite->frameDuration(c)) {
+      constantFrameRate = false;
+      break;
+    }
+  }
+  if (constantFrameRate)
+    return sprite->frameDuration(0);
+
+  int precision = 1000;
+  for (frame_t c(0); c < sprite->totalFrames() && precision > 1; ++c) {
+    int len = sprite->frameDuration(c);
+    while (len / precision == 0)
+      precision /= 10;
+  }
+  return precision;
+}
+
 bool FliFormat::onSave(FileOp* fop)
 {
   Sprite* sprite = fop->document->sprite();
-  unsigned char cmap[768];
-  unsigned char omap[768];
-  s_fli_header fli_header;
-  int c, times;
-  Palette *pal;
-
-  /* prepare fli header */
-  fli_header.filesize = 0;
-  fli_header.frames = 0;
-  fli_header.width = sprite->width();
-  fli_header.height = sprite->height();
-
-  if ((fli_header.width == 320) && (fli_header.height == 200))
-    fli_header.magic = HEADER_FLI;
-  else
-    fli_header.magic = HEADER_FLC;
-
-  fli_header.depth = 8;
-  fli_header.flags = 3;
-  fli_header.speed = get_time_precision(sprite);
-  fli_header.created = 0;
-  fli_header.updated = 0;
-  fli_header.aspect_x = 1;
-  fli_header.aspect_y = 1;
-  fli_header.oframe1 = fli_header.oframe2 = 0;
-
-  /* open the file to write in binary mode */
+
+  // Open the file to write in binary mode
   FileHandle handle(open_file_with_exception(fop->filename, "wb"));
   FILE* f = handle.get();
+  flic::StdioFileInterface finterface(f);
+  flic::Encoder encoder(&finterface);
 
-  fseek(f, 128, SEEK_SET);
+  flic::Header header;
+  header.frames = 0;
+  header.width = sprite->width();
+  header.height = sprite->height();
+  header.speed = get_time_precision(sprite);
+  encoder.writeHeader(header);
 
   // Create the bitmaps
-  base::UniquePtr<Image> bmp(Image::create(IMAGE_INDEXED, sprite->width(), sprite->height()));
-  base::UniquePtr<Image> old(Image::create(IMAGE_INDEXED, sprite->width(), sprite->height()));
+  ImageRef bmp(Image::create(IMAGE_INDEXED, sprite->width(), sprite->height()));
   render::Render render;
 
   // Write frame by frame
-  for (frame_t frpos(0);
-       frpos < sprite->totalFrames();
-       ++frpos) {
-    // Get color map
-    pal = sprite->palette(frpos);
-    for (c=0; c<256; c++) {
-      cmap[3*c  ] = rgba_getr(pal->getEntry(c));
-      cmap[3*c+1] = rgba_getg(pal->getEntry(c));
-      cmap[3*c+2] = rgba_getb(pal->getEntry(c));
+  flic::Frame fliFrame;
+  fliFrame.pixels = bmp->getPixelAddress(0, 0);
+  fliFrame.rowstride = IndexedTraits::getRowStrideBytes(bmp->width());
+  for (frame_t frame_it=0;
+       frame_it <= sprite->totalFrames();
+       ++frame_it) {
+    frame_t frame = (frame_it % sprite->totalFrames());
+    const Palette* pal = sprite->palette(frame);
+    int size = MIN(256, pal->size());
+
+    for (int c=0; c<size; c++) {
+      color_t color = pal->getEntry(c);
+      fliFrame.colormap[c].r = rgba_getr(color);
+      fliFrame.colormap[c].g = rgba_getg(color);
+      fliFrame.colormap[c].b = rgba_getb(color);
     }
 
     // Render the frame in the bitmap
-    render.renderSprite(bmp, sprite, frpos);
+    render.renderSprite(bmp.get(), sprite, frame);
 
     // How many times this frame should be written to get the same
     // time that it has in the sprite
-    times = sprite->frameDuration(frpos) / fli_header.speed;
-
-    for (c=0; c<times; c++) {
-      // Write this frame
-      if (frpos == 0 && c == 0)
-        fli_write_frame(f, &fli_header, NULL, NULL,
-                        (unsigned char *)bmp->getPixelAddress(0, 0), cmap, W_ALL);
-      else
-        fli_write_frame(f, &fli_header,
-                        (unsigned char *)old->getPixelAddress(0, 0), omap,
-                        (unsigned char *)bmp->getPixelAddress(0, 0), cmap, W_ALL);
-
-      // Update the old image and color-map to the new ones to compare later
-      copy_image(old, bmp);
-      memcpy(omap, cmap, 768);
+    if (frame_it < sprite->totalFrames()) {
+      int times = sprite->frameDuration(frame) / header.speed;
+      times = MAX(1, times);
+      for (int c=0; c<times; c++)
+        encoder.writeFrame(fliFrame);
+    }
+    else {
+      encoder.writeRingFrame(fliFrame);
     }
 
     // Update progress
-    fop_progress(fop, (float)(frpos+1) / (float)(sprite->totalFrames()));
+    fop_progress(fop, (float)(frame_it+1) / (float)(sprite->totalFrames()+1));
   }
 
-  // Write the header and close the file
-  fli_write_header(f, &fli_header);
-
   return true;
 }
-#endif
 
-static int get_time_precision(Sprite *sprite)
-{
-  int precision = 1000;
-
-  for (frame_t c(0); c < sprite->totalFrames() && precision > 1; ++c) {
-    int len = sprite->frameDuration(c);
-
-    while (len / precision == 0)
-      precision /= 10;
-  }
-
-  return precision;
-}
+#endif
 
 } // namespace app
diff --git a/src/flic b/src/flic
new file mode 160000
index 0000000..357b718
--- /dev/null
+++ b/src/flic
@@ -0,0 +1 @@
+Subproject commit 357b71838560fd5ff1043719b4ebe4f2a8d0e6e4

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-games/aseprite.git



More information about the Pkg-games-commits mailing list