aboutsummaryrefslogtreecommitdiff
path: root/Src/gif/GIFLoader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Src/gif/GIFLoader.cpp')
-rw-r--r--Src/gif/GIFLoader.cpp127
1 files changed, 127 insertions, 0 deletions
diff --git a/Src/gif/GIFLoader.cpp b/Src/gif/GIFLoader.cpp
new file mode 100644
index 00000000..5d2c858e
--- /dev/null
+++ b/Src/gif/GIFLoader.cpp
@@ -0,0 +1,127 @@
+#include "GIFLoader.h"
+#include "api__gif.h"
+#include <wchar.h>
+#include <bfc/platform/strcmp.h>
+
+extern "C" {
+#include "../giflib/gif_lib.h"
+};
+
+static bool StringEnds(const wchar_t *a, const wchar_t *b)
+{
+ size_t aLen = wcslen(a);
+ size_t bLen = wcslen(b);
+ if (aLen < bLen) return false; // too short
+ return !_wcsicmp(a + aLen - bLen, b);
+}
+
+int GIFLoader::isMine(const wchar_t *filename)
+{
+ return (filename && StringEnds(filename, L".GIF"));
+}
+
+int GIFLoader::getHeaderSize()
+{
+ return 3;
+}
+
+const wchar_t *GIFLoader::mimeType()
+{
+ return L"image/gif";
+}
+
+int GIFLoader::testData(const void *data, int datalen)
+{
+ if(datalen >= 3 && strncmp((const char*)data,"GIF",3)==0) return 1;
+ return 0;
+}
+
+typedef struct {
+ BYTE * data;
+ int len;
+} readStruct;
+
+extern "C" int myreader(GifFileType *gif, GifByteType *data, int len) {
+ readStruct* r = (readStruct*)gif->UserData;
+ int l = min(len,r->len);
+ if(l == 0) return 0;
+ memcpy(data,r->data,l);
+ r->len -= l;
+ r->data += l;
+ return l;
+}
+
+ARGB32 *GIFLoader::loadImage(const void *datain, int datalen, int *w, int *h, ifc_xmlreaderparams *params)
+{
+ readStruct read = {(BYTE*)datain,datalen};
+ int* l_error = NULL;
+ GifFileType * gif = DGifOpen(&read, myreader, l_error);
+ if(!gif) return 0;
+
+ if(!DGifSlurp(gif) || !gif->ImageCount) { DGifCloseFile(gif, l_error); return 0; }
+
+ ColorMapObject *map = gif->SColorMap;
+ if(!map) map = gif->SavedImages[0].ImageDesc.ColorMap;
+ if(!map) { DGifCloseFile(gif, l_error); return 0; }
+ int iw = gif->SavedImages[0].ImageDesc.Width;
+ int ih = gif->SavedImages[0].ImageDesc.Height;
+ if(w) *w = iw;
+ if(h) *h = ih;
+
+ ARGB32 * data = (ARGB32 *)WASABI_API_MEMMGR->sysMalloc(iw * ih * sizeof(ARGB32));
+ ARGB32 * p = data;
+ ARGB32 * end = data + (iw * ih);
+
+ GifPixelType *line = gif->SavedImages[0].RasterBits;
+
+
+ if(gif->SavedImages[0].ImageDesc.Interlace)
+ {
+ // The way Interlaced image should be read - offsets and jumps...
+ const int InterlacedOffset[] = { 0, 4, 2, 1 };
+ const int InterlacedJumps[] = { 8, 8, 4, 2 };
+
+ for(int i = 0; i < 4; i++)
+ {
+ for(int j = InterlacedOffset[i]; j < ih; j += InterlacedJumps[i])
+ {
+ p = &data[j*iw];
+ for(int k = 0; k<iw; k++)
+ {
+ int px = *(line++);
+ if(px < map->ColorCount && (px != gif->SBackGroundColor || px == 0)) {
+ GifColorType& color = map->Colors[px];
+ *(p++) = 0xff000000 | color.Blue | (color.Green << 8) | (color.Red << 16);
+ } else
+ *(p++) = 0;
+ }
+ }
+ }
+ }
+ else
+ {
+ while(p < end) {
+ int px = *(line++);
+ if(px < map->ColorCount && (px != gif->SBackGroundColor || px == 0)) {
+ GifColorType& color = map->Colors[px];
+ *(p++) = 0xff000000 | color.Blue | (color.Green << 8) | (color.Red << 16);
+ } else
+ *(p++) = 0;
+ }
+ }
+
+ DGifCloseFile(gif, l_error);
+ return data;
+}
+
+#define CBCLASS GIFLoader
+START_DISPATCH;
+ CB(ISMINE, isMine);
+ CB(MIMETYPE, mimeType);
+ CB(TESTDATA, testData);
+ CB(GETHEADERSIZE, getHeaderSize);
+ CB(GETDIMENSIONS, getDimensions);
+ CB(LOADIMAGE, loadImage);
+ CB(LOADIMAGEDATA, loadImageData);
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file