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 /* cppcheck-suppress uninitstring */
100 strncat(OneFileName, Postfixes[i],
101 sizeof(OneFileName) - 1 - strlen(OneFileName));
103 if ((rgbfp[i] = fopen(OneFileName, "rb")) == NULL)
104 GIF_EXIT("Can't open input file name.");
112 _setmode(0, O_BINARY);
118 GifQprintf("\n%s: RGB image: ", PROGRAM_NAME);
121 GifByteType *Buffer, *BufferP;
123 if ((Buffer = (GifByteType *) malloc(Width * 3)) == NULL)
124 GIF_EXIT("Failed to allocate memory required, aborted.");
126 for (i = 0; i < Height; i++) {
128 GifQprintf("\b\b\b\b%-4d", i);
129 if (fread(Buffer, Width * 3, 1, rgbfp[0]) != 1)
130 GIF_EXIT("Input file(s) terminated prematurly.");
131 for (j = 0, BufferP = Buffer; j < Width; j++) {
132 *RedP++ = *BufferP++;
133 *GreenP++ = *BufferP++;
134 *BlueP++ = *BufferP++;
138 free((char *) Buffer);
142 for (i = 0; i < Height; i++) {
143 GifQprintf("\b\b\b\b%-4d", i);
144 if (fread(RedP, Width, 1, rgbfp[0]) != 1 ||
145 fread(GreenP, Width, 1, rgbfp[1]) != 1 ||
146 fread(BlueP, Width, 1, rgbfp[2]) != 1)
147 GIF_EXIT("Input file(s) terminated prematurly.");
154 // cppcheck-suppress useClosedFile
156 // cppcheck-suppress useClosedFile
161 /******************************************************************************
162 Save the GIF resulting image.
163 ******************************************************************************/
164 static void SaveGif(GifByteType *OutputBuffer,
165 int Width, int Height,
166 int ExpColorMapSize, ColorMapObject *OutputColorMap)
169 GifFileType *GifFile;
170 GifByteType *Ptr = OutputBuffer;
172 /* Open stdout for the output file: */
173 if ((GifFile = EGifOpenFileHandle(1, &Error)) == NULL) {
174 PrintGifError(Error);
178 if (EGifPutScreenDesc(GifFile,
179 Width, Height, ExpColorMapSize, 0,
180 OutputColorMap) == GIF_ERROR ||
181 EGifPutImageDesc(GifFile,
182 0, 0, Width, Height, false, NULL) ==
184 PrintGifError(Error);
185 if (GifFile != NULL) {
186 EGifCloseFile(GifFile, NULL);
190 GifQprintf("\n%s: Image 1 at (%d, %d) [%dx%d]: ",
191 PROGRAM_NAME, GifFile->Image.Left, GifFile->Image.Top,
192 GifFile->Image.Width, GifFile->Image.Height);
194 for (i = 0; i < Height; i++) {
195 if (EGifPutLine(GifFile, Ptr, Width) == GIF_ERROR)
197 if (GifFile != NULL) {
198 EGifCloseFile(GifFile, NULL);
202 GifQprintf("\b\b\b\b%-4d", Height - i - 1);
207 if (EGifCloseFile(GifFile, &Error) == GIF_ERROR)
208 PrintGifError(Error);
209 if (GifFile != NULL) {
210 EGifCloseFile(GifFile, NULL);
215 /******************************************************************************
216 Close output file (if open), and exit.
217 ******************************************************************************/
218 static void RGB2GIF(bool OneFileFlag, int NumFiles, char *FileName,
219 int ExpNumOfColors, int Width, int Height)
223 GifByteType *RedBuffer = NULL, *GreenBuffer = NULL, *BlueBuffer = NULL,
224 *OutputBuffer = NULL;
225 ColorMapObject *OutputColorMap = NULL;
227 ColorMapSize = 1 << ExpNumOfColors;
230 LoadRGB(FileName, OneFileFlag,
231 &RedBuffer, &GreenBuffer, &BlueBuffer, Width, Height);
234 LoadRGB(NULL, OneFileFlag,
235 &RedBuffer, &GreenBuffer, &BlueBuffer, Width, Height);
238 if ((OutputColorMap = GifMakeMapObject(ColorMapSize, NULL)) == NULL ||
239 (OutputBuffer = (GifByteType *) malloc(Width * Height *
240 sizeof(GifByteType))) == NULL)
241 GIF_EXIT("Failed to allocate memory required, aborted.");
243 if (GifQuantizeBuffer(Width, Height, &ColorMapSize,
244 RedBuffer, GreenBuffer, BlueBuffer,
245 OutputBuffer, OutputColorMap->Colors) == GIF_ERROR)
247 free((char *) RedBuffer);
248 free((char *) GreenBuffer);
249 free((char *) BlueBuffer);
251 SaveGif(OutputBuffer, Width, Height, ExpNumOfColors, OutputColorMap);
254 /******************************************************************************
255 The real screen dumping routine.
256 ******************************************************************************/
257 static void DumpScreen2RGB(char *FileName, int OneFileFlag,
258 ColorMapObject *ColorMap,
259 GifRowType *ScreenBuffer,
260 int ScreenWidth, int ScreenHeight)
264 GifColorType *ColorMapEntry;
267 if (FileName != NULL) {
269 if ((rgbfp[0] = fopen(FileName, "wb")) == NULL)
270 GIF_EXIT("Can't open input file name.");
272 static char *Postfixes[] = { ".R", ".G", ".B" };
273 char OneFileName[80];
275 for (i = 0; i < 3; i++) {
276 strncpy(OneFileName, FileName, sizeof(OneFileName)-1);
277 /* cppcheck-suppress uninitstring */
278 strncat(OneFileName, Postfixes[i],
279 sizeof(OneFileName) - 1 - strlen(OneFileName));
281 if ((rgbfp[i] = fopen(OneFileName, "wb")) == NULL) {
282 GIF_EXIT("Can't open input file name.");
290 _setmode(1, O_BINARY);
297 unsigned char *Buffer, *BufferP;
299 if ((Buffer = (unsigned char *) malloc(ScreenWidth * 3)) == NULL)
300 GIF_EXIT("Failed to allocate memory required, aborted.");
301 for (i = 0; i < ScreenHeight; i++) {
302 GifRow = ScreenBuffer[i];
303 GifQprintf("\b\b\b\b%-4d", ScreenHeight - i);
304 for (j = 0, BufferP = Buffer; j < ScreenWidth; j++) {
305 ColorMapEntry = &ColorMap->Colors[GifRow[j]];
306 *BufferP++ = ColorMapEntry->Red;
307 *BufferP++ = ColorMapEntry->Green;
308 *BufferP++ = ColorMapEntry->Blue;
310 if (fwrite(Buffer, ScreenWidth * 3, 1, rgbfp[0]) != 1)
311 GIF_EXIT("Write to file(s) failed.");
314 free((char *) Buffer);
317 unsigned char *Buffers[3];
319 if ((Buffers[0] = (unsigned char *) malloc(ScreenWidth)) == NULL ||
320 (Buffers[1] = (unsigned char *) malloc(ScreenWidth)) == NULL ||
321 (Buffers[2] = (unsigned char *) malloc(ScreenWidth)) == NULL)
322 GIF_EXIT("Failed to allocate memory required, aborted.");
324 for (i = 0; i < ScreenHeight; i++) {
325 GifRow = ScreenBuffer[i];
326 GifQprintf("\b\b\b\b%-4d", ScreenHeight - i);
327 for (j = 0; j < ScreenWidth; j++) {
328 ColorMapEntry = &ColorMap->Colors[GifRow[j]];
329 Buffers[0][j] = ColorMapEntry->Red;
330 Buffers[1][j] = ColorMapEntry->Green;
331 Buffers[2][j] = ColorMapEntry->Blue;
333 if (fwrite(Buffers[0], ScreenWidth, 1, rgbfp[0]) != 1 ||
334 fwrite(Buffers[1], ScreenWidth, 1, rgbfp[1]) != 1 ||
335 fwrite(Buffers[2], ScreenWidth, 1, rgbfp[2]) != 1)
336 GIF_EXIT("Write to file(s) failed.");
339 free((char *) Buffers[0]);
340 free((char *) Buffers[1]);
341 free((char *) Buffers[2]);
343 // cppcheck-suppress useClosedFile
345 // cppcheck-suppress useClosedFile
350 static void GIF2RGB(int NumFiles, char *FileName,
354 int i, j, Size, Row, Col, Width, Height, ExtCode, Count;
355 GifRecordType RecordType;
356 GifByteType *Extension;
357 GifRowType *ScreenBuffer;
358 GifFileType *GifFile;
360 InterlacedOffset[] = { 0, 4, 2, 1 }, /* The way Interlaced image should. */
361 InterlacedJumps[] = { 8, 8, 4, 2 }; /* be read - offsets and jumps... */
363 ColorMapObject *ColorMap;
368 if ((GifFile = DGifOpenFileName(FileName, &Error)) == NULL) {
369 PrintGifError(Error);
375 /* Use stdin instead: */
376 if ((GifFile = DGifOpenFileHandle(0, &Error)) == NULL) {
377 PrintGifError(Error);
383 * Allocate the screen as vector of column of rows. Note this
384 * screen is device independent - it's the screen defined by the
385 * GIF file parameters.
387 if ((ScreenBuffer = (GifRowType *)
388 malloc(GifFile->SHeight * sizeof(GifRowType))) == NULL)
389 GIF_EXIT("Failed to allocate memory required, aborted.");
391 Size = GifFile->SWidth * sizeof(GifPixelType);/* Size in bytes one row.*/
392 if ((ScreenBuffer[0] = (GifRowType) malloc(Size)) == NULL) /* First row. */
393 GIF_EXIT("Failed to allocate memory required, aborted.");
395 for (i = 0; i < GifFile->SWidth; i++) /* Set its color to BackGround. */
396 ScreenBuffer[0][i] = GifFile->SBackGroundColor;
397 for (i = 1; i < GifFile->SHeight; i++) {
398 /* Allocate the other rows, and set their color to background too: */
399 if ((ScreenBuffer[i] = (GifRowType) malloc(Size)) == NULL)
400 GIF_EXIT("Failed to allocate memory required, aborted.");
402 memcpy(ScreenBuffer[i], ScreenBuffer[0], Size);
405 /* Scan the content of the GIF file and load the image(s) in: */
407 if (DGifGetRecordType(GifFile, &RecordType) == GIF_ERROR) {
408 PrintGifError(GifFile->Error);
411 switch (RecordType) {
412 case IMAGE_DESC_RECORD_TYPE:
413 if (DGifGetImageDesc(GifFile) == GIF_ERROR) {
414 PrintGifError(GifFile->Error);
417 Row = GifFile->Image.Top; /* Image Position relative to Screen. */
418 Col = GifFile->Image.Left;
419 Width = GifFile->Image.Width;
420 Height = GifFile->Image.Height;
421 GifQprintf("\n%s: Image %d at (%d, %d) [%dx%d]: ",
422 PROGRAM_NAME, ++ImageNum, Col, Row, Width, Height);
423 if (GifFile->Image.Left + GifFile->Image.Width > GifFile->SWidth ||
424 GifFile->Image.Top + GifFile->Image.Height > GifFile->SHeight) {
425 fprintf(stderr, "Image %d is not confined to screen dimension, aborted.\n",ImageNum);
428 if (GifFile->Image.Interlace) {
429 /* Need to perform 4 passes on the images: */
430 for (Count = i = 0; i < 4; i++)
431 for (j = Row + InterlacedOffset[i]; j < Row + Height;
432 j += InterlacedJumps[i]) {
433 GifQprintf("\b\b\b\b%-4d", Count++);
434 if (DGifGetLine(GifFile, &ScreenBuffer[j][Col],
435 Width) == GIF_ERROR) {
436 PrintGifError(GifFile->Error);
442 for (i = 0; i < Height; i++) {
443 GifQprintf("\b\b\b\b%-4d", i);
444 if (DGifGetLine(GifFile, &ScreenBuffer[Row++][Col],
445 Width) == GIF_ERROR) {
446 PrintGifError(GifFile->Error);
452 case EXTENSION_RECORD_TYPE:
453 /* Skip any extension blocks in file: */
454 if (DGifGetExtension(GifFile, &ExtCode, &Extension) == GIF_ERROR) {
455 PrintGifError(GifFile->Error);
458 while (Extension != NULL) {
459 if (DGifGetExtensionNext(GifFile, &Extension) == GIF_ERROR) {
460 PrintGifError(GifFile->Error);
465 case TERMINATE_RECORD_TYPE:
467 default: /* Should be trapped by DGifGetRecordType. */
470 } while (RecordType != TERMINATE_RECORD_TYPE);
472 /* Lets dump it - set the global variables required and do it: */
473 ColorMap = (GifFile->Image.ColorMap
474 ? GifFile->Image.ColorMap
475 : GifFile->SColorMap);
476 if (ColorMap == NULL) {
477 fprintf(stderr, "Gif Image does not have a colormap\n");
481 /* check that the background color isn't garbage (SF bug #87) */
482 if (GifFile->SBackGroundColor < 0 || GifFile->SBackGroundColor >= ColorMap->ColorCount) {
483 fprintf(stderr, "Background color out of range for colormap\n");
487 DumpScreen2RGB(OutFileName, OneFileFlag,
490 GifFile->SWidth, GifFile->SHeight);
492 (void)free(ScreenBuffer);
494 if (DGifCloseFile(GifFile, &Error) == GIF_ERROR) {
495 PrintGifError(Error);
501 /******************************************************************************
502 * Interpret the command line and scan the given GIF file.
503 ******************************************************************************/
504 int main(int argc, char **argv)
506 bool Error, OutFileFlag = false, ColorFlag = false, SizeFlag = false;
507 int NumFiles, Width = 0, Height = 0, ExpNumOfColors = 8;
514 if ((Error = GAGetArgs(argc, argv, CtrlStr, &GifNoisyPrint,
515 &ColorFlag, &ExpNumOfColors, &SizeFlag, &Width, &Height,
516 &OneFileFlag, &OutFileFlag, &OutFileName,
517 &HelpFlag, &NumFiles, &FileName)) != false ||
518 (NumFiles > 1 && !HelpFlag)) {
520 GAPrintErrMsg(Error);
521 else if (NumFiles > 1)
522 GIF_MESSAGE("Error in command line parsing - one input file please.");
523 GAPrintHowTo(CtrlStr);
528 (void)fprintf(stderr, VersionStr, GIFLIB_MAJOR, GIFLIB_MINOR);
529 GAPrintHowTo(CtrlStr);
532 if (!OutFileFlag) OutFileName = NULL;
534 if (SizeFlag && Width > 0 && Height > 0)
535 RGB2GIF(OneFileFlag, NumFiles, *FileName,
536 ExpNumOfColors, Width, Height);
538 GIF2RGB(NumFiles, *FileName, OneFileFlag, OutFileName);