Page Menu
Home
Phabricator (Chris)
Search
Configure Global Search
Log In
Files
F126636
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
43 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/util/gif/README b/util/gif/README
new file mode 100644
index 00000000..56474b78
--- /dev/null
+++ b/util/gif/README
@@ -0,0 +1,429 @@
+This is the text version of the documentation, which is autogenerated from
+the HTML version.
+
+,-------------------------------------------------------------------------.
+| algif - Allegro GIF Addon |
+`-------------------------------------------------------------------------'
+
+Version 1.2
+by Elias Pschernig
+Download - http://prdownloads.sourceforge.net/algif/algif_1.2.zip?download
+algif homepage - http://algif.sf.net
+Allegro homepage - http://alleg.sf.net
+
+,-------------------------------------------------------------------------.
+| Contents |
+`-------------------------------------------------------------------------'
+
+Not present in the .txt output.
+,-------------------------------------------------------------------------.
+| Introduction |
+`-------------------------------------------------------------------------'
+
+This is a simple addon to Allegro which allows reading and writing of GIF
+animations. It provides functionality both to integrate with Allegro's
+load_bitmap and save_bitmap functions, as well as reading full animations.
+The .gif specification can be found here: http://www.w3.org/Graphics/GIF
+/spec-gif89a.txt
+First of all, .gif may not be the right file format for you. It is severely
+limited, with no alpha channel, and only a maximum of 256 colors per frame.
+You may be better off using .png, which doesn't have any of these limits
+and compresses better. And there also exists an addon to use it with
+Allegro.
+Having said that, .gif still is a common format for small animated pictures
+on websites - and therefore very well suited for small pixel animations in
+games, since you can use the same files you display on your website
+directly as in-game animations.
+There are lots of other ways besides algif to read .gif files into an
+Allegro program. Some are:
+
+ * http://www.allegro.cc/depot/project-screenshots.php?id=648&
+
+ * http://angband.oook.cz/file.php?dir=10&file=load_gif.c
+
+The reason I released algif is, I wrote the code for it a long time ago, so
+never had a need to look at one of the other libraries - and maybe it has a
+useful feature which the others don't have.
+
+,-------------------------------------------------------------------------.
+| HOW TO USE |
+`-------------------------------------------------------------------------'
+
+The first, and hardest step, is to compile it. This may seem very simple:
+gcc -c *.c
+ar -rcs libalgif.a *.o
+Or simply compile the .c files along with your project.
+But in practice, it is much harder. You may prefer to use a makefile, in
+which case you can try the provided one, it was tested with a recent mingw
+and linux distribution.
+The makefile also has an install target, so if you type "make install", it
+will copy the libalgif.a to /usr/local/lib or $MINGDIR/lib and algif.h to
+/usr/local/include or $MINGDIR/include.
+And last, put include <algif.h> at the top of the source files where you
+want to use functions out of it, and link your program against it. With
+gcc, just add -lalgif as option.
+That should be it. If it doesn't work, contact me.
+
+,-------------------------------------------------------------------------.
+| API - Standard use |
+`-------------------------------------------------------------------------'
+
+These are the standard functions you will need when loading gif animations
+in your programs.
+
+
+algif_init
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+void algif_init (void);
+This function calls register_bitmap_file_type to make "gif" one of
+Allegro's supported bitmap formats. After you call this, you can load .gif
+pictures with load_bitmap, and save them with save_bitmap.
+Additionally, it will register a new datafile type with the id "GIF ". To
+create such datafiles, you first need to recompile grabber/dat with the GIF
+plugin. The ->dat member of GIF datafile objects will point to a
+GIF_ANIMATION (see below).
+
+
+load_gif
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+BITMAP *load_gif (char const *filename, RGB * pal);
+This will load all the frames stored in a .gif into a single BITMAP,
+following the semantics of Allegro's load_bitmap. After calling algif_init,
+this function will be automatically used for .gif files by load_bitmap.
+Note that this function uses Allegro's select_palette internally, so if you
+are using select_palette yourself, you need to restore the palette
+afterwards.
+
+
+save_gif
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+int save_gif (AL_CONST char *filename, BITMAP *bmp, AL_CONST RGB * pal);
+This will save a BITMAP as a gif image, following the semantics of
+Allegro's save_bitmap. After calling algif_init, this function will be
+automatically used for .gif files by save_bitmap.
+
+
+algif_load_animation
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+int algif_load_animation (const char *filename, BITMAP ***frames, int **durations);
+This will load a gif animation into an array of BITMAP pointers, and the
+frame durations into an integer array. A pointer to the BITMAPs is written
+to *frames, a pointer to the durations to *durations. Each bitmap will have
+the size of the complete animation. The bitmaps will all use Allegro's
+current color depth. Returns the number of stored frames, 0 on error. The
+durations are given in 1/100th seconds. You are responsible for freeing all
+the bitmaps as well as the arrays yourself.
+Example:
+BITMAP **frames = NULL;
+int *durations = NULL;
+int n = algif_load_animation ("my.gif", &frames, &durations);
+if (n)
+{
+ ...
+ for (i = 0; i < n; i++)
+ destroy_bitmap (frames[i]);
+ free (frames);
+ free (durations);
+}
+
+,-------------------------------------------------------------------------.
+| API - Advanced use |
+`-------------------------------------------------------------------------'
+
+Normally, you should not need to use these functions directly - the other
+functions are wrappers around them which are easier to use. But in case you
+need more control, or need to write out .gif animations, you may use them.
+See the descriptions of GIF_ANIMATION, GIF_FRAME and GIF_PALETTE for
+details on the values you can access/have to fill in.
+
+
+algif_load_raw_animation
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+GIF_ANIMATION *algif_load_raw_animation (char const *filename);
+Loads a .gif file into a GIF_ANIMATION structure.
+
+
+algif_create_raw_animation
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+GIF_ANIMATION *algif_create_raw_animation (int frames_count);
+Allocates an empty GIF_ANIMATION with the specified number of frames.
+
+
+destroy_gif_animation
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+void destroy_gif_animation (GIF_ANIMATION * gif);
+Deystroys a .gif animation, including all frames and bitmaps.
+
+
+algif_save_raw_animation
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+int algif_save_raw_animation (const char *filename, GIF_ANIMATION *gif);
+Saves a .gif animation. No optimizations are applied - if you want small
+gifs, you need to take care yourself to only include changed bitmap areas
+and only use as many palettes and colors as necessary. No comments or other
+invisible headers will be added.
+Returns 0 on success.
+
+
+algif_render_frame
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+void algif_render_frame (GIF_ANIMATION *gif, BITMAP *bitmap, int frame, int xpos, int ypos);
+This is the worker function which handles conversion of a GIF_ANIMATION to
+real bitmaps. You need to call it for every frame, starting with frame 0,
+and always specify the same x and y position. This guarantees that the
+right offsets and disposal methods are applied. In regular programs, you
+will never use this - use load_gif or algif_load_animation instead.
+
+
+GIF_ANIMATION
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This struct contains the following documented fields:
+
+ * int width, height; - Dimensions of the complete animation.
+
+ * int frame_count; - Number of frames.
+
+ * int background_color; - The background color index.
+
+ * GIF_PALETTE palette; - The global palette.
+
+ * GIF_FRAME *frames; - The frames.
+
+The background color is read/written - but not otherwise used by algif.
+
+
+GIF_FRAME
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This struct contains the following documented fields:
+
+ * BITMAP *bitmap_8_bit; - The bitmap, in 8-bit format.
+
+ * GIF_PALETTE palette; - The local palette for this frame.
+
+ * int xoff, yoff; - Offset of this frame into the animation.
+
+ * int duration; - Duration of the frame in 1/100th seconds.
+
+ * int disposal_method; - Disposal method of this frame.
+
+ * int transparent_index; - The transparent color for this frame.
+
+The disposal method has the same numeric value as in the .gif. It specifies
+how to dispose the frame. The values are: 0 - do not dispose (i.e.,
+whatever the application wants) 1 - keep (it is used as background for the
+next frame) 2 - background (before displaying the next frame, clear with
+background color) 3 - previous (before displaying the next frame, restore
+to previous frame)
+The transparent_index is set to -1 if it is not enabled while loading, and
+will cause the frame to be saved without the transparency flag when saving.
+Normally, you should not need to deal with disposal method and transparent
+index yourself, algif handles it for you.
+
+
+GIF_PALETTE
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+
+ * int colors_count; - Number of colors present.
+
+ * RGB colors[256]; - RGB triplets, where every color is from 0 to 255.
+
+Note that this is different from Allegro palettes which use RGB to only
+hold values from 0 to 63. The number of colors in a .gif palette always is
+a power of 2, so if you want small gifs, it helps using 64 colors instead
+of 65, but not using 65 colors instead of 128. If colors_count is 0, no
+global/local palette is present in the .gif file.
+
+,-------------------------------------------------------------------------.
+| Example gifs |
+`-------------------------------------------------------------------------'
+
+
+
+alex.gif
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+381 bytes
+This is allegro/misc/alex.xpm, converted to .gif. Look how much smaller the
+file is.
+
+
+allefant.gif
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+6172 bytes
+Just a gif animation I drew. Look how extremely small the file size is,
+given it is a 16 frame animation with 256x64 pixel.
+
+
+dispose.gif
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+475 bytes
+A gif animation demonstrating the different disposal methods for frames.
+The first frame in the upper left corner has a disposal method of "keep",
+so it just stays there when the second frame in the upper right corner is
+displayed. That frame has a disposal method of "previous", so when its
+duration is over, the animation reverts to the previous state where only
+the upper left frame is displayed. The third frame in the lower left corner
+is draw on top of it. It has a disposal method of "background", so before
+displaying the forth frame, its area is cleared to transparent. The last
+frame has no disposal method specified, since the last frame is never
+disposed and the animation starts all over when looping.
+
+
+rgb.gif
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+3257 bytes
+This is a gif which contains more than 256 colors ("truecolor gif"). As you
+can see, instead of compressing the file, it is blown up now to use more
+space than any other existing bitmap format would use for the same picture
+- but it shows how well algif can handle the .gif palettes.
+
+,-------------------------------------------------------------------------.
+| Example programs |
+`-------------------------------------------------------------------------'
+
+
+
+load_gif
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This is a simple example demonstrating load_gif. It will load alex.gif (or
+a gif given on the command line) by calling Allegro's load_bitmap, and
+display the bitmap. Since algif_init registers GIF as a known type, calling
+load_bitmap on a .gif file has the same effect as calling load_gif.
+
+
+load_animation
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This is an equally simple example, this time for algif_load_animation. It
+loads a GIF animation and loops it forever.
+
+
+load_raw_animation
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This example is here to demonstrate access to the raw GIF data. It loads a
+GIF, and displays global and per-frame information about it. Use cursor
+left/right to change the current frame.
+
+
+save_raw_animation
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In case you want to save gif animations, this shows how it is done. It
+creates two of the example gifs, dispose.gif and rgb.gif, then saves them
+as files.
+
+,-------------------------------------------------------------------------.
+| Miscellaneous |
+`-------------------------------------------------------------------------'
+
+
+
+TODO
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+There are a few things I can think of, which I don't need personally. If at
+least one person requests one of them, I will add it. If there are other
+requests, I will consider them as well of course. For some, like e.g.
+providing a version ready for MSVC or OSX users, I'd need help.
+
+ * Grabber plugin
+
+ * Better build process/autotools/libtool/dynamic library/...
+
+ * Better support for MSVC/OSX/djgpp/...
+
+ * Support for GIF comments
+
+ * Support for GIF text
+
+ * Automatic optimization (cropping, palette ordering)
+
+ * Make it work without Allegro
+
+
+
+BUGS
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Well, still quite a lot I guess. Please report. Release 1.0 meant, the base
+functinoality (loading a gif into allegro) worked. The lib will yet have to
+stabilize now.
+
+
+Version history
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+
+___________________________________________________________________________
+Version 1.0
+
+Initial version.
+
+___________________________________________________________________________
+Version 1.1
+
+Maintenance release, no functional change.
+
+___________________________________________________________________________
+Version 1.2 (Feb 2005)
+
+
+ * Jonny Cook reported problems with C++, added now extern "C" to algif.h
+
+ * Peter Wang fixed some bugs in save_gif
+
+ * Peter Wang fixed handling of palettes in load_gif
+
+
+
+License and disclaimer
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+
+___________________________________________________________________________
+Notes
+
+There was a patent on the LZW algorithm used with GIF files, but to my
+knowledge, this patent is expired by now, and therefore everyone is free to
+use the algorithm.. you should still check yourself though before using
+this code.
+The algif addon itself is put under the MIT license.
+
+___________________________________________________________________________
+MIT license
+
+Copyright (c) 2000-2004 algif contributors
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+
diff --git a/util/gif/algif.c b/util/gif/algif.c
new file mode 100644
index 00000000..524ed337
--- /dev/null
+++ b/util/gif/algif.c
@@ -0,0 +1,151 @@
+#include "algif.h"
+
+/* This will load a gif animation into an array of BITMAP pointers. Each
+ * bitmap will have the size of the complete animation. The bitmaps will all
+ * use Allegro's current color depth. Returns the number of stored frames,
+ * 0 on error. You are responsible for freeing all the bitmaps as well as
+ * the arrays yourself.
+ *
+ * E.g.
+ * BITMAP **frames = NULL;
+ * int **durations = NULL;
+ * int n = algif_load_animation ("my.gif", &frames, &durations);
+ * if (n)
+ * {
+ * ...
+ * for (i = 0; i < n; i++)
+ * destroy_bitmap (frames[i]);
+ * free (frames);
+ * free (durations);
+ * }
+ */
+int
+algif_load_animation (const char *filename, BITMAP ***frames, int **durations)
+{
+ GIF_ANIMATION *gif = algif_load_raw_animation (filename);
+ int i, n;
+ BITMAP *prev = NULL;
+
+ if (!gif)
+ return 0;
+
+ n = gif->frames_count;
+ *frames = calloc (n, sizeof **frames);
+ if (durations)
+ *durations = calloc (n, sizeof **durations);
+ for (i = 0; i < n; i++)
+ {
+ BITMAP *b = (*frames)[i] = create_bitmap (gif->width, gif->height);
+ if (prev)
+ blit (prev, b, 0, 0, 0, 0, b->w, b->h);
+ algif_render_frame (gif, b, i, 0, 0);
+ if (durations)
+ (*durations)[i] = gif->frames[i].duration;
+ prev = b;
+ }
+ algif_destroy_raw_animation (gif);
+ return n;
+}
+
+/* Allegrified version. Puts all frames into a single bitmap,
+ * with the current color depth. */
+BITMAP *
+load_gif (AL_CONST char *filename, RGB *pal)
+{
+ int i;
+ GIF_ANIMATION *gif = algif_load_raw_animation (filename);
+ BITMAP *bmp = NULL;
+ GIF_PALETTE gifpal;
+ PALETTE tmppal;
+
+ if (!gif || gif->frames_count == 0)
+ return NULL;
+
+ /* Either use the global palette, or the palette of the first frame. */
+ gifpal = gif->palette;
+ if (gifpal.colors_count == 0)
+ {
+ gifpal = gif->frames[0].palette;
+ }
+
+ if (!pal)
+ pal = tmppal;
+
+ for (i = 0; i < gifpal.colors_count; i++)
+ {
+ pal[i].r = gifpal.colors[i].r / 4;
+ pal[i].g = gifpal.colors[i].g / 4;
+ pal[i].b = gifpal.colors[i].b / 4;
+ }
+
+ for ( ; i < PAL_SIZE; i++) {
+ pal[i].r = 0;
+ pal[i].g = 0;
+ pal[i].b = 0;
+ }
+
+ if (gif)
+ {
+ bmp = create_bitmap (gif->width, gif->height);
+
+ select_palette(pal);
+
+ for (i = 0; i < gif->frames_count; i++)
+ {
+ algif_render_frame (gif, bmp, i, 0, 0);
+ }
+
+ unselect_palette();
+
+ algif_destroy_raw_animation (gif);
+ }
+
+ return bmp;
+}
+
+/* Allegrified version. Saves only a single bitmap. */
+int
+save_gif (AL_CONST char *filename, BITMAP *bmp, AL_CONST PALETTE pal)
+{
+ GIF_ANIMATION gif;
+ GIF_FRAME frame;
+ int ret, i;
+ PALETTE cp;
+
+ gif.width = bmp->w;
+ gif.height = bmp->h;
+ gif.frames_count = 1;
+ gif.background_index = 0;
+ gif.loop = -1;
+ gif.palette.colors_count = 0;
+
+ gif.frames = &frame;
+ frame.bitmap_8_bit = create_bitmap_ex (8, bmp->w, bmp->h);
+ frame.palette.colors_count = 0;
+ frame.xoff = 0;
+ frame.yoff = 0;
+ frame.duration = 0;
+ frame.disposal_method = 0;
+ frame.transparent_index = -1;
+
+ blit (bmp, frame.bitmap_8_bit, 0, 0, 0, 0, bmp->w, bmp->h);
+
+ if (!pal)
+ {
+ get_palette (cp);
+ pal = cp;
+ }
+
+ frame.palette.colors_count = 256;
+ for (i = 0; i < 256; i++)
+ {
+ frame.palette.colors[i].r = _rgb_scale_6[pal[i].r];
+ frame.palette.colors[i].g = _rgb_scale_6[pal[i].g];
+ frame.palette.colors[i].b = _rgb_scale_6[pal[i].b];
+ }
+
+ ret = algif_save_raw_animation (filename, &gif);
+ destroy_bitmap (frame.bitmap_8_bit);
+ return ret;
+}
+
diff --git a/util/gif/algif.h b/util/gif/algif.h
new file mode 100644
index 00000000..e07d4adf
--- /dev/null
+++ b/util/gif/algif.h
@@ -0,0 +1,61 @@
+#ifndef _GIF_H_
+#define _GIF_H_
+
+#include <allegro.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define DAT_GIF DAT_ID('G','I','F',' ')
+
+typedef struct GIF_ANIMATION GIF_ANIMATION;
+typedef struct GIF_FRAME GIF_FRAME;
+typedef struct GIF_PALETTE GIF_PALETTE;
+
+struct GIF_PALETTE
+{
+ int colors_count;
+ RGB colors[256];
+};
+
+struct GIF_ANIMATION
+{
+ int width, height;
+ int frames_count;
+ int background_index;
+ int loop; /* -1 = no, 0 = forever, 1..65535 = that many times */
+ GIF_PALETTE palette;
+ GIF_FRAME *frames;
+
+ BITMAP *store;
+};
+
+struct GIF_FRAME
+{
+ BITMAP *bitmap_8_bit;
+ GIF_PALETTE palette;
+ int xoff, yoff;
+ int duration; /* in 1/100th seconds */
+ int disposal_method; /* 0 = don't care, 1 = keep, 2 = background, 3 = previous */
+ int transparent_index;
+};
+
+/* Simple use. */
+void algif_init (void);
+int algif_load_animation (char const *filename, BITMAP ***frames, int **durations);
+BITMAP *load_gif (AL_CONST char *filename, RGB *pal);
+int save_gif (AL_CONST char *filename, BITMAP *bmp, AL_CONST RGB *pal);
+
+/* Advanced use. */
+GIF_ANIMATION *algif_load_raw_animation (char const *filename);
+void algif_render_frame (GIF_ANIMATION *gif, BITMAP *bitmap, int frame, int xpos, int ypos);
+GIF_ANIMATION *algif_create_raw_animation (int frames_count);
+int algif_save_raw_animation (const char *filename, GIF_ANIMATION *gif);
+void algif_destroy_raw_animation (GIF_ANIMATION *gif);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/util/gif/gif.c b/util/gif/gif.c
new file mode 100644
index 00000000..7f522a72
--- /dev/null
+++ b/util/gif/gif.c
@@ -0,0 +1,459 @@
+#include "algif.h"
+#include "lzw.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+GIF_ANIMATION *
+algif_create_raw_animation (int frames_count)
+{
+ GIF_ANIMATION *gif = calloc (1, sizeof *gif);
+ /* Create frames. */
+ gif->frames_count = frames_count;
+ gif->frames = calloc (gif->frames_count, sizeof *gif->frames);
+ return gif;
+}
+
+/* Destroy a complete gif, including all frames. */
+void
+algif_destroy_raw_animation (GIF_ANIMATION *gif)
+{
+ int i;
+
+ for (i = 0; i < gif->frames_count; i++)
+ {
+ GIF_FRAME *frame = gif->frames + i;
+
+ if (frame->bitmap_8_bit)
+ destroy_bitmap (frame->bitmap_8_bit);
+ }
+ if (gif->store)
+ destroy_bitmap (gif->store);
+ free (gif->frames);
+ free (gif);
+}
+
+static void
+write_palette (PACKFILE *file, GIF_PALETTE *palette, int bits)
+{
+ int i;
+ for (i = 0; i < (1 << bits); i++)
+ {
+ pack_putc (palette->colors[i].r, file);
+ pack_putc (palette->colors[i].g, file);
+ pack_putc (palette->colors[i].b, file);
+ }
+}
+
+static void
+read_palette (PACKFILE * file, GIF_PALETTE *palette)
+{
+ int i;
+
+ for (i = 0; i < palette->colors_count; i++)
+ {
+ palette->colors[i].r = pack_getc (file);
+ palette->colors[i].g = pack_getc (file);
+ palette->colors[i].b = pack_getc (file);
+ }
+}
+
+/*
+ * Compresses all the frames in the animation and writes to a gif file.
+ * Nothing else like extensions or comments is written.
+ *
+ * Returns 0 on success.
+ *
+ * Note: All bitmaps must have a color depth of 8.
+ */
+int
+algif_save_raw_animation (const char *filename, GIF_ANIMATION *gif)
+{
+ int frame;
+ int i, j;
+ PACKFILE *file;
+
+ file = pack_fopen (filename, "w");
+ if (!file)
+ return -1;
+
+ pack_fwrite ("GIF89a", 6, file);
+ pack_iputw (gif->width, file);
+ pack_iputw (gif->height, file);
+ /* 7 global palette
+ * 456 color richness
+ * 3 sorted
+ * 012 palette bits
+ */
+ for (i = 1, j = 0; i < gif->palette.colors_count; i *= 2, j++);
+ pack_putc ((j ? 128 : 0) + 64 + 32 + 16 + (j ? j - 1 : 0), file);
+ pack_putc (gif->background_index, file);
+ pack_putc (0, file); /* No aspect ratio. */
+
+ if (j)
+ write_palette (file, &gif->palette, j);
+
+ if (gif->loop != -1)
+ /* Loop count extension. */
+ {
+ pack_putc (0x21, file); /* Extension Introducer. */
+ pack_putc (0xff, file); /* Application Extension. */
+ pack_putc (11, file); /* Size. */
+ pack_fwrite ("NETSCAPE2.0", 11, file);
+ pack_putc (3, file); /* Size. */
+ pack_putc (1, file);
+ pack_iputw (gif->loop, file);
+ pack_putc (0, file);
+ }
+
+ for (frame = 0; frame < gif->frames_count; frame++)
+ {
+ int w = gif->frames[frame].bitmap_8_bit->w;
+ int h = gif->frames[frame].bitmap_8_bit->h;
+
+ pack_putc (0x21, file); /* Extension Introducer. */
+ pack_putc (0xf9, file); /* Graphic Control Extension. */
+ pack_putc (4, file); /* Size. */
+ /* Disposal method, and enable transparency. */
+ i = gif->frames[frame].disposal_method << 2;
+ if (gif->frames[frame].transparent_index != -1)
+ i |= 1;
+ pack_putc (i, file);
+ pack_iputw (gif->frames[frame].duration, file); /* In 1/100th seconds. */
+ if (gif->frames[frame].transparent_index != -1)
+ pack_putc (gif->frames[frame].transparent_index, file); /* Transparent color index. */
+ else
+ pack_putc (0, file);
+ pack_putc (0x00, file); /* Terminator. */
+
+ pack_putc (0x2c, file); /* Image Descriptor. */
+ pack_iputw (gif->frames[frame].xoff, file);
+ pack_iputw (gif->frames[frame].yoff, file);
+ pack_iputw (w, file);
+ pack_iputw (h, file);
+
+ /* 7: local palette
+ * 6: interlaced
+ * 5: sorted
+ * 012: palette bits
+ */
+
+ for (i = 1, j = 0; i < gif->frames[frame].palette.colors_count; i *= 2, j++);
+ pack_putc ((j ? 128 : 0) + (j ? j - 1 : 0), file);
+
+ if (j)
+ write_palette (file, &gif->frames[frame].palette, j);
+
+ LZW_encode (file, gif->frames[frame].bitmap_8_bit);
+
+ pack_putc (0x00, file); /* Terminator. */
+ }
+
+ pack_putc (0x3b, file); /* Trailer. */
+
+ pack_fclose (file);
+ return 0;
+}
+
+static void
+deinterlace (BITMAP *bmp)
+{
+ BITMAP *n = create_bitmap_ex (bitmap_color_depth (bmp), bmp->w, bmp->h);
+ int y, i = 0;
+ for (y = 0; y < n->h; y += 8)
+ {
+ blit (bmp, n, 0, i++, 0, y, n->w, 1);
+ }
+ for (y = 4; y < n->h; y += 8)
+ {
+ blit (bmp, n, 0, i++, 0, y, n->w, 1);
+ }
+ for (y = 2; y < n->h; y += 4)
+ {
+ blit (bmp, n, 0, i++, 0, y, n->w, 1);
+ }
+ for (y = 1; y < n->h; y += 2)
+ {
+ blit (bmp, n, 0, i++, 0, y, n->w, 1);
+ }
+ blit (n, bmp, 0, 0, 0, 0, n->w, n->h);
+ destroy_bitmap (n);
+}
+
+static GIF_ANIMATION *
+load_object (PACKFILE * file, long size)
+{
+ int version;
+ BITMAP *bmp = NULL;
+ int i, j;
+ GIF_ANIMATION *gif = calloc (1, sizeof *gif);
+ GIF_FRAME frame;
+ int have_global_palette = 0;
+
+ (void) size;
+
+ gif->frames_count = 0;
+
+ /* is it really a GIF? */
+ if (pack_getc (file) != 'G')
+ goto error;
+ if (pack_getc (file) != 'I')
+ goto error;
+ if (pack_getc (file) != 'F')
+ goto error;
+ if (pack_getc (file) != '8')
+ goto error;
+ /* '7' or '9', for 87a or 89a. */
+ version = pack_getc (file);
+ if (version != '7' && version != '9')
+ goto error;
+ if (pack_getc (file) != 'a')
+ goto error;
+
+ gif->width = pack_igetw (file);
+ gif->height = pack_igetw (file);
+ i = pack_getc (file);
+ /* Global color table? */
+ if (i & 128)
+ gif->palette.colors_count = 1 << ((i & 7) + 1);
+ else
+ gif->palette.colors_count = 0;
+ /* Background color is only valid with a global palette. */
+ gif->background_index = pack_getc (file);
+
+ /* Skip aspect ratio. */
+ pack_fseek (file, 1);
+
+ if (gif->palette.colors_count)
+ {
+ read_palette (file, &gif->palette);
+ have_global_palette = 1;
+ }
+
+ memset(&frame, 0, sizeof frame); /* For first frame. */
+ frame.transparent_index = -1;
+
+ do
+ {
+ i = pack_getc (file);
+
+ switch (i)
+ {
+ case 0x2c: /* Image Descriptor */
+ {
+ int w, h;
+ int interlaced = 0;
+
+ frame.xoff = pack_igetw (file);
+ frame.yoff = pack_igetw (file);
+ w = pack_igetw (file);
+ h = pack_igetw (file);
+ bmp = create_bitmap_ex (8, w, h);
+ if (!bmp)
+ goto error;
+ i = pack_getc (file);
+
+ /* Local palette. */
+ if (i & 128)
+ {
+ frame.palette.colors_count = 1 << ((i & 7) + 1);
+ read_palette (file, &frame.palette);
+ }
+ else
+ {
+ frame.palette.colors_count = 0;
+ }
+
+ if (i & 64)
+ interlaced = 1;
+
+ if (LZW_decode (file, bmp))
+ goto error;
+
+ if (interlaced)
+ deinterlace (bmp);
+
+ frame.bitmap_8_bit = bmp;
+ bmp = NULL;
+
+ gif->frames_count++;
+ gif->frames =
+ realloc (gif->frames,
+ gif->frames_count * sizeof *gif->frames);
+ gif->frames[gif->frames_count - 1] = frame;
+
+ memset(&frame, 0, sizeof frame); /* For next frame. */
+ frame.transparent_index = -1;
+
+ break;
+ }
+ case 0x21: /* Extension Introducer. */
+ j = pack_getc (file); /* Extension Type. */
+ i = pack_getc (file); /* Size. */
+ if (j == 0xf9) /* Graphic Control Extension. */
+ {
+ /* size must be 4 */
+ if (i != 4)
+ goto error;
+ i = pack_getc (file);
+ frame.disposal_method = (i >> 2) & 7;
+ frame.duration = pack_igetw (file);
+ if (i & 1) /* Transparency? */
+ {
+ frame.transparent_index = pack_getc (file);
+ }
+ else
+ {
+ pack_fseek (file, 1);
+ frame.transparent_index = -1;
+ }
+ i = pack_getc (file); /* Size. */
+ }
+ /* Application Extension. */
+ else if (j == 0xff)
+ {
+ if (i == 11)
+ {
+ char name[12];
+ pack_fread (name, 11, file);
+ i = pack_getc (file); /* Size. */
+ name[11] = '\0';
+ if (!strcmp (name, "NETSCAPE2.0"))
+ {
+ if (i == 3)
+ {
+ j = pack_getc (file);
+ gif->loop = pack_igetw (file);
+ if (j != 1)
+ gif->loop = 0;
+ i = pack_getc (file); /* Size. */
+ }
+ }
+ }
+ }
+
+ /* Possibly more blocks until terminator block (0). */
+ while (i)
+ {
+ pack_fseek (file, i);
+ i = pack_getc (file);
+ }
+ break;
+ case 0x3b:
+ /* GIF Trailer. */
+ pack_fclose (file);
+ return gif;
+ }
+ }
+ while (TRUE);
+ error:
+ if (file)
+ pack_fclose (file);
+ if (gif)
+ algif_destroy_raw_animation (gif);
+ if (bmp)
+ destroy_bitmap (bmp);
+ return NULL;
+}
+
+/*
+ * Allocates and reads a GIF_ANIMATION structure, filling in all the
+ * frames found in the file. On error, nothing is allocated, and NULL is
+ * returned. No extensions or comments are read in. If the gif contains
+ * a transparency index, and it is no 0, it is swapped with 0 - so index
+ * 0 will be the transparent color. There is no way to know when a file
+ * contained no transparency originally. Frame duration is specified in
+ * 1/100th seconds.
+ *
+ * All bitmaps will have a color depth of 8.
+ */
+GIF_ANIMATION *
+algif_load_raw_animation (const char *filename)
+{
+ PACKFILE *file;
+ GIF_ANIMATION *gif = NULL;
+
+ file = pack_fopen (filename, "r");
+ if (file)
+ gif = load_object (file, 0);
+ return gif;
+}
+
+static int
+get_rgbcolor (RGB *rgb)
+{
+ return makecol (rgb->r, rgb->g, rgb->b);
+}
+
+/* Renders the next frame in a GIF animation to the specified bitmap and
+ * the given position. You need to call this in order on the same
+ * destination for frames [0..gif->frames_count - 1] to properly render all
+ * the frames in the GIF.
+ */
+void
+algif_render_frame (GIF_ANIMATION *gif, BITMAP *bitmap, int frame, int xpos,
+ int ypos)
+{
+ int x, y, w, h;
+ GIF_FRAME *f = &gif->frames[frame];
+ GIF_PALETTE *pal;
+ if (frame == 0)
+ rectfill (bitmap, xpos, ypos, xpos + gif->width - 1,
+ ypos + gif->height - 1, bitmap_mask_color (bitmap));
+ else
+ {
+ GIF_FRAME *p = &gif->frames[frame - 1];
+ if (p->disposal_method == 2)
+ rectfill (bitmap, xpos + p->xoff, ypos + p->yoff,
+ xpos + p->xoff + p->bitmap_8_bit->w - 1,
+ ypos + p->yoff + p->bitmap_8_bit->h - 1,
+ bitmap_mask_color (bitmap));
+ else if (p->disposal_method == 3 && gif->store)
+ {
+ blit (gif->store, bitmap, 0, 0, xpos + p->xoff, ypos + p->yoff,
+ gif->store->w, gif->store->h);
+ destroy_bitmap (gif->store);
+ gif->store = NULL;
+ }
+ }
+ w = f->bitmap_8_bit->w;
+ h = f->bitmap_8_bit->h;
+ if (f->disposal_method == 3)
+ {
+ if (gif->store)
+ destroy_bitmap (gif->store);
+ gif->store = create_bitmap_ex (bitmap_color_depth (bitmap), w, h);
+ blit (bitmap, gif->store, xpos + f->xoff, ypos + f->yoff, 0, 0, w, h);
+ }
+ pal = &gif->frames[frame].palette;
+ if (pal->colors_count == 0)
+ pal = &gif->palette;
+
+ //int i;
+ //for (i = 0; i < pal->colors_count; i++)
+ // printf("%d: %d %d %d\n", i, pal->colors[i].r, pal->colors[i].g, pal->colors[i].b);
+
+ for (y = 0; y < h; y++)
+ {
+ for (x = 0; x < w; x++)
+ {
+ int c = getpixel (f->bitmap_8_bit, x, y);
+ if (c != f->transparent_index)
+ {
+ putpixel (bitmap, xpos + f->xoff + x, ypos + f->yoff + y,
+ get_rgbcolor (&pal->colors[c]));
+ }
+ }
+ }
+}
+
+/* Registers gif as bitmap and datafile type. */
+void
+algif_init (void)
+{
+ register_bitmap_file_type ("gif", load_gif, save_gif);
+ register_datafile_object (DAT_GIF,
+ (void *(*)(PACKFILE *, long)) load_object,
+ (void (*)(void *))
+ algif_destroy_raw_animation);
+}
diff --git a/util/gif/gif.h b/util/gif/gif.h
new file mode 100644
index 00000000..1539d6e2
--- /dev/null
+++ b/util/gif/gif.h
@@ -0,0 +1 @@
+#include "algif.h"
diff --git a/util/gif/icon.res b/util/gif/icon.res
new file mode 100644
index 00000000..8c12e5f2
Binary files /dev/null and b/util/gif/icon.res differ
diff --git a/util/gif/lzw.c b/util/gif/lzw.c
new file mode 100644
index 00000000..445d9698
--- /dev/null
+++ b/util/gif/lzw.c
@@ -0,0 +1,300 @@
+#include "lzw.h"
+
+static int
+read_code (PACKFILE * file, char *buf, int *bit_pos, int bit_size)
+{
+ int i;
+ int code = 0;
+ int pos = 1;
+
+ for (i = 0; i < bit_size; i++)
+ {
+ int byte_pos = (*bit_pos >> 3) & 255;
+
+ if (byte_pos == 0)
+ {
+ int data_len = pack_getc (file);
+
+ if (data_len == 0)
+ {
+ //printf ("Fatal. Errorneous GIF stream.\n");
+ //abort ();
+ return -1;
+ }
+ pack_fread (buf + 256 - data_len, data_len, file);
+ byte_pos = 256 - data_len;
+ *bit_pos = byte_pos << 3;
+ }
+ if (buf[byte_pos] & (1 << (*bit_pos & 7)))
+ code += pos;
+ pos += pos;
+ (*bit_pos)++;
+ }
+ return code;
+}
+
+static void
+write_code (PACKFILE * file, char *buf, int *bit_pos, int bit_size, int code)
+{
+ int i;
+ int pos = 1;
+
+ for (i = 0; i < bit_size; i++)
+ {
+ int byte_pos = *bit_pos >> 3;
+
+ if (code & pos)
+ buf[byte_pos] |= (1 << (*bit_pos & 7));
+ else
+ buf[byte_pos] &= ~(1 << (*bit_pos & 7));
+ (*bit_pos)++;
+ if (*bit_pos == 2040)
+ {
+ pack_putc (byte_pos + 1, file);
+ pack_fwrite (buf, byte_pos + 1, file);
+ *bit_pos = 0;
+ }
+ pos += pos;
+ }
+}
+
+static int
+read_pixel (BITMAP *bmp, int pos)
+{
+ return getpixel (bmp, pos % bmp->w, pos / bmp->w);
+}
+
+static void
+write_pixel (BITMAP *bmp, int pos, int code)
+{
+ putpixel (bmp, pos % bmp->w, pos / bmp->w, code);
+}
+
+int
+LZW_decode (PACKFILE * file, BITMAP *bmp)
+{
+ int orig_bit_size;
+ char buf[256];
+ int bit_size;
+ int bit_pos;
+ int clear_marker;
+ int end_marker;
+ struct
+ {
+ int prefix;
+ int c;
+ int len;
+ }
+ codes[4096]; /* Maximum bit size is 12. */
+ int n;
+ int i, prev, code, c;
+ int out_pos = 0;
+
+ orig_bit_size = pack_getc (file);
+ n = 2 + (1 << orig_bit_size);
+
+ for (i = 0; i < n; i++)
+ {
+ codes[i].c = i;
+ codes[i].len = 0;
+ }
+
+ clear_marker = n - 2;
+ end_marker = n - 1;
+
+ bit_size = orig_bit_size + 1;
+
+ bit_pos = 0;
+
+ /* Expect to read clear code as first code here. */
+ prev = read_code (file, buf, &bit_pos, bit_size);
+ if (prev == -1)
+ return -1;
+ do
+ {
+ code = read_code (file, buf, &bit_pos, bit_size);
+ if (code == -1)
+ return -1;
+ if (code == clear_marker)
+ {
+ bit_size = orig_bit_size;
+ n = 1 << bit_size;
+ n += 2;
+ bit_size++;
+ prev = code;
+ continue;
+ }
+
+ if (code == end_marker)
+ break;
+
+ /* Known code: ok. Else: must be doubled char. */
+ if (code < n)
+ c = code;
+ else
+ c = prev;
+
+ /* Output the code. */
+ out_pos += codes[c].len;
+ i = 0;
+ do
+ {
+ write_pixel (bmp, out_pos - i, codes[c].c);
+ if (codes[c].len)
+ c = codes[c].prefix;
+ else
+ break;
+ i++;
+ }
+ while (1);
+
+ out_pos++;
+
+ /* Unknown code -> must be double char. */
+ if (code >= n)
+ {
+ write_pixel (bmp, out_pos, codes[c].c);
+ out_pos++;
+ }
+
+ /* Except after clear marker, build new code. */
+ if (prev != clear_marker)
+ {
+ codes[n].prefix = prev;
+ codes[n].len = codes[prev].len + 1;
+ codes[n].c = codes[c].c;
+ n++;
+ }
+
+ /* Out of bits? Increase. */
+ if (n == (1 << bit_size))
+ {
+ if (bit_size < 12)
+ bit_size++;
+ }
+
+ prev = code;
+ }
+ while (1);
+ return 0;
+}
+
+static int
+get_minimum_bitsize (BITMAP *bmp)
+{
+ int x, y, max = 0, b = 2;
+ for (y = 0; y < bmp->h; y++)
+ {
+ for (x = 0; x < bmp->w; x++)
+ {
+ int c = getpixel (bmp, x, y);
+ if (c > max)
+ max = c;
+ }
+ }
+ while ((1 << b) <= max)
+ {
+ b++;
+ }
+ return b;
+}
+
+void
+LZW_encode (PACKFILE * file, BITMAP *bmp)
+{
+ int orig_bit_size;
+ int bit_size;
+ char buf[256];
+ int bit_pos;
+ int clear_marker;
+ int end_marker;
+ struct
+ {
+ int prefix;
+ int c;
+ int len;
+ }
+ codes[4096]; /* Maximum bit size is 12. */
+ int code, prev;
+ int in_pos;
+ int n, i;
+
+ orig_bit_size = get_minimum_bitsize (bmp);
+
+ n = 2 + (1 << orig_bit_size);
+
+ for (i = 0; i < n; i++)
+ {
+ codes[i].c = i;
+ codes[i].len = 0;
+ }
+
+ clear_marker = n - 2;
+ end_marker = n - 1;
+
+ pack_putc (orig_bit_size, file);
+
+ bit_size = orig_bit_size + 1;
+
+ bit_pos = 0;
+
+ /* Play fair and put a clear marker at the start. */
+ write_code (file, buf, &bit_pos, bit_size, clear_marker);
+
+ prev = read_pixel (bmp, 0);
+
+ for (in_pos = 1; in_pos < bmp->w * bmp->h; in_pos++)
+ {
+ code = read_pixel (bmp, in_pos);
+
+ if (prev != clear_marker)
+ {
+ /* Search for the code. */
+ for (i = end_marker + 1; i < n; i++)
+ {
+ if (codes[i].prefix == prev && codes[i].c == code)
+ {
+ code = i;
+ break;
+ }
+ }
+
+ /* If not found, add it, and write previous code. */
+ if (i == n)
+ {
+ codes[n].prefix = prev;
+ codes[n].len = codes[prev].len + 1;
+ codes[n].c = code;
+ n++;
+
+ write_code (file, buf, &bit_pos, bit_size, prev);
+ }
+ }
+
+ /* Out of bits? Increase. */
+ if (n == 1 + (1 << bit_size))
+ {
+ if (bit_size < 12)
+ bit_size++;
+ }
+
+ /* Too big table? Clear and start over. */
+ if (n == 4096)
+ {
+ write_code (file, buf, &bit_pos, bit_size, clear_marker);
+ bit_size = orig_bit_size + 1;
+ n = end_marker + 1;
+ }
+
+ prev = code;
+ }
+ write_code (file, buf, &bit_pos, bit_size, prev);
+ write_code (file, buf, &bit_pos, bit_size, end_marker);
+ if (bit_pos)
+ {
+ int byte_pos = (bit_pos + 7) / 8;
+
+ pack_putc (byte_pos, file);
+ pack_fwrite (buf, byte_pos, file);
+ }
+}
diff --git a/util/gif/lzw.h b/util/gif/lzw.h
new file mode 100644
index 00000000..54a78a5b
--- /dev/null
+++ b/util/gif/lzw.h
@@ -0,0 +1,6 @@
+#ifndef _LZW_H_
+#define _LZW_H_
+#include <allegro.h>
+int LZW_decode (PACKFILE * file, BITMAP *bmp);
+void LZW_encode (PACKFILE * file, BITMAP *bmp);
+#endif
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Thu, Jun 11, 12:19 PM (3 w, 4 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
69000
Default Alt Text
(43 KB)
Attached To
Mode
R75 R-Tech1
Attached
Detach File
Event Timeline