]> git.imager.perl.org - imager.git/commitdiff
[rt #79029] add support for giflib 5.0
authorTony Cook <tony@develop-help.com>
Thu, 23 Aug 2012 12:59:13 +0000 (22:59 +1000)
committerTony Cook <tony@develop-help.com>
Tue, 11 Sep 2012 10:11:24 +0000 (20:11 +1000)
Changes
GIF/Changes
GIF/Makefile.PL
GIF/imgif.c
GIF/t/t10gif.t

diff --git a/Changes b/Changes
index 5aae5f090b541a7d52670eded77ddddd16893643..86f61e118a72c313ce525b510cf241abd17f4f88 100644 (file)
--- a/Changes
+++ b/Changes
@@ -15,6 +15,9 @@ Imager release history.  Older releases can be found in Changes.old
    - improve error reporting
    - provide better control of the level of anti-aliasing
 
    - improve error reporting
    - provide better control of the level of anti-aliasing
 
+ - support for giflib 5.0.
+   https://rt.cpan.org/Ticket/Display.html?id=79029
+
 Imager 0.92 - 14 Aug 2012
 ===========
 
 Imager 0.92 - 14 Aug 2012
 ===========
 
index a854d3e12b2e8dfd725073c26ac9f91a4ba83b2d..dfc8de7ef66b76b69c3c72c3fe826c5f07434981 100644 (file)
@@ -1,4 +1,10 @@
-Imager-File-GIF 0.84
+Imager-File-GIF 0.85
+====================
+
+ - add giflib 5.0 support.
+   https://rt.cpan.org/Ticket/Display.html?id=79029
+
+Imager-File-GIF 0.84 - released with Imager 0.92_01
 ====================
 
  - giflib 4.2 eliminates the GIF_LIB_VERSION macro, handle that
 ====================
 
  - giflib 4.2 eliminates the GIF_LIB_VERSION macro, handle that
index 0640ba326df8a3908e587b354deed92a0bbc62aa..378dd435eef6db190b527b30062bd5b207321dff 100644 (file)
@@ -74,7 +74,7 @@ my %probe =
    inccheck => sub { -e File::Spec->catfile($_[0], "gif_lib.h") },
    libbase => "gif",
    testcode => _gif_test_code(),
    inccheck => sub { -e File::Spec->catfile($_[0], "gif_lib.h") },
    libbase => "gif",
    testcode => _gif_test_code(),
-   testcodeheaders => [ "gif_lib.h", "stdio.h" ],
+   testcodeheaders => [ "stddef.h", "gif_lib.h", "stdio.h" ],
    incpath => \@incpaths,
    libpath => \@libpaths,
   );
    incpath => \@incpaths,
    libpath => \@libpaths,
   );
@@ -119,8 +119,13 @@ int ver_min;
 #else
 int ver_maj = GIFLIB_MAJOR;
 int ver_min = GIFLIB_MINOR;
 #else
 int ver_maj = GIFLIB_MAJOR;
 int ver_min = GIFLIB_MINOR;
+int error;
 #endif
 #endif
+#if defined(GIFLIB_MAJOR) && GIFLIB_MAJOR >= 5
+gf=DGifOpenFileName("testimg/expected.gif", &error);
+#else
 gf=DGifOpenFileName("testimg/expected.gif");
 gf=DGifOpenFileName("testimg/expected.gif");
+#endif
 if (!gf) {
   fprintf(stderr, "GIF: Cannot open testimg/expected.gif\n");
   return 1;
 if (!gf) {
   fprintf(stderr, "GIF: Cannot open testimg/expected.gif\n");
   return 1;
@@ -129,9 +134,11 @@ if (gf->SWidth != 16 || gf->SHeight != 16) {
   fprintf(stderr, "GIF: bad screen description (%d x %d)\n", gf->SWidth, gf->SHeight);
   return 1;
 }
   fprintf(stderr, "GIF: bad screen description (%d x %d)\n", gf->SWidth, gf->SHeight);
   return 1;
 }
-/* crashes in older versions of giflib */
+#if !defined(GIFLIB_MAJOR) || GIFLIB_MAJOR < 5
+/* crashes in older versions of giflib, not used in giflib 5 */
 EGifSetGifVersion("89a");
 EGifSetGifVersion("87a");
 EGifSetGifVersion("89a");
 EGifSetGifVersion("87a");
+#endif
 
 #ifdef GIF_LIB_VERSION
 /* skip the " Version " */
 
 #ifdef GIF_LIB_VERSION
 /* skip the " Version " */
index 3302d4837b1ddfea4e0768683f3a049c8fe73895..506e10054ae1fbf6744d82a1e9e8d7d8f0c3817a 100644 (file)
@@ -59,21 +59,69 @@ functionality with giflib3.
 =cut
 */
 
 =cut
 */
 
+#if defined(GIFLIB_MAJOR) && GIFLIB_MAJOR >= 5
+#define myDGifOpen(userPtr, readFunc, Error) DGifOpen((userPtr), (readFunc), (Error))
+#define myEGifOpen(userPtr, readFunc, Error) EGifOpen((userPtr), (readFunc), (Error))
+#define myGifError(gif) ((gif)->Error)
+#define MakeMapObject GifMakeMapObject
+#define FreeMapObject GifFreeMapObject
+
+#define gif_mutex_lock()
+#define gif_mutex_unlock()
+#else
+static GifFileType *
+myDGifOpen(void *userPtr, InputFunc readFunc, int *error) {
+  GifFileType *result = DGifOpen(userPtr, readFunc);
+  if (!result)
+    *error = GifLastError();
+
+  return result;
+}
+static GifFileType *
+myEGifOpen(void *userPtr, OutputFunc outputFunc, int *error) {
+  GifFileType *result = EGifOpen(userPtr, outputFunc);
+  if (!result)
+    *error = GifLastError();
+
+  return result;
+}
+#define myGifError(gif) GifLastError()
+
+#define gif_mutex_lock() i_mutex_lock(mutex)
+#define gif_mutex_unlock() i_mutex_unlock(mutex)
+#define NEED_MUTEX
+#endif
+
 static char const *gif_error_msg(int code);
 static char const *gif_error_msg(int code);
-static void gif_push_error(void);
+static void gif_push_error(int code);
 
 /* Make some variables global, so we could access them faster: */
 
 
 /* Make some variables global, so we could access them faster: */
 
-static int
+static const int
   InterlacedOffset[] = { 0, 4, 2, 1 }, /* The way Interlaced image should. */
   InterlacedJumps[] = { 8, 8, 4, 2 };    /* be read - offsets and jumps... */
 
 
   InterlacedOffset[] = { 0, 4, 2, 1 }, /* The way Interlaced image should. */
   InterlacedJumps[] = { 8, 8, 4, 2 };    /* be read - offsets and jumps... */
 
 
+#ifdef NEED_MUTEX
 static i_mutex_t mutex;
 static i_mutex_t mutex;
+#endif
+
+/*
+=item i_init_gif()
+
+Initialize GIF support.
+
+For versions of giflib that require it, create a mutex to avoid
+reentrancy.
+
+=cut
+*/
 
 void
 i_init_gif(void) {
 
 void
 i_init_gif(void) {
+#ifdef NEED_MUTEX
   mutex = i_mutex_new();
   mutex = i_mutex_new();
+#endif
 }
 
 static
 }
 
 static
@@ -144,7 +192,7 @@ i_readgif_low(GifFileType *GifFile, int **colour_table, int *colours) {
   GifByteType *Extension;
   
   GifRowType GifRow;
   GifByteType *Extension;
   
   GifRowType GifRow;
-  static GifColorType *ColorMapEntry;
+  GifColorType *ColorMapEntry;
   i_color col;
 
   mm_log((1,"i_readgif_low(GifFile %p, colour_table %p, colours %p)\n", GifFile, colour_table, colours));
   i_color col;
 
   mm_log((1,"i_readgif_low(GifFile %p, colour_table %p, colours %p)\n", GifFile, colour_table, colours));
@@ -193,7 +241,7 @@ i_readgif_low(GifFileType *GifFile, int **colour_table, int *colours) {
   /* Scan the content of the GIF file and load the image(s) in: */
   do {
     if (DGifGetRecordType(GifFile, &RecordType) == GIF_ERROR) {
   /* Scan the content of the GIF file and load the image(s) in: */
   do {
     if (DGifGetRecordType(GifFile, &RecordType) == GIF_ERROR) {
-      gif_push_error();
+      gif_push_error(myGifError(GifFile));
       i_push_error(0, "Unable to get record type");
       if (colour_table && *colour_table) {
        myfree(*colour_table);
       i_push_error(0, "Unable to get record type");
       if (colour_table && *colour_table) {
        myfree(*colour_table);
@@ -208,7 +256,7 @@ i_readgif_low(GifFileType *GifFile, int **colour_table, int *colours) {
     switch (RecordType) {
     case IMAGE_DESC_RECORD_TYPE:
       if (DGifGetImageDesc(GifFile) == GIF_ERROR) {
     switch (RecordType) {
     case IMAGE_DESC_RECORD_TYPE:
       if (DGifGetImageDesc(GifFile) == GIF_ERROR) {
-       gif_push_error();
+       gif_push_error(myGifError(GifFile));
        i_push_error(0, "Unable to get image descriptor");
        if (colour_table && *colour_table) {
          myfree(*colour_table);
        i_push_error(0, "Unable to get image descriptor");
        if (colour_table && *colour_table) {
          myfree(*colour_table);
@@ -262,7 +310,7 @@ i_readgif_low(GifFileType *GifFile, int **colour_table, int *colours) {
        for (Count = i = 0; i < 4; i++) for (j = Row + InterlacedOffset[i]; j < Row + Height; j += InterlacedJumps[i]) {
          Count++;
          if (DGifGetLine(GifFile, GifRow, Width) == GIF_ERROR) {
        for (Count = i = 0; i < 4; i++) for (j = Row + InterlacedOffset[i]; j < Row + Height; j += InterlacedJumps[i]) {
          Count++;
          if (DGifGetLine(GifFile, GifRow, Width) == GIF_ERROR) {
-           gif_push_error();
+           gif_push_error(myGifError(GifFile));
            i_push_error(0, "Reading GIF line");
            if (colour_table && *colour_table) {
              myfree(*colour_table);
            i_push_error(0, "Reading GIF line");
            if (colour_table && *colour_table) {
              myfree(*colour_table);
@@ -287,7 +335,7 @@ i_readgif_low(GifFileType *GifFile, int **colour_table, int *colours) {
       else {
        for (i = 0; i < Height; i++) {
          if (DGifGetLine(GifFile, GifRow, Width) == GIF_ERROR) {
       else {
        for (i = 0; i < Height; i++) {
          if (DGifGetLine(GifFile, GifRow, Width) == GIF_ERROR) {
-           gif_push_error();
+           gif_push_error(myGifError(GifFile));
            i_push_error(0, "Reading GIF line");
            if (colour_table && *colour_table) {
              myfree(*colour_table);
            i_push_error(0, "Reading GIF line");
            if (colour_table && *colour_table) {
              myfree(*colour_table);
@@ -313,7 +361,7 @@ i_readgif_low(GifFileType *GifFile, int **colour_table, int *colours) {
     case EXTENSION_RECORD_TYPE:
       /* Skip any extension blocks in file: */
       if (DGifGetExtension(GifFile, &ExtCode, &Extension) == GIF_ERROR) {
     case EXTENSION_RECORD_TYPE:
       /* Skip any extension blocks in file: */
       if (DGifGetExtension(GifFile, &ExtCode, &Extension) == GIF_ERROR) {
-       gif_push_error();
+       gif_push_error(myGifError(GifFile));
        i_push_error(0, "Reading extension record");
        if (colour_table && *colour_table) {
          myfree(*colour_table);
        i_push_error(0, "Reading extension record");
        if (colour_table && *colour_table) {
          myfree(*colour_table);
@@ -326,7 +374,7 @@ i_readgif_low(GifFileType *GifFile, int **colour_table, int *colours) {
       }
       while (Extension != NULL) {
        if (DGifGetExtensionNext(GifFile, &Extension) == GIF_ERROR) {
       }
       while (Extension != NULL) {
        if (DGifGetExtensionNext(GifFile, &Extension) == GIF_ERROR) {
-         gif_push_error();
+         gif_push_error(myGifError(GifFile));
          i_push_error(0, "reading next block of extension");
          if (colour_table && *colour_table) {
            myfree(*colour_table);
          i_push_error(0, "reading next block of extension");
          if (colour_table && *colour_table) {
            myfree(*colour_table);
@@ -349,7 +397,7 @@ i_readgif_low(GifFileType *GifFile, int **colour_table, int *colours) {
   myfree(GifRow);
   
   if (DGifCloseFile(GifFile) == GIF_ERROR) {
   myfree(GifRow);
   
   if (DGifCloseFile(GifFile) == GIF_ERROR) {
-    gif_push_error();
+    gif_push_error(myGifError(GifFile));
     i_push_error(0, "Closing GIF file object");
     if (colour_table && *colour_table) {
       myfree(*colour_table);
     i_push_error(0, "Closing GIF file object");
     if (colour_table && *colour_table) {
       myfree(*colour_table);
@@ -369,7 +417,8 @@ i_readgif_low(GifFileType *GifFile, int **colour_table, int *colours) {
 Internal function called by i_readgif_multi_low() in error handling
 
 */
 Internal function called by i_readgif_multi_low() in error handling
 
 */
-static void free_images(i_img **imgs, int count) {
+static void
+free_images(i_img **imgs, int count) {
   int i;
   
   if (count) {
   int i;
   
   if (count) {
@@ -463,7 +512,8 @@ standard.
 =cut
 */
 
 =cut
 */
 
-i_img **i_readgif_multi_low(GifFileType *GifFile, int *count, int page) {
+i_img **
+i_readgif_multi_low(GifFileType *GifFile, int *count, int page) {
   i_img *img;
   int i, j, Size, Width, Height, ExtCode, Count;
   int ImageNum = 0, BackGround = 0, ColorMapSize = 0;
   i_img *img;
   int i, j, Size, Width, Height, ExtCode, Count;
   int ImageNum = 0, BackGround = 0, ColorMapSize = 0;
@@ -503,7 +553,7 @@ i_img **i_readgif_multi_low(GifFileType *GifFile, int *count, int page) {
   /* Scan the content of the GIF file and load the image(s) in: */
   do {
     if (DGifGetRecordType(GifFile, &RecordType) == GIF_ERROR) {
   /* Scan the content of the GIF file and load the image(s) in: */
   do {
     if (DGifGetRecordType(GifFile, &RecordType) == GIF_ERROR) {
-      gif_push_error();
+      gif_push_error(myGifError(GifFile));
       i_push_error(0, "Unable to get record type");
       free_images(results, *count);
       DGifCloseFile(GifFile);
       i_push_error(0, "Unable to get record type");
       free_images(results, *count);
       DGifCloseFile(GifFile);
@@ -516,7 +566,7 @@ i_img **i_readgif_multi_low(GifFileType *GifFile, int *count, int page) {
     switch (RecordType) {
     case IMAGE_DESC_RECORD_TYPE:
       if (DGifGetImageDesc(GifFile) == GIF_ERROR) {
     switch (RecordType) {
     case IMAGE_DESC_RECORD_TYPE:
       if (DGifGetImageDesc(GifFile) == GIF_ERROR) {
-       gif_push_error();
+       gif_push_error(myGifError(GifFile));
        i_push_error(0, "Unable to get image descriptor");
         free_images(results, *count);
        DGifCloseFile(GifFile);
        i_push_error(0, "Unable to get image descriptor");
         free_images(results, *count);
        DGifCloseFile(GifFile);
@@ -649,7 +699,7 @@ i_img **i_readgif_multi_low(GifFileType *GifFile, int *count, int page) {
                 j += InterlacedJumps[i]) {
              Count++;
              if (DGifGetLine(GifFile, GifRow, Width) == GIF_ERROR) {
                 j += InterlacedJumps[i]) {
              Count++;
              if (DGifGetLine(GifFile, GifRow, Width) == GIF_ERROR) {
-               gif_push_error();
+               gif_push_error(myGifError(GifFile));
                i_push_error(0, "Reading GIF line");
                free_images(results, *count);
                DGifCloseFile(GifFile);
                i_push_error(0, "Reading GIF line");
                free_images(results, *count);
                DGifCloseFile(GifFile);
@@ -678,7 +728,7 @@ i_img **i_readgif_multi_low(GifFileType *GifFile, int *count, int page) {
        else {
          for (i = 0; i < Height; i++) {
            if (DGifGetLine(GifFile, GifRow, Width) == GIF_ERROR) {
        else {
          for (i = 0; i < Height; i++) {
            if (DGifGetLine(GifFile, GifRow, Width) == GIF_ERROR) {
-             gif_push_error();
+             gif_push_error(myGifError(GifFile));
              i_push_error(0, "Reading GIF line");
              free_images(results, *count);
              DGifCloseFile(GifFile);
              i_push_error(0, "Reading GIF line");
              free_images(results, *count);
              DGifCloseFile(GifFile);
@@ -719,7 +769,7 @@ i_img **i_readgif_multi_low(GifFileType *GifFile, int *count, int page) {
        /* giflib does't have an interface to skip the image data */
        for (i = 0; i < Height; i++) {
          if (DGifGetLine(GifFile, GifRow, Width) == GIF_ERROR) {
        /* giflib does't have an interface to skip the image data */
        for (i = 0; i < Height; i++) {
          if (DGifGetLine(GifFile, GifRow, Width) == GIF_ERROR) {
-           gif_push_error();
+           gif_push_error(myGifError(GifFile));
            i_push_error(0, "Reading GIF line");
            free_images(results, *count);
            myfree(GifRow);
            i_push_error(0, "Reading GIF line");
            free_images(results, *count);
            myfree(GifRow);
@@ -741,7 +791,7 @@ i_img **i_readgif_multi_low(GifFileType *GifFile, int *count, int page) {
     case EXTENSION_RECORD_TYPE:
       /* Skip any extension blocks in file: */
       if (DGifGetExtension(GifFile, &ExtCode, &Extension) == GIF_ERROR) {
     case EXTENSION_RECORD_TYPE:
       /* Skip any extension blocks in file: */
       if (DGifGetExtension(GifFile, &ExtCode, &Extension) == GIF_ERROR) {
-       gif_push_error();
+       gif_push_error(myGifError(GifFile));
        i_push_error(0, "Reading extension record");
         free_images(results, *count);
        myfree(GifRow);
        i_push_error(0, "Reading extension record");
         free_images(results, *count);
        myfree(GifRow);
@@ -766,7 +816,7 @@ i_img **i_readgif_multi_low(GifFileType *GifFile, int *count, int page) {
       if (ExtCode == 0xFF && *Extension == 11) {
         if (memcmp(Extension+1, "NETSCAPE2.0", 11) == 0) {
           if (DGifGetExtensionNext(GifFile, &Extension) == GIF_ERROR) {
       if (ExtCode == 0xFF && *Extension == 11) {
         if (memcmp(Extension+1, "NETSCAPE2.0", 11) == 0) {
           if (DGifGetExtensionNext(GifFile, &Extension) == GIF_ERROR) {
-            gif_push_error();
+            gif_push_error(myGifError(GifFile));
             i_push_error(0, "reading loop extension");
             free_images(results, *count);
            myfree(GifRow);
             i_push_error(0, "reading loop extension");
             free_images(results, *count);
            myfree(GifRow);
@@ -796,7 +846,7 @@ i_img **i_readgif_multi_low(GifFileType *GifFile, int *count, int page) {
       }
       while (Extension != NULL) {
        if (DGifGetExtensionNext(GifFile, &Extension) == GIF_ERROR) {
       }
       while (Extension != NULL) {
        if (DGifGetExtensionNext(GifFile, &Extension) == GIF_ERROR) {
-         gif_push_error();
+         gif_push_error(myGifError(GifFile));
          i_push_error(0, "reading next block of extension");
           free_images(results, *count);
          myfree(GifRow);
          i_push_error(0, "reading next block of extension");
           free_images(results, *count);
          myfree(GifRow);
@@ -825,7 +875,7 @@ i_img **i_readgif_multi_low(GifFileType *GifFile, int *count, int page) {
   myfree(GifRow);
   
   if (DGifCloseFile(GifFile) == GIF_ERROR) {
   myfree(GifRow);
   
   if (DGifCloseFile(GifFile) == GIF_ERROR) {
-    gif_push_error();
+    gif_push_error(myGifError(GifFile));
     i_push_error(0, "Closing GIF file object");
     free_images(results, *count);
     return NULL;
     i_push_error(0, "Closing GIF file object");
     free_images(results, *count);
     return NULL;
@@ -853,22 +903,23 @@ i_img **
 i_readgif_multi_wiol(io_glue *ig, int *count) {
   GifFileType *GifFile;
   i_img **result;
 i_readgif_multi_wiol(io_glue *ig, int *count) {
   GifFileType *GifFile;
   i_img **result;
+  int gif_error;
 
 
-  i_mutex_lock(mutex);
+  gif_mutex_lock();
 
   i_clear_error();
   
 
   i_clear_error();
   
-  if ((GifFile = DGifOpen((void *)ig, io_glue_read_cb )) == NULL) {
-    gif_push_error();
+  if ((GifFile = myDGifOpen((void *)ig, io_glue_read_cb, &gif_error )) == NULL) {
+    gif_push_error(gif_error);
     i_push_error(0, "Cannot create giflib callback object");
     mm_log((1,"i_readgif_multi_wiol: Unable to open callback datasource.\n"));
     i_push_error(0, "Cannot create giflib callback object");
     mm_log((1,"i_readgif_multi_wiol: Unable to open callback datasource.\n"));
-    i_mutex_unlock(mutex);
+    gif_mutex_unlock();
     return NULL;
   }
     
   result = i_readgif_multi_low(GifFile, count, -1);
 
     return NULL;
   }
     
   result = i_readgif_multi_low(GifFile, count, -1);
 
-  i_mutex_unlock(mutex);
+  gif_mutex_unlock();
 
   return result;
 }
 
   return result;
 }
@@ -884,22 +935,23 @@ i_img *
 i_readgif_wiol(io_glue *ig, int **color_table, int *colors) {
   GifFileType *GifFile;
   i_img *result;
 i_readgif_wiol(io_glue *ig, int **color_table, int *colors) {
   GifFileType *GifFile;
   i_img *result;
+  int gif_error;
 
 
-  i_mutex_lock(mutex);
+  gif_mutex_lock();
 
   i_clear_error();
 
 
   i_clear_error();
 
-  if ((GifFile = DGifOpen((void *)ig, io_glue_read_cb )) == NULL) {
-    gif_push_error();
+  if ((GifFile = myDGifOpen((void *)ig, io_glue_read_cb, &gif_error )) == NULL) {
+    gif_push_error(gif_error);
     i_push_error(0, "Cannot create giflib callback object");
     mm_log((1,"i_readgif_wiol: Unable to open callback datasource.\n"));
     i_push_error(0, "Cannot create giflib callback object");
     mm_log((1,"i_readgif_wiol: Unable to open callback datasource.\n"));
-    i_mutex_unlock(mutex);
+    gif_mutex_unlock();
     return NULL;
   }
     
   result = i_readgif_low(GifFile, color_table, colors);
 
     return NULL;
   }
     
   result = i_readgif_low(GifFile, color_table, colors);
 
-  i_mutex_unlock(mutex);
+  gif_mutex_unlock();
 
   return result;
 }
 
   return result;
 }
@@ -947,6 +999,7 @@ i_img *
 i_readgif_single_wiol(io_glue *ig, int page) {
   GifFileType *GifFile;
   i_img *result;
 i_readgif_single_wiol(io_glue *ig, int page) {
   GifFileType *GifFile;
   i_img *result;
+  int gif_error;
 
   i_clear_error();
   if (page < 0) {
 
   i_clear_error();
   if (page < 0) {
@@ -954,19 +1007,19 @@ i_readgif_single_wiol(io_glue *ig, int page) {
     return NULL;
   }
 
     return NULL;
   }
 
-  i_mutex_lock(mutex);
+  gif_mutex_lock();
 
 
-  if ((GifFile = DGifOpen((void *)ig, io_glue_read_cb )) == NULL) {
-    gif_push_error();
+  if ((GifFile = myDGifOpen((void *)ig, io_glue_read_cb, &gif_error )) == NULL) {
+    gif_push_error(gif_error);
     i_push_error(0, "Cannot create giflib callback object");
     mm_log((1,"i_readgif_wiol: Unable to open callback datasource.\n"));
     i_push_error(0, "Cannot create giflib callback object");
     mm_log((1,"i_readgif_wiol: Unable to open callback datasource.\n"));
-    i_mutex_unlock(mutex);
+    gif_mutex_unlock();
     return NULL;
   }
     
   result = i_readgif_single_low(GifFile, page);
 
     return NULL;
   }
     
   result = i_readgif_single_low(GifFile, page);
 
-  i_mutex_unlock(mutex);
+  gif_mutex_unlock();
 
   return result;
 }
 
   return result;
 }
@@ -988,7 +1041,7 @@ do_write(GifFileType *gf, int interlace, i_img *img, i_palidx *data) {
     for (i = 0; i < 4; ++i) {
       for (j = InterlacedOffset[i]; j < img->ysize; j += InterlacedJumps[i]) {
        if (EGifPutLine(gf, data+j*img->xsize, img->xsize) == GIF_ERROR) {
     for (i = 0; i < 4; ++i) {
       for (j = InterlacedOffset[i]; j < img->ysize; j += InterlacedJumps[i]) {
        if (EGifPutLine(gf, data+j*img->xsize, img->xsize) == GIF_ERROR) {
-         gif_push_error();
+         gif_push_error(myGifError(gf));
          i_push_error(0, "Could not save image data:");
          mm_log((1, "Error in EGifPutLine\n"));
          EGifCloseFile(gf);
          i_push_error(0, "Could not save image data:");
          mm_log((1, "Error in EGifPutLine\n"));
          EGifCloseFile(gf);
@@ -1001,7 +1054,7 @@ do_write(GifFileType *gf, int interlace, i_img *img, i_palidx *data) {
     int y;
     for (y = 0; y < img->ysize; ++y) {
       if (EGifPutLine(gf, data, img->xsize) == GIF_ERROR) {
     int y;
     for (y = 0; y < img->ysize; ++y) {
       if (EGifPutLine(gf, data, img->xsize) == GIF_ERROR) {
-       gif_push_error();
+       gif_push_error(myGifError(gf));
        i_push_error(0, "Could not save image data:");
        mm_log((1, "Error in EGifPutLine\n"));
        EGifCloseFile(gf);
        i_push_error(0, "Could not save image data:");
        mm_log((1, "Error in EGifPutLine\n"));
        EGifCloseFile(gf);
@@ -1023,7 +1076,9 @@ Returns non-zero on success.
 
 =cut
 */
 
 =cut
 */
-static int do_gce(GifFileType *gf, i_img *img, int want_trans, int trans_index)
+
+static int
+do_gce(GifFileType *gf, i_img *img, int want_trans, int trans_index)
 {
   unsigned char gce[4] = {0};
   int want_gce = 0;
 {
   unsigned char gce[4] = {0};
   int want_gce = 0;
@@ -1052,7 +1107,7 @@ static int do_gce(GifFileType *gf, i_img *img, int want_trans, int trans_index)
   }
   if (want_gce) {
     if (EGifPutExtension(gf, 0xF9, sizeof(gce), gce) == GIF_ERROR) {
   }
   if (want_gce) {
     if (EGifPutExtension(gf, 0xF9, sizeof(gce), gce) == GIF_ERROR) {
-      gif_push_error();
+      gif_push_error(myGifError(gf));
       i_push_error(0, "Could not save GCE");
     }
   }
       i_push_error(0, "Could not save GCE");
     }
   }
@@ -1066,7 +1121,9 @@ Write any comments in the image.
 
 =cut
 */
 
 =cut
 */
-static int do_comments(GifFileType *gf, i_img *img) {
+
+static int
+do_comments(GifFileType *gf, i_img *img) {
   int pos = -1;
 
   while (i_tags_find(&img->tags, "gif_comment", pos+1, &pos)) {
   int pos = -1;
 
   while (i_tags_find(&img->tags, "gif_comment", pos+1, &pos)) {
@@ -1104,7 +1161,9 @@ writing extension blocks so that they could only be written to files.
 
 =cut
 */
 
 =cut
 */
-static int do_ns_loop(GifFileType *gf, i_img *img)
+
+static int
+do_ns_loop(GifFileType *gf, i_img *img)
 {
   /* EGifPutExtension() doesn't appear to handle application 
      extension blocks in any way
 {
   /* EGifPutExtension() doesn't appear to handle application 
      extension blocks in any way
@@ -1121,19 +1180,33 @@ static int do_ns_loop(GifFileType *gf, i_img *img)
   if (i_tags_get_int(&img->tags, "gif_loop", 0, &loop_count)) {
     unsigned char nsle[12] = "NETSCAPE2.0";
     unsigned char subblock[3];
   if (i_tags_get_int(&img->tags, "gif_loop", 0, &loop_count)) {
     unsigned char nsle[12] = "NETSCAPE2.0";
     unsigned char subblock[3];
+
+    subblock[0] = 1;
+    subblock[1] = loop_count % 256;
+    subblock[2] = loop_count / 256;
+
+#if defined(GIFLIB_MAJOR) && GIFLIB_MAJOR >= 5
+    if (EGifPutExtensionLeader(gf, APPLICATION_EXT_FUNC_CODE) == GIF_ERROR
+       || EGifPutExtensionBlock(gf, 11, nsle) == GIF_ERROR
+       || EGifPutExtensionBlock(gf, 3, subblock) == GIF_ERROR
+       || EGifPutExtensionTrailer(gf) == GIF_ERROR) {
+      gif_push_error(myGifError(gf));
+      i_push_error(0, "writing loop extension");
+      return 0;
+    }
+       
+#else
     if (EGifPutExtensionFirst(gf, APPLICATION_EXT_FUNC_CODE, 11, nsle) == GIF_ERROR) {
     if (EGifPutExtensionFirst(gf, APPLICATION_EXT_FUNC_CODE, 11, nsle) == GIF_ERROR) {
-      gif_push_error();
+      gif_push_error(myGifError(gf));
       i_push_error(0, "writing loop extension");
       return 0;
     }
       i_push_error(0, "writing loop extension");
       return 0;
     }
-    subblock[0] = 1;
-    subblock[1] = loop_count % 256;
-    subblock[2] = loop_count / 256;
     if (EGifPutExtensionLast(gf, APPLICATION_EXT_FUNC_CODE, 3, subblock) == GIF_ERROR) {
     if (EGifPutExtensionLast(gf, APPLICATION_EXT_FUNC_CODE, 3, subblock) == GIF_ERROR) {
-      gif_push_error();
+      gif_push_error(myGifError(gf));
       i_push_error(0, "writing loop extension sub-block");
       return 0;
     }
       i_push_error(0, "writing loop extension sub-block");
       return 0;
     }
+#endif
   }
 
   return 1;
   }
 
   return 1;
@@ -1147,8 +1220,8 @@ Create a giflib color map object from an Imager color map.
 =cut
 */
 
 =cut
 */
 
-static ColorMapObject *make_gif_map(i_quantize *quant, i_img *img, 
-                                    int want_trans) {
+static ColorMapObject *
+make_gif_map(i_quantize *quant, i_img *img, int want_trans) {
   GifColorType colors[256];
   int i;
   int size = quant->mc_count;
   GifColorType colors[256];
   int i;
   int size = quant->mc_count;
@@ -1183,7 +1256,6 @@ static ColorMapObject *make_gif_map(i_quantize *quant, i_img *img,
   map = MakeMapObject(map_size, colors);
   mm_log((1, "XXX map is at %p and colors at %p\n", map, map->Colors));
   if (!map) {
   map = MakeMapObject(map_size, colors);
   mm_log((1, "XXX map is at %p and colors at %p\n", map, map->Colors));
   if (!map) {
-    gif_push_error();
     i_push_error(0, "Could not create color map object");
     return NULL;
   }
     i_push_error(0, "Could not create color map object");
     return NULL;
   }
@@ -1220,10 +1292,14 @@ If t/t105gif.t crashes here then run Makefile.PL with
 
 or install a less buggy giflib.
 
 
 or install a less buggy giflib.
 
+This code is completely unnecessary in giflib 5
+
 =cut
 */
 
 =cut
 */
 
-static void gif_set_version(i_quantize *quant, i_img **imgs, int count) {
+static void
+gif_set_version(i_quantize *quant, i_img **imgs, int count) {
+#if !defined(GIFLIB_MAJOR) || GIFLIB_MAJOR < 5
   int need_89a = 0;
   int temp;
   int i;
   int need_89a = 0;
   int temp;
   int i;
@@ -1254,6 +1330,7 @@ static void gif_set_version(i_quantize *quant, i_img **imgs, int count) {
      EGifSetGifVersion("89a");
   else
      EGifSetGifVersion("87a");
      EGifSetGifVersion("89a");
   else
      EGifSetGifVersion("87a");
+#endif
 }
 
 static int 
 }
 
 static int 
@@ -1536,7 +1613,7 @@ i_writegif_low(i_quantize *quant, GifFileType *gf, i_img **imgs, int count) {
     myfree(localmaps);
     myfree(glob_imgs);
     quant->mc_colors = orig_colors;
     myfree(localmaps);
     myfree(glob_imgs);
     quant->mc_colors = orig_colors;
-    gif_push_error();
+    gif_push_error(myGifError(gf));
     i_push_error(0, "Could not save screen descriptor");
     FreeMapObject(map);
     myfree(result);
     i_push_error(0, "Could not save screen descriptor");
     FreeMapObject(map);
     myfree(result);
@@ -1644,7 +1721,7 @@ i_writegif_low(i_quantize *quant, GifFileType *gf, i_img **imgs, int count) {
     myfree(localmaps);
     myfree(glob_imgs);
     quant->mc_colors = orig_colors;
     myfree(localmaps);
     myfree(glob_imgs);
     quant->mc_colors = orig_colors;
-    gif_push_error();
+    gif_push_error(myGifError(gf));
     i_push_error(0, "Could not save image descriptor");
     EGifCloseFile(gf);
     mm_log((1, "Error in EGifPutImageDesc."));
     i_push_error(0, "Could not save image descriptor");
     EGifCloseFile(gf);
     mm_log((1, "Error in EGifPutImageDesc."));
@@ -1761,7 +1838,7 @@ i_writegif_low(i_quantize *quant, GifFileType *gf, i_img **imgs, int count) {
       myfree(localmaps);
       myfree(glob_imgs);
       quant->mc_colors = orig_colors;
       myfree(localmaps);
       myfree(glob_imgs);
       quant->mc_colors = orig_colors;
-      gif_push_error();
+      gif_push_error(myGifError(gf));
       i_push_error(0, "Could not save image descriptor");
       myfree(result);
       if (map)
       i_push_error(0, "Could not save image descriptor");
       myfree(result);
       if (map)
@@ -1789,7 +1866,7 @@ i_writegif_low(i_quantize *quant, GifFileType *gf, i_img **imgs, int count) {
     myfree(glob_colors);
     myfree(localmaps);
     myfree(glob_imgs);
     myfree(glob_colors);
     myfree(localmaps);
     myfree(glob_imgs);
-    gif_push_error();
+    gif_push_error(myGifError(gf));
     i_push_error(0, "Could not close GIF file");
     mm_log((1, "Error in EGifCloseFile\n"));
     return 0;
     i_push_error(0, "Could not close GIF file");
     mm_log((1, "Error in EGifCloseFile\n"));
     return 0;
@@ -1826,24 +1903,25 @@ i_writegif_wiol(io_glue *ig, i_quantize *quant, i_img **imgs,
                 int count) {
   GifFileType *GifFile;
   int result;
                 int count) {
   GifFileType *GifFile;
   int result;
+  int gif_error;
 
 
-  i_mutex_lock(mutex);
+  gif_mutex_lock();
 
   i_clear_error();
 
   gif_set_version(quant, imgs, count);
   
 
   i_clear_error();
 
   gif_set_version(quant, imgs, count);
   
-  if ((GifFile = EGifOpen((void *)ig, io_glue_write_cb )) == NULL) {
-    gif_push_error();
+  if ((GifFile = myEGifOpen((void *)ig, io_glue_write_cb, &gif_error )) == NULL) {
+    gif_push_error(gif_error);
     i_push_error(0, "Cannot create giflib callback object");
     mm_log((1,"i_writegif_wiol: Unable to open callback datasource.\n"));
     i_push_error(0, "Cannot create giflib callback object");
     mm_log((1,"i_writegif_wiol: Unable to open callback datasource.\n"));
-    i_mutex_unlock(mutex);
+    gif_mutex_unlock();
     return 0;
   }
   
   result = i_writegif_low(quant, GifFile, imgs, count);
   
     return 0;
   }
   
   result = i_writegif_low(quant, GifFile, imgs, count);
   
-  i_mutex_unlock(mutex);
+  gif_mutex_unlock();
 
   if (i_io_close(ig))
     return 0;
 
   if (i_io_close(ig))
     return 0;
@@ -1857,15 +1935,16 @@ i_writegif_wiol(io_glue *ig, i_quantize *quant, i_img **imgs,
 Grabs the most recent giflib error code from GifLastError() and 
 returns a string that describes that error.
 
 Grabs the most recent giflib error code from GifLastError() and 
 returns a string that describes that error.
 
-The returned pointer points to a static buffer, either from a literal
-C string or a static buffer.
+Returns NULL for unknown error codes.
 
 =cut
 */
 
 
 =cut
 */
 
-static char const *gif_error_msg(int code) {
-  static char msg[80];
-
+static char const *
+gif_error_msg(int code) {
+#if defined(GIFLIB_MAJOR) && GIFLIB_MAJOR >= 5
+  return GifErrorString(code);
+#else
   switch (code) {
   case E_GIF_ERR_OPEN_FAILED: /* should not see this */
     return "Failed to open given file";
   switch (code) {
   case E_GIF_ERR_OPEN_FAILED: /* should not see this */
     return "Failed to open given file";
@@ -1937,17 +2016,13 @@ static char const *gif_error_msg(int code) {
     return "Unexpected EOF - invalid file";
 
   default:
     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;
+    return NULL;
   }
   }
+#endif
 }
 
 /*
 }
 
 /*
-=item gif_push_error()
+=item gif_push_error(code)
 
 Utility function that takes the current GIF error code, converts it to
 an error message and pushes it on the error stack.
 
 Utility function that takes the current GIF error code, converts it to
 an error message and pushes it on the error stack.
@@ -1955,27 +2030,16 @@ an error message and pushes it on the error stack.
 =cut
 */
 
 =cut
 */
 
-static void gif_push_error(void) {
-  int code = GifLastError(); /* clears saved error */
-
-  i_push_error(code, gif_error_msg(code));
+static void
+gif_push_error(int code) {
+  const char *msg = gif_error_msg(code);
+  if (msg)
+    i_push_error(code, msg);
+  else
+    i_push_errorf(code, "Unknown GIF error %d", code);
 }
 
 /*
 }
 
 /*
-=head1 BUGS
-
-The Netscape loop extension isn't implemented.  Giflib's extension
-writing code doesn't seem to support writing named extensions in this 
-form.
-
-A bug in giflib is tickled by the i_writegif_callback().  This isn't a
-problem on ungiflib, but causes a SEGV on giflib.  A patch is provided
-in t/t10formats.t
-
-The GIF file tag (GIF87a vs GIF89a) currently isn't set.  Using the
-supplied interface in giflib 4.1.0 causes a SEGV in
-EGifSetGifVersion().  See L<gif_set_version> for an explanation.
-
 =head1 AUTHOR
 
 Arnar M. Hrafnkelsson, addi@umich.edu
 =head1 AUTHOR
 
 Arnar M. Hrafnkelsson, addi@umich.edu
index c926b0c6bcfe787f21b7a10e36dc6ba0d23b7642..b766f81e290f03fd99f857016935c6ed38de05dc 100644 (file)
@@ -404,7 +404,8 @@ read_failure('testimg/nocmap.gif');
      ($io, { make_colors=>'addi',
             translate=>'closest',
             transp=>'ordered',
      ($io, { make_colors=>'addi',
             translate=>'closest',
             transp=>'ordered',
-          }, @imgs), "write from paletted");
+          }, @imgs), "write from paletted")
+    or diag(Imager->_error_as_msg());
   close FH;
   
   # make sure nothing bad happened
   close FH;
   
   # make sure nothing bad happened