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
00023 GifFileType* gif = DGifOpen(file, InputFunc);
00024 if (!gif) {
00025 COR_LOG("DGifOpen failed");
00026 return 0;
00027 }
00028
00029
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
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
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
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
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
00092
00093
00094 for (int row = 0; row < height; row += 8) {
00095 memcpy(out + width * row, in, width);
00096 in += width;
00097 }
00098
00099
00100 for (int row = 4; row < height; row += 8) {
00101 memcpy(out + width * row, in, width);
00102 in += width;
00103 }
00104
00105
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 memcpy(out, in, width * height);
00118 }
00119
00120 DGifCloseFile(gif);
00121 return new SimpleImage(width, height, PF_I8, image.release(),
00122 (byte*)palette.release(), 256, PF_R8G8B8A8);
00123 }
00124
00125 }