Page MenuHomePhabricator (Chris)

No OneTemporary

Authored By
Unknown
Size
43 KB
Referenced Files
None
Subscribers
None
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

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)

Event Timeline