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