#endif
#include <errno.h>
#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
/*
=head1 NAME
-gif.c - read and write gif files for Imager
+imgif.c - read and write gif files for Imager
=head1 SYNOPSIS
static char const *gif_error_msg(int code);
static void gif_push_error(void);
-static int gif_read_callback(GifFileType *gft, GifByteType *buf, int length);
-
/* Make some variables global, so we could access them faster: */
static int
}
}
-long
+#ifdef GIF_LIB_VERSION
+
+static const
+char gif_version_str[] = GIF_LIB_VERSION;
+
+double
i_giflib_version(void) {
- return 10;
+ const char *p = gif_version_str;
+
+ while (*p && (*p < '0' || *p > '9'))
+ ++p;
+
+ if (!*p)
+ return 0;
+
+ return strtod(p, NULL);
}
+#else
+
+double
+i_giflib_version(void) {
+ return GIFLIB_MAJOR + GIFLIB_MINOR * 0.1;
+}
+
+#endif
+
/*
=item i_readgif_low(GifFileType *GifFile, int **colour_table, int *colours)
io_glue_read_cb(GifFileType *gft, GifByteType *buf, int length) {
io_glue *ig = (io_glue *)gft->UserData;
- return ig->readcb(ig, buf, length);
+ return i_io_read(ig, buf, length);
}
i_img *
i_img *
i_readgif_single_wiol(io_glue *ig, int page) {
- i_clear_error();
+ GifFileType *GifFile;
+ i_clear_error();
if (page < 0) {
i_push_error(0, "page must be non-negative");
return NULL;
}
- GifFileType *GifFile;
-
if ((GifFile = DGifOpen((void *)ig, io_glue_read_cb )) == NULL) {
gif_push_error();
i_push_error(0, "Cannot create giflib callback object");
}
else {
char buf[50];
+#ifdef IMAGER_SNPRINTF
+ snprintf(buf, sizeof(buf), "%d", img->tags.tags[pos].idata);
+#else
sprintf(buf, "%d", img->tags.tags[pos].idata);
+#endif
if (EGifPutComment(gf, buf) == GIF_ERROR) {
return 0;
}
}
/*
-=item has_common_palette(imgs, count, quant, want_trans)
+=item has_common_palette(imgs, count, quant)
-Tests if all the given images are paletted and have a common palette,
-if they do it builds that palette.
+Tests if all the given images are paletted and their colors are in the
+palette produced.
-A possible improvement might be to eliminate unused colors in the
-images palettes.
+Previously this would build a consolidated palette from the source,
+but that meant that if the caller supplied a static palette (or
+specified a fixed palette like "webmap") then we wouldn't be
+quantizing to the caller specified palette.
=cut
*/
+
static int
-has_common_palette(i_img **imgs, int count, i_quantize *quant,
- int want_trans) {
- int size = quant->mc_count;
+has_common_palette(i_img **imgs, int count, i_quantize *quant) {
int i;
int imgn;
char used[256];
+ int col_count;
/* we try to build a common palette here, if we can manage that, then
that's the palette we use */
memset(used, 1, sizeof(used));
}
- for (i = 0; i < i_colorcount(imgs[imgn]); ++i) {
+ col_count = i_colorcount(imgs[imgn]);
+ for (i = 0; i < col_count; ++i) {
i_color c;
i_getcolors(imgs[imgn], i, &c, 1);
if (used[i]) {
- if (in_palette(&c, quant, size) < 0) {
- if (size < quant->mc_size) {
- quant->mc_colors[size++] = c;
- }
- else {
- /* oops, too many colors */
- return 0;
- }
+ if (in_palette(&c, quant, quant->mc_count) < 0) {
+ mm_log((1, " color not found in palette, no palette shortcut\n"));
+
+ return 0;
}
}
}
}
- quant->mc_count = size;
+ mm_log((1, " all colors found in palette, palette shortcut\n"));
return 1;
}
i_palidx *p = data;
i_palidx trans[256];
int i;
- int x, y;
+ i_img_dim x, y;
/* build a translation table */
for (i = 0; i < i_colorcount(img); ++i) {
if (!i_tags_get_int(&imgs[0]->tags, "gif_screen_width", 0, &scrw))
scrw = 0;
if (!i_tags_get_int(&imgs[0]->tags, "gif_screen_height", 0, &scrh))
- scrw = 0;
+ scrh = 0;
anylocal = 0;
localmaps = mymalloc(sizeof(int) * count);
glob_img_count = 0;
glob_want_trans = 0;
for (imgn = 0; imgn < count; ++imgn) {
+ i_img *im = imgs[imgn];
+ if (im->xsize > 0xFFFF || im->ysize > 0xFFFF) {
+ i_push_error(0, "image too large for GIF");
+ return 0;
+ }
+
posx = posy = 0;
- i_tags_get_int(&imgs[imgn]->tags, "gif_left", 0, &posx);
- i_tags_get_int(&imgs[imgn]->tags, "gif_top", 0, &posy);
- if (imgs[imgn]->xsize + posx > scrw)
- scrw = imgs[imgn]->xsize + posx;
- if (imgs[imgn]->ysize + posy > scrh)
- scrh = imgs[imgn]->ysize + posy;
- if (!i_tags_get_int(&imgs[imgn]->tags, "gif_local_map", 0, localmaps+imgn))
+ i_tags_get_int(&im->tags, "gif_left", 0, &posx);
+ if (posx < 0) posx = 0;
+ i_tags_get_int(&im->tags, "gif_top", 0, &posy);
+ if (posy < 0) posy = 0;
+ if (im->xsize + posx > scrw)
+ scrw = im->xsize + posx;
+ if (im->ysize + posy > scrh)
+ scrh = im->ysize + posy;
+ if (!i_tags_get_int(&im->tags, "gif_local_map", 0, localmaps+imgn))
localmaps[imgn] = 0;
if (localmaps[imgn])
anylocal = 1;
else {
- if (imgs[imgn]->channels == 4) {
+ if (im->channels == 4) {
glob_want_trans = 1;
}
- glob_imgs[glob_img_count++] = imgs[imgn];
+ glob_imgs[glob_img_count++] = im;
}
}
glob_want_trans = glob_want_trans && quant->transp != tr_none ;
+ if (scrw > 0xFFFF || scrh > 0xFFFF) {
+ i_push_error(0, "screen size too large for GIF");
+ return 0;
+ }
+
orig_count = quant->mc_count;
orig_size = quant->mc_size;
mm_log((2, " reserving color for transparency\n"));
--quant->mc_size;
}
- if (has_common_palette(glob_imgs, glob_img_count, quant, want_trans)) {
- glob_paletted = 1;
- }
- else {
- glob_paletted = 0;
- i_quant_makemap(quant, glob_imgs, glob_img_count);
- }
+
+ i_quant_makemap(quant, glob_imgs, glob_img_count);
+ glob_paletted = has_common_palette(glob_imgs, glob_img_count, quant);
glob_color_count = quant->mc_count;
quant->mc_colors = orig_colors;
}
}
else {
want_trans = quant->transp != tr_none && imgs[0]->channels == 4;
- if (has_common_palette(imgs, 1, quant, want_trans)) {
- colors_paletted = 1;
- }
- else {
- colors_paletted = 0;
- i_quant_makemap(quant, imgs, 1);
- }
+ i_quant_makemap(quant, imgs, 1);
+ colors_paletted = has_common_palette(imgs, 1, quant);
}
+
if ((map = make_gif_map(quant, imgs[0], want_trans)) == NULL) {
myfree(glob_colors);
myfree(localmaps);
to give room for a transparency colour */
if (want_trans && quant->mc_size == 256)
--quant->mc_size;
- if (has_common_palette(imgs, 1, quant, want_trans)) {
- colors_paletted = 1;
- }
- else {
- colors_paletted = 0;
- i_quant_makemap(quant, imgs, 1);
- }
+ i_quant_makemap(quant, imgs, 1);
+ colors_paletted = has_common_palette(imgs, 1, quant);
if ((map = make_gif_map(quant, imgs[0], want_trans)) == NULL) {
myfree(glob_colors);
myfree(localmaps);
if (want_trans && quant->mc_size == 256)
--quant->mc_size;
- if (has_common_palette(imgs+imgn, 1, quant, want_trans)) {
+ if (has_common_palette(imgs+imgn, 1, quant)) {
result = quant_paletted(quant, imgs[imgn]);
}
else {
io_glue_write_cb(GifFileType *gft, const GifByteType *data, int length) {
io_glue *ig = (io_glue *)gft->UserData;
- return ig->writecb(ig, data, length);
+ return i_io_write(ig, data, length);
}
result = i_writegif_low(quant, GifFile, imgs, count);
- ig->closecb(ig);
+ if (i_io_close(ig))
+ return 0;
return result;
}
return "Unexpected EOF - invalid file";
default:
+#ifdef IMAGER_SNPRINTF
+ snprintf(msg, sizeof(msg), "Unknown giflib error code %d", code);
+#else
sprintf(msg, "Unknown giflib error code %d", code);
+#endif
return msg;
}
}