1 /* gif2dbl: convert a gif file to a DBL file using a RGB palette
2  * for non-transparent gifs and RGBA palette for transparent ones.
3  *
4  * author: Raffaele Sena (raff@aromatic.org)
5  *
6  * (derived from gif2mask.c)
7  */
8 
9 /* $Id$ */
10 
11 #include <stdlib.h>
12 #include <stdio.h>
13 #include <string.h>
14 #include <math.h>
15 
16 #include <ming_config.h>
17 #include <gif_lib.h>
18 #include <zlib.h>
19 
20 #include "libming.h"
21 
error(char * msg,int errorCode)22 void error(char *msg, int errorCode)
23 {
24   printf("%s:\n\n", msg);
25   PrintGifError(errorCode);
26   exit(-1);
27 }
28 
29 /**
30  * Get transparency color from graphic extension block
31  *
32  * Return: transparency color or -1
33  */
getTransparentColor(GifFileType * file)34 int getTransparentColor(GifFileType * file)
35 {
36   int i,returnvalue=-1;
37   ExtensionBlock * ext = file->SavedImages[0].ExtensionBlocks;
38 
39   for (i=0; i < file->SavedImages[0].ExtensionBlockCount; i++, ext++) {
40 
41     if (ext->Function == GRAPHICS_EXT_FUNC_CODE) {
42       if (ext->Bytes[0] & 1){   /* there is a transparent color */
43         if (!ext->Bytes[3]) returnvalue=255; // exception
44         else returnvalue=ext->Bytes[3]&0xff;
45       }
46     }
47 
48   }
49 
50   return returnvalue;
51 }
52 
readGif(char * fileName,int * length,int * bytesPerColor)53 unsigned char *readGif(char *fileName, int *length, int *bytesPerColor)
54 {
55   GifFileType *file;
56   ColorMapObject *colorMap;
57   unsigned char *bits;
58   unsigned char *data;
59   unsigned char *p;
60   int i, nColors, size, alpha, bgColor, alignedWidth;
61 
62   int errorCode = 0;
63 
64 #if GIFLIB_MAJOR < 5
65   if((file = DGifOpenFileName(fileName)) == NULL)
66     error("Error opening file", errorCode);
67 #else
68   if((file = DGifOpenFileName(fileName, &errorCode)) == NULL)
69     error("Error opening file", errorCode);
70 #endif
71 
72   if(DGifSlurp(file) != GIF_OK)
73 #if GIFLIB_MAJOR < 5
74     error("Error slurping file", 0);
75 #else
76     error("Error slurping file", file->Error);
77 #endif
78 
79   /* data should now be available */
80 
81 	/* Local colormap has precedence over Global colormap */
82   colorMap = file->Image.ColorMap ? file->Image.ColorMap : file->SColorMap;
83 
84   nColors = colorMap->ColorCount;
85   alpha = getTransparentColor(file);
86 
87 	/* bgColor is the background color to fill the bitmap with
88 	 * if an image is smaller than screen coordinates
89 	 */
90   if (file->SColorMap)			/* There is a GlobalColorMap */
91     bgColor = file->SBackGroundColor;   /* The BackGroundColor is meaningful */
92   else
93   if (alpha >= 0)			/* There is a transparency color */
94     bgColor = alpha;			/* set the bgColor to tranparent */
95   else
96     bgColor = 0;			/* Don't know what to do here.
97 					 * If this doesn't work, we could
98 					 * create a new color and set the
99 					 * alpha-channel to transparent
100 					 * (unless we are using all the 256
101 					 * colors, in which case either we
102 					 * give up, or move to 16-bits palette
103 					 */
104 
105   *bytesPerColor = 3;
106   if (alpha >= 0) *bytesPerColor += 1;	/* if tranparent color, use the alpha
107 					 * channel (RGBA instead of RGB)
108 					 */
109 
110 	/* Ah! The Flash specs says scanlines must be DWORD ALIGNED!
111 	 * (but image width is the correct number of pixels)
112 	 */
113   alignedWidth = (file->SWidth + 3) & ~3;
114 
115   /* size = size-of-header + size-of-colormap + size-of-bitmap */
116   size = 6 + (nColors * *bytesPerColor) + (alignedWidth * file->SHeight);
117   data = malloc(size);
118 
119   p = data;
120   *p++ = 3; 				/* 8-bit image data */
121   *p++ = (file->SWidth >> 0) & 0xFF;	/* image width */
122   *p++ = (file->SWidth >> 8) & 0xFF;
123   *p++ = (file->SHeight >> 0) & 0xFF;	/* image height */
124   *p++ = (file->SHeight >> 8) & 0xFF;
125   *p++ = nColors-1;			/* size(colorMap) - 1 */
126 
127 	/* create ColorMap */
128   for(i=0; i<nColors; ++i)
129   {
130     GifColorType c = colorMap->Colors[i];
131 
132     if (*bytesPerColor == 3) {	/* RGB */
133       *p++ = c.Red;
134       *p++ = c.Green;
135       *p++ = c.Blue;
136     } else {			/* RGBA */
137 #if 1				/* You would think that an alpha value of 0
138 				 * would mean fully transparent, but Flash
139 				 * player doesn't seem to think so.
140 				 * So, we just set the transparency color
141 				 * as 0,0,0,0
142 				 */
143     if (i != alpha) {
144       *p++ = c.Red;
145       *p++ = c.Green;
146       *p++ = c.Blue;
147       *p++ = 255;	/* Fully opaque */
148     } else {
149       *p++ = 0;		/* red */
150       *p++ = 0;		/* green */
151       *p++ = 0;		/* blue */
152       *p++ = 0;		/* Fully transparent */
153     }
154 #else
155       *p++ = c.Red;
156       *p++ = c.Green;
157       *p++ = c.Blue;
158       *p++ = (i != alpha) ? 255 : 0; /* set alpha to 0 for transparent color */
159 #endif
160     }
161   }
162 
163   bits = file->SavedImages[0].RasterBits;
164 
165   if (alignedWidth == file->SWidth
166 	&& file->Image.Width == file->SWidth
167 	&& file->Image.Height == file->SHeight) {
168 
169 	/* we are all nicely aligned and don't need to move the bitmap around.
170 	 * Just copy the bits into the output buffer.
171 	 */
172     memcpy(p, bits, file->SWidth * file->SHeight);
173 
174   } else {
175 	/* here we need to pad the scanline or to move the bitmap around
176 	 * (if the image is not at 0,0 in the logical screen)
177 	 */
178     int screenWidth = file->SWidth;
179     int screenHeight = file->SHeight;
180 
181     int imageTop = file->Image.Top;
182     int imageBottom = file->Image.Top + file->Image.Height;
183     int imageLeft = file->Image.Left;
184     int imageWidth = file->Image.Width;
185 
186     for (i=0; i < screenHeight; i++, p += alignedWidth) {
187 
188 	/* the image is smaller than the logical "screen":
189 	 * Fill the reminder with the background color.
190 	 */
191       if (imageWidth != screenWidth)
192         memset(p, bgColor, screenWidth);
193 
194 	/* finally, copy scanline
195 	 */
196       if (i >= imageTop && i < imageBottom) {
197 	memcpy(p + imageLeft, bits, imageWidth);
198 	bits += imageWidth;
199       }
200     }
201   }
202 
203 	/* Done! */
204 #if GIFLIB_MAJOR >= 5 && GIFLIB_MINOR >= 1
205   if (DGifCloseFile(file, &errorCode) != GIF_OK)
206     error("Error closing file", errorCode);
207 #else
208   DGifCloseFile(file);
209 #endif
210 
211   *length = size;
212   return data;
213 }
214 
usage()215 void usage()
216 {
217   printf("gif2dbl - convert a gif image to DefineBitLossless2 bitmap\n");
218   printf("\nusage: gif2dbl <file.gif>\n");
219 
220   exit(0);
221 }
222 
main(int argc,char * argv[])223 int main(int argc, char *argv[])
224 {
225   int len, size, bytesPerColor;
226   unsigned long outsize;
227   char *outfile;
228   unsigned char *data, *outdata;
229   FILE *dbl;
230 
231   if(argc <= 1)
232     usage();
233 
234   len = strlen(argv[1]);
235 
236   if(strcmp(argv[1]+len-4, ".gif") != 0)
237     usage();
238 
239   outfile = strdup(argv[1]);
240 
241   outfile[len-3] = 'd';
242   outfile[len-2] = 'b';
243   outfile[len-1] = 'l';
244 
245   data = readGif(argv[1], &size, &bytesPerColor);
246 
247   outdata = malloc(outsize = (int)floor(size*1.01+12));
248 
249   /* zlib-compress the gif data */
250   compress2(outdata, &outsize, data+6, size-6, 9);
251 
252   /* dump to outfile */
253   dbl = fopen(outfile, "wb");
254 
255   if (dbl)
256   {
257 	/* DBL header */
258     fputc('D', dbl);
259     fputc('B', dbl);
260     fputc('l', dbl);
261     fputc(bytesPerColor==3 ? 1 : 2, dbl);	/* 1: RGB - 2: RGBA */
262 
263 	/* fill size */
264     fputc(((outsize+6) >> 24) & 0xFF, dbl);
265     fputc(((outsize+6) >> 16) & 0xFF, dbl);
266     fputc(((outsize+6) >> 8) & 0xFF, dbl);
267     fputc(((outsize+6) >> 0) & 0xFF, dbl);
268 
269 	/* write header */
270     if(fwrite(data, sizeof(char), 6, dbl) != 6)
271     {
272       perror(outfile);
273       exit(1);
274     }
275 	/* write compressed data */
276     if(fwrite(outdata, sizeof(char), outsize, dbl) != outsize)
277     {
278       perror(outfile);
279       exit(-1);
280     }
281 
282 	/* and we are done! */
283     fclose(dbl);
284   }
285   else {
286     perror(outfile);
287     exit(-1);
288   }
289 
290   exit(0);
291 }
292