static void GIFReadImageData(struct GIFImage *image, FILE *stream) { int minCodeSize; unsigned char **rows; unsigned int width, height, interlaced; unsigned char *colors; unsigned int numColors; unsigned int xpos, ypos; int pass, val; GIF_TRACE(("Reading Image Data\n")); /* Initialize the compression routines. */ GIF_FGETC(minCodeSize, stream); if (minCodeSize >= LZW_BITS_MAX) /* this should be in fact <= 8 */ GIFError("GIF/LZW error: invalid LZW code size"); if (LZWReadByte(LZW_TRUE, minCodeSize, stream) < 0) GIFError("Error reading GIF image"); /* Ignore the picture if it is "uninteresting". */ rows = image->Rows; if (rows == NULL) { #if 0 while (LZWReadByte(LZW_FALSE, minCodeSize, stream) >= 0) { } #else /* This is faster, but possible LZW errors may go undetected. */ GIFSkipDataBlocks(stream); #endif return; } width = image->Width; height = image->Height; interlaced = image->InterlaceFlag; GIFGetColorTable(&colors, &numColors, image); xpos = ypos = 0; pass = 0; while ((val = LZWReadByte(LZW_FALSE, minCodeSize, stream)) >= 0) { if ((unsigned int)val >= numColors) { GIFWarning("Pixel value out of range"); val = numColors - 1; } rows[ypos][xpos] = (unsigned char)val; if (++xpos == width) { xpos = 0; if (interlaced) { switch (pass) { case 0: case 1: ypos += 8; break; case 2: ypos += 4; break; case 3: ypos += 2; break; } if (ypos >= height) { switch (++pass) { case 1: ypos = 4; break; case 2: ypos = 2; break; case 3: ypos = 1; break; default: goto fini; } } } else ++ypos; } if (ypos >= height) break; } fini: /* Ignore the trailing garbage. */ while (LZWReadByte(LZW_FALSE, minCodeSize, stream) >= 0) { } }
int /* PRIVATE */ pngx_read_gif(png_structp png_ptr, png_infop info_ptr, FILE *stream) { /* GIF-specific data */ struct GIFScreen screen; struct GIFImage image; struct GIFExtension ext; struct GIFGraphicCtlExt graphicExt; int code; unsigned char *colorTable; unsigned int numColors; unsigned int transparent; unsigned int numImages; /* PNG-specific data */ png_uint_32 width, height; png_bytepp row_pointers; /* Set up the custom error handling. */ pngx_err_ptr = png_ptr; GIFError = pngx_gif_error; GIFWarning = pngx_gif_warning; /* Read the GIF screen. */ GIFReadScreen(&screen, stream); width = screen.Width; height = screen.Height; /* Set the PNG image type. */ png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); /* Allocate memory. */ row_pointers = pngx_malloc_rows(png_ptr, info_ptr, (int)screen.Background); /* Complete the initialization of the GIF reader. */ GIFInitImage(&image, &screen, row_pointers); GIFInitExtension(&ext, &screen, NULL, 0); transparent = (unsigned int)(-1); numImages = 0; /* Iterate over the GIF file. */ for ( ; ; ) { code = GIFReadNextBlock(&image, &ext, stream); if (code == GIF_IMAGE) /* ',' */ { if (image.Rows != NULL) { /* Complete the PNG info. */ if (image.InterlaceFlag) pngx_set_interlace_type(png_ptr, info_ptr, PNG_INTERLACE_ADAM7); colorTable = GIFGetColorTable(&image, &numColors); pngx_set_GIF_palette(png_ptr, info_ptr, colorTable, numColors); if (transparent < 256) pngx_set_GIF_transparent(png_ptr, info_ptr, transparent); /* Inform the GIF routines not to read the upcoming images. */ image.Rows = NULL; } ++numImages; } else if (code == GIF_EXTENSION && ext.Label == GIF_GRAPHICCTL) /* '!' */ { GIFGetGraphicCtl(&ext, &graphicExt); if (image.Rows != NULL && graphicExt.TransparentFlag) if (transparent >= 256) transparent = graphicExt.Transparent; } else if (code == GIF_TERMINATOR) /* ';' */ break; } /* Deallocate the GIF reader's extension buffer. * Use free() in conjunction with the reader's realloc(). */ if (ext.Buffer != NULL) free(ext.Buffer); /* FIXME: * Deallocate ext.Buffer on error, to prevent memory leaks. */ if (image.Rows != NULL) png_error(png_ptr, "No image in GIF file"); return numImages; }