1 /*****************************************************************************
3 gif2rgb - convert GIF to 24-bit RGB pixel triples or vice-versa
5 *****************************************************************************/
7 /***************************************************************************
9 Toshio Kuratomi had written this in a comment about the rgb2gif code:
11 Besides fixing bugs, what's really needed is for someone to work out how to
12 calculate a colormap for writing GIFs from rgb sources. Right now, an rgb
13 source that has only two colors (b/w) is being converted into an 8 bit GIF....
14 Which is horrendously wasteful without compression.
16 I (ESR) took this off the main to-do list in 2012 because I don't think
17 the GIFLIB project actually needs to be in the converters-and-tools business.
18 Plenty of hackers do that; our job is to supply stable library capability
19 with our utilities mainly interesting as test tools.
21 ***************************************************************************/
37 #define PROGRAM_NAME "gif2rgb"
39 __attribute__((__section__(".tizen.build-id")))
45 __DATE__ ", " __TIME__ "\n"
46 "(C) Copyright 1989 Gershon Elber.\n";
50 " v%- c%-#Colors!d s%-Width|Height!d!d 1%- o%-OutFileName!s h%- GifFile!*s";
52 static void LoadRGB(char *FileName,
54 GifByteType **RedBuffer,
55 GifByteType **GreenBuffer,
56 GifByteType **BlueBuffer,
57 int Width, int Height);
58 static void SaveGif(GifByteType *OutputBuffer,
59 int Width, int Height,
60 int ExpColorMapSize, ColorMapObject *OutputColorMap);
62 /******************************************************************************
63 Load RGB file into internal frame buffer.
64 ******************************************************************************/
65 static void LoadRGB(char *FileName,
67 GifByteType **RedBuffer,
68 GifByteType **GreenBuffer,
69 GifByteType **BlueBuffer,
70 int Width, int Height)
74 GifByteType *RedP, *GreenP, *BlueP;
77 Size = ((long) Width) * Height * sizeof(GifByteType);
79 if ((*RedBuffer = (GifByteType *) malloc((unsigned int) Size)) == NULL ||
80 (*GreenBuffer = (GifByteType *) malloc((unsigned int) Size)) == NULL ||
81 (*BlueBuffer = (GifByteType *) malloc((unsigned int) Size)) == NULL)
82 GIF_EXIT("Failed to allocate memory required, aborted.");
85 GreenP = *GreenBuffer;
88 if (FileName != NULL) {
90 if ((rgbfp[0] = fopen(FileName, "rb")) == NULL)
91 GIF_EXIT("Can't open input file name.");
94 static char *Postfixes[] = { ".R", ".G", ".B" };
97 for (i = 0; i < 3; i++) {
98 strncpy(OneFileName, FileName, sizeof(OneFileName)-1);
99 strncat(OneFileName, Postfixes[i],
100 sizeof(OneFileName) - 1 - strlen(OneFileName));
102 if ((rgbfp[i] = fopen(OneFileName, "rb")) == NULL)
103 GIF_EXIT("Can't open input file name.");
111 _setmode(0, O_BINARY);
117 GifQprintf("\n%s: RGB image: ", PROGRAM_NAME);
120 GifByteType *Buffer, *BufferP;
122 if ((Buffer = (GifByteType *) malloc(Width * 3)) == NULL)
123 GIF_EXIT("Failed to allocate memory required, aborted.");
125 for (i = 0; i < Height; i++) {
127 GifQprintf("\b\b\b\b%-4d", i);
128 if (fread(Buffer, Width * 3, 1, rgbfp[0]) != 1)
129 GIF_EXIT("Input file(s) terminated prematurly.");
130 for (j = 0, BufferP = Buffer; j < Width; j++) {
131 *RedP++ = *BufferP++;
132 *GreenP++ = *BufferP++;
133 *BlueP++ = *BufferP++;
137 free((char *) Buffer);
141 for (i = 0; i < Height; i++) {
142 GifQprintf("\b\b\b\b%-4d", i);
143 if (fread(RedP, Width, 1, rgbfp[0]) != 1 ||
144 fread(GreenP, Width, 1, rgbfp[1]) != 1 ||
145 fread(BlueP, Width, 1, rgbfp[2]) != 1)
146 GIF_EXIT("Input file(s) terminated prematurly.");
158 /******************************************************************************
159 Save the GIF resulting image.
160 ******************************************************************************/
161 static void SaveGif(GifByteType *OutputBuffer,
162 int Width, int Height,
163 int ExpColorMapSize, ColorMapObject *OutputColorMap)
166 GifFileType *GifFile;
167 GifByteType *Ptr = OutputBuffer;
169 /* Open stdout for the output file: */
170 if ((GifFile = EGifOpenFileHandle(1, &Error)) == NULL) {
171 PrintGifError(Error);
175 if (EGifPutScreenDesc(GifFile,
176 Width, Height, ExpColorMapSize, 0,
177 OutputColorMap) == GIF_ERROR ||
178 EGifPutImageDesc(GifFile,
179 0, 0, Width, Height, false, NULL) == GIF_ERROR) {
180 PrintGifError(Error);
184 GifQprintf("\n%s: Image 1 at (%d, %d) [%dx%d]: ",
185 PROGRAM_NAME, GifFile->Image.Left, GifFile->Image.Top,
186 GifFile->Image.Width, GifFile->Image.Height);
188 for (i = 0; i < Height; i++) {
189 if (EGifPutLine(GifFile, Ptr, Width) == GIF_ERROR)
191 GifQprintf("\b\b\b\b%-4d", Height - i - 1);
196 if (EGifCloseFile(GifFile, &Error) == GIF_ERROR) {
197 PrintGifError(Error);
202 /******************************************************************************
203 Close output file (if open), and exit.
204 ******************************************************************************/
205 static void RGB2GIF(bool OneFileFlag, int NumFiles, char *FileName,
206 int ExpNumOfColors, int Width, int Height)
210 GifByteType *RedBuffer = NULL, *GreenBuffer = NULL, *BlueBuffer = NULL,
211 *OutputBuffer = NULL;
212 ColorMapObject *OutputColorMap = NULL;
214 ColorMapSize = 1 << ExpNumOfColors;
217 LoadRGB(FileName, OneFileFlag,
218 &RedBuffer, &GreenBuffer, &BlueBuffer, Width, Height);
221 LoadRGB(NULL, OneFileFlag,
222 &RedBuffer, &GreenBuffer, &BlueBuffer, Width, Height);
225 if ((OutputColorMap = GifMakeMapObject(ColorMapSize, NULL)) == NULL ||
226 (OutputBuffer = (GifByteType *) malloc(Width * Height *
227 sizeof(GifByteType))) == NULL)
228 GIF_EXIT("Failed to allocate memory required, aborted.");
230 if (GifQuantizeBuffer(Width, Height, &ColorMapSize,
231 RedBuffer, GreenBuffer, BlueBuffer,
232 OutputBuffer, OutputColorMap->Colors) == GIF_ERROR)
234 free((char *) RedBuffer);
235 free((char *) GreenBuffer);
236 free((char *) BlueBuffer);
238 SaveGif(OutputBuffer, Width, Height, ExpNumOfColors, OutputColorMap);
241 /******************************************************************************
242 The real screen dumping routine.
243 ******************************************************************************/
244 static void DumpScreen2RGB(char *FileName, int OneFileFlag,
245 ColorMapObject *ColorMap,
246 GifRowType *ScreenBuffer,
247 int ScreenWidth, int ScreenHeight)
251 GifColorType *ColorMapEntry;
254 if (FileName != NULL) {
256 if ((rgbfp[0] = fopen(FileName, "wb")) == NULL)
257 GIF_EXIT("Can't open input file name.");
259 static char *Postfixes[] = { ".R", ".G", ".B" };
260 char OneFileName[80];
262 for (i = 0; i < 3; i++) {
263 strncpy(OneFileName, FileName, sizeof(OneFileName)-1);
264 strncat(OneFileName, Postfixes[i],
265 sizeof(OneFileName) - 1 - strlen(OneFileName));
267 if ((rgbfp[i] = fopen(OneFileName, "wb")) == NULL) {
268 GIF_EXIT("Can't open input file name.");
276 _setmode(1, O_BINARY);
282 if (ColorMap == NULL) {
283 fprintf(stderr, "Color map pointer is NULL.\n");
288 unsigned char *Buffer, *BufferP;
290 if ((Buffer = (unsigned char *) malloc(ScreenWidth * 3)) == NULL)
291 GIF_EXIT("Failed to allocate memory required, aborted.");
292 for (i = 0; i < ScreenHeight; i++) {
293 GifRow = ScreenBuffer[i];
294 GifQprintf("\b\b\b\b%-4d", ScreenHeight - i);
295 for (j = 0, BufferP = Buffer; j < ScreenWidth; j++) {
296 ColorMapEntry = &ColorMap->Colors[GifRow[j]];
297 *BufferP++ = ColorMapEntry->Red;
298 *BufferP++ = ColorMapEntry->Green;
299 *BufferP++ = ColorMapEntry->Blue;
301 if (fwrite(Buffer, ScreenWidth * 3, 1, rgbfp[0]) != 1)
302 GIF_EXIT("Write to file(s) failed.");
305 free((char *) Buffer);
308 unsigned char *Buffers[3];
310 if ((Buffers[0] = (unsigned char *) malloc(ScreenWidth)) == NULL ||
311 (Buffers[1] = (unsigned char *) malloc(ScreenWidth)) == NULL ||
312 (Buffers[2] = (unsigned char *) malloc(ScreenWidth)) == NULL)
313 GIF_EXIT("Failed to allocate memory required, aborted.");
315 for (i = 0; i < ScreenHeight; i++) {
316 GifRow = ScreenBuffer[i];
317 GifQprintf("\b\b\b\b%-4d", ScreenHeight - i);
318 for (j = 0; j < ScreenWidth; j++) {
319 ColorMapEntry = &ColorMap->Colors[GifRow[j]];
320 Buffers[0][j] = ColorMapEntry->Red;
321 Buffers[1][j] = ColorMapEntry->Green;
322 Buffers[2][j] = ColorMapEntry->Blue;
324 if (fwrite(Buffers[0], ScreenWidth, 1, rgbfp[0]) != 1 ||
325 fwrite(Buffers[1], ScreenWidth, 1, rgbfp[1]) != 1 ||
326 fwrite(Buffers[2], ScreenWidth, 1, rgbfp[2]) != 1)
327 GIF_EXIT("Write to file(s) failed.");
330 free((char *) Buffers[0]);
331 free((char *) Buffers[1]);
332 free((char *) Buffers[2]);
339 static void GIF2RGB(int NumFiles, char *FileName,
343 int i, j, Size, Row, Col, Width, Height, ExtCode, Count;
344 GifRecordType RecordType;
345 GifByteType *Extension;
346 GifRowType *ScreenBuffer;
347 GifFileType *GifFile;
349 InterlacedOffset[] = { 0, 4, 2, 1 }, /* The way Interlaced image should. */
350 InterlacedJumps[] = { 8, 8, 4, 2 }; /* be read - offsets and jumps... */
352 ColorMapObject *ColorMap;
357 if ((GifFile = DGifOpenFileName(FileName, &Error)) == NULL) {
358 PrintGifError(Error);
364 /* Use stdin instead: */
365 if ((GifFile = DGifOpenFileHandle(0, &Error)) == NULL) {
366 PrintGifError(Error);
371 if (GifFile->SHeight == 0 || GifFile->SWidth == 0) {
372 fprintf(stderr, "Image of width or height 0\n");
377 * Allocate the screen as vector of column of rows. Note this
378 * screen is device independent - it's the screen defined by the
379 * GIF file parameters.
381 if ((ScreenBuffer = (GifRowType *)
382 malloc(GifFile->SHeight * sizeof(GifRowType))) == NULL)
383 GIF_EXIT("Failed to allocate memory required, aborted.");
385 Size = GifFile->SWidth * sizeof(GifPixelType);/* Size in bytes one row.*/
386 if ((ScreenBuffer[0] = (GifRowType) malloc(Size)) == NULL) /* First row. */
387 GIF_EXIT("Failed to allocate memory required, aborted.");
389 for (i = 0; i < GifFile->SWidth; i++) /* Set its color to BackGround. */
390 ScreenBuffer[0][i] = GifFile->SBackGroundColor;
391 for (i = 1; i < GifFile->SHeight; i++) {
392 /* Allocate the other rows, and set their color to background too: */
393 if ((ScreenBuffer[i] = (GifRowType) malloc(Size)) == NULL)
394 GIF_EXIT("Failed to allocate memory required, aborted.");
396 memcpy(ScreenBuffer[i], ScreenBuffer[0], Size);
399 /* Scan the content of the GIF file and load the image(s) in: */
401 if (DGifGetRecordType(GifFile, &RecordType) == GIF_ERROR) {
402 PrintGifError(GifFile->Error);
405 switch (RecordType) {
406 case IMAGE_DESC_RECORD_TYPE:
407 if (DGifGetImageDesc(GifFile) == GIF_ERROR) {
408 PrintGifError(GifFile->Error);
411 Row = GifFile->Image.Top; /* Image Position relative to Screen. */
412 Col = GifFile->Image.Left;
413 Width = GifFile->Image.Width;
414 Height = GifFile->Image.Height;
415 GifQprintf("\n%s: Image %d at (%d, %d) [%dx%d]: ",
416 PROGRAM_NAME, ++ImageNum, Col, Row, Width, Height);
417 if (GifFile->Image.Left + GifFile->Image.Width > GifFile->SWidth ||
418 GifFile->Image.Top + GifFile->Image.Height > GifFile->SHeight) {
419 fprintf(stderr, "Image %d is not confined to screen dimension, aborted.\n",ImageNum);
422 if (GifFile->Image.Interlace) {
423 /* Need to perform 4 passes on the images: */
424 for (Count = i = 0; i < 4; i++)
425 for (j = Row + InterlacedOffset[i]; j < Row + Height;
426 j += InterlacedJumps[i]) {
427 GifQprintf("\b\b\b\b%-4d", Count++);
428 if (DGifGetLine(GifFile, &ScreenBuffer[j][Col],
429 Width) == GIF_ERROR) {
430 PrintGifError(GifFile->Error);
436 for (i = 0; i < Height; i++) {
437 GifQprintf("\b\b\b\b%-4d", i);
438 if (DGifGetLine(GifFile, &ScreenBuffer[Row++][Col],
439 Width) == GIF_ERROR) {
440 PrintGifError(GifFile->Error);
446 case EXTENSION_RECORD_TYPE:
447 /* Skip any extension blocks in file: */
448 if (DGifGetExtension(GifFile, &ExtCode, &Extension) == GIF_ERROR) {
449 PrintGifError(GifFile->Error);
452 while (Extension != NULL) {
453 if (DGifGetExtensionNext(GifFile, &Extension) == GIF_ERROR) {
454 PrintGifError(GifFile->Error);
459 case TERMINATE_RECORD_TYPE:
461 default: /* Should be trapped by DGifGetRecordType. */
464 } while (RecordType != TERMINATE_RECORD_TYPE);
466 /* Lets dump it - set the global variables required and do it: */
467 ColorMap = (GifFile->Image.ColorMap
468 ? GifFile->Image.ColorMap
469 : GifFile->SColorMap);
470 if (ColorMap == NULL) {
471 fprintf(stderr, "Gif Image does not have a colormap\n");
475 /* check that the background color isn't garbage (SF bug #87) */
476 if (GifFile->SBackGroundColor < 0 || GifFile->SBackGroundColor >= ColorMap->ColorCount) {
477 fprintf(stderr, "Background color out of range for colormap\n");
481 DumpScreen2RGB(OutFileName, OneFileFlag,
484 GifFile->SWidth, GifFile->SHeight);
486 (void)free(ScreenBuffer);
488 if (DGifCloseFile(GifFile, &Error) == GIF_ERROR) {
489 PrintGifError(Error);
495 /******************************************************************************
496 * Interpret the command line and scan the given GIF file.
497 ******************************************************************************/
498 int main(int argc, char **argv)
500 bool Error, OutFileFlag = false, ColorFlag = false, SizeFlag = false;
501 int NumFiles, Width = 0, Height = 0, ExpNumOfColors = 8;
508 if ((Error = GAGetArgs(argc, argv, CtrlStr, &GifNoisyPrint,
509 &ColorFlag, &ExpNumOfColors, &SizeFlag, &Width, &Height,
510 &OneFileFlag, &OutFileFlag, &OutFileName,
511 &HelpFlag, &NumFiles, &FileName)) != false ||
512 (NumFiles > 1 && !HelpFlag)) {
514 GAPrintErrMsg(Error);
515 else if (NumFiles > 1)
516 GIF_MESSAGE("Error in command line parsing - one input file please.");
517 GAPrintHowTo(CtrlStr);
522 (void)fprintf(stderr, VersionStr, GIFLIB_MAJOR, GIFLIB_MINOR);
523 GAPrintHowTo(CtrlStr);
526 if (!OutFileFlag) OutFileName = NULL;
528 if (SizeFlag && Width > 0 && Height > 0)
529 RGB2GIF(OneFileFlag, NumFiles, *FileName,
530 ExpNumOfColors, Width, Height);
532 GIF2RGB(NumFiles, *FileName, OneFileFlag, OutFileName);