corona
1.0.2
|
00001 #include <stdio.h> 00002 #include <string.h> 00003 extern "C" { 00004 #include <gif_lib.h> 00005 } 00006 #include "Debug.h" 00007 #include "Open.h" 00008 #include "SimpleImage.h" 00009 #include "Utility.h" 00010 00011 00012 namespace corona { 00013 00014 int InputFunc(GifFileType* gif, GifByteType* bytes, int size) { 00015 File* file = (File*)gif->UserData; 00016 return file->read(bytes, size); 00017 } 00018 00019 Image* OpenGIF(File* file) { 00020 COR_GUARD("OpenGIF"); 00021 00022 // open GIF file 00023 GifFileType* gif = DGifOpen(file, InputFunc); 00024 if (!gif) { 00025 COR_LOG("DGifOpen failed"); 00026 return 0; 00027 } 00028 00029 // read GIF image 00030 if (DGifSlurp(gif) != GIF_OK) { 00031 COR_LOG("DGifSlurp failed"); 00032 DGifCloseFile(gif); 00033 return 0; 00034 } 00035 ColorMapObject* cmap = gif->SColorMap; 00036 00037 // validate attributes 00038 if (cmap == 0 || 00039 gif->ImageCount < 1 || 00040 cmap->ColorCount != (1 << cmap->BitsPerPixel)) 00041 { 00042 COR_IF_DEBUG { 00043 char str[1024]; 00044 sprintf(str, "incorrect gif attributes:\n"); 00045 sprintf(str + strlen(str), " ImageCount: %d\n", gif->ImageCount); 00046 if (cmap) { 00047 sprintf(str + strlen(str), " BitsPerPixel: %d\n", cmap->BitsPerPixel); 00048 sprintf(str + strlen(str), " ColorCount: %d\n", cmap->ColorCount); 00049 } 00050 COR_LOG(str); 00051 } 00052 00053 DGifCloseFile(gif); 00054 return 0; 00055 } 00056 00057 // use the first frame of the animation 00058 SavedImage* gif_image = gif->SavedImages + 0; 00059 00060 const int width = gif->SWidth; 00061 const int height = gif->SHeight; 00062 auto_array<byte> image(new byte[width * height]); 00063 auto_array<RGBA> palette(new RGBA[256]); 00064 00065 // look for the transparent color extension 00066 int transparent = -1; 00067 for (int i = 0; i < gif_image->ExtensionBlockCount; ++i) { 00068 ExtensionBlock* eb = gif_image->ExtensionBlocks + i; 00069 if (eb->Function == 0xF9 && 00070 eb->ByteCount == 4) { 00071 bool has_transparency = ((eb->Bytes[0] & 1) == 1); 00072 if (has_transparency) { 00073 transparent = eb->Bytes[3]; 00074 } 00075 } 00076 } 00077 00078 // copy over the palette 00079 memset(palette, 0, 256 * 4); 00080 for (int i = 0; i < cmap->ColorCount; ++i) { 00081 palette[i].red = cmap->Colors[i].Red; 00082 palette[i].green = cmap->Colors[i].Green; 00083 palette[i].blue = cmap->Colors[i].Blue; 00084 palette[i].alpha = (transparent == i ? 0 : 255); 00085 } 00086 00087 byte* in = (byte*)gif_image->RasterBits; 00088 byte* out = image; 00089 if (gif->Image.Interlace) { 00090 00091 // deinterlace 00092 00093 // group 1 - every 8th row, starting with row 0 00094 for (int row = 0; row < height; row += 8) { 00095 memcpy(out + width * row, in, width); 00096 in += width; 00097 } 00098 00099 // group 2 - every 8th row, starting with row 4 00100 for (int row = 4; row < height; row += 8) { 00101 memcpy(out + width * row, in, width); 00102 in += width; 00103 } 00104 00105 // group 3 - every 4th row, starting with row 2 00106 for (int row = 2; row < height; row += 4) { 00107 memcpy(out + width * row, in, width); 00108 in += width; 00109 } 00110 00111 for (int row = 1; row < height; row += 2) { 00112 memcpy(out + width * row, in, width); 00113 in += width; 00114 } 00115 00116 } else { 00117 if (transparent == -1) { 00118 memset(out, 0, width * height); 00119 } else { 00120 memset(out, transparent, width * height); 00121 } 00122 const int x = gif_image->ImageDesc.Left; 00123 const int y = gif_image->ImageDesc.Top; 00124 const int w = gif_image->ImageDesc.Width; 00125 const int h = gif_image->ImageDesc.Height; 00126 00127 for (int iy = 0; iy < h; iy++) { 00128 memcpy(out + (width * (y+iy)) + x, in + (w*iy), w); 00129 } 00130 } 00131 00132 DGifCloseFile(gif); 00133 return new SimpleImage(width, height, PF_I8, image.release(), 00134 (byte*)palette.release(), 256, PF_R8G8B8A8); 00135 } 00136 00137 }