bb12c7cddb817244f93293065a95f080fed6ced6
[platform/upstream/giflib.git] / giftext.c
1 /*****************************************************************************
2
3 giftext - dump GIF pixels and metadata as text
4
5 *****************************************************************************/
6
7 #include <stdlib.h>
8 #include <stdio.h>
9 #include <ctype.h>
10 #include <fcntl.h>
11 #include <stdbool.h>
12
13 #ifdef _WIN32
14 #include <io.h>
15 #endif /* _WIN32 */
16
17 #include "gif_lib.h"
18 #include "getarg.h"
19
20 #define PROGRAM_NAME    "giftext"
21
22 #define MAKE_PRINTABLE(c)  (isprint(c) ? (c) : ' ')
23
24 static char
25     *VersionStr =
26         PROGRAM_NAME
27         VERSION_COOKIE
28         "       Gershon Elber,  "
29         __DATE__ ",   " __TIME__ "\n"
30         "(C) Copyright 1989 Gershon Elber.\n";
31 static char
32     *CtrlStr =
33         PROGRAM_NAME
34         " v%- c%- e%- z%- p%- r%- h%- GifFile!*s";
35
36 static void PrintCodeBlock(GifFileType *GifFile, GifByteType *CodeBlock, bool Reset);
37 static void PrintPixelBlock(GifByteType *PixelBlock, int Len, bool Reset);
38 static void PrintExtBlock(GifByteType *Extension, bool Reset);
39 static void PrintLZCodes(GifFileType *GifFile);
40
41 /******************************************************************************
42  Interpret the command line and scan the given GIF file.
43 ******************************************************************************/
44 int main(int argc, char **argv)
45 {
46     int i, j, ExtCode, ErrorCode, CodeSize, NumFiles, Len, ImageNum = 1;
47     bool Error,
48         ColorMapFlag = false, EncodedFlag = false, LZCodesFlag = false,
49         PixelFlag = false, HelpFlag = false, RawFlag = false; 
50     char *GifFileName, **FileName = NULL;
51     GifPixelType *Line;
52     GifRecordType RecordType;
53     GifByteType *CodeBlock, *Extension;
54     GifFileType *GifFile;
55
56     if ((Error = GAGetArgs(argc, argv, CtrlStr,
57                 &GifNoisyPrint, &ColorMapFlag, &EncodedFlag,
58                 &LZCodesFlag, &PixelFlag, &RawFlag, &HelpFlag,
59                 &NumFiles, &FileName)) != false ||
60         (NumFiles > 1 && !HelpFlag)) {
61         if (Error)
62             GAPrintErrMsg(Error);
63         else if (NumFiles > 1)
64             GIF_MESSAGE("Error in command line parsing - one GIF file please.");
65         GAPrintHowTo(CtrlStr);
66         exit(EXIT_FAILURE);
67     }
68
69     if (HelpFlag) {
70         (void)fprintf(stderr, VersionStr, GIFLIB_MAJOR, GIFLIB_MINOR);
71         GAPrintHowTo(CtrlStr);
72         exit(EXIT_SUCCESS);
73     }
74
75     if (NumFiles == 1) {
76         GifFileName = *FileName;
77         if ((GifFile = DGifOpenFileName(*FileName, &ErrorCode)) == NULL) {
78             PrintGifError(ErrorCode);
79             exit(EXIT_FAILURE);
80         }
81     }
82     else {
83         /* Use stdin instead: */
84         GifFileName = "Stdin";
85         if ((GifFile = DGifOpenFileHandle(0, &ErrorCode)) == NULL) {
86             PrintGifError(ErrorCode);
87             exit(EXIT_FAILURE);
88         }
89     }
90
91     /* Because we write binary data - make sure no text will be written. */
92     if (RawFlag) {
93         ColorMapFlag = EncodedFlag = LZCodesFlag = PixelFlag = false;
94 #ifdef _WIN32
95         _setmode(1, O_BINARY);             /* Make sure it is in binary mode. */
96 #endif /* _WIN32 */
97     }
98     else {
99         printf("\n%s:\n\n\tScreen Size - Width = %d, Height = %d.\n",
100                GifFileName, GifFile->SWidth, GifFile->SHeight);
101         printf("\tColorResolution = %d, BitsPerPixel = %d, BackGround = %d, Aspect = %d.\n",
102                GifFile->SColorResolution,
103                GifFile->SColorMap ? GifFile->SColorMap->BitsPerPixel : 0,
104                GifFile->SBackGroundColor,
105                GifFile->AspectByte);
106         if (GifFile->SColorMap)
107             printf("\tHas Global Color Map.\n\n");
108         else
109             printf("\tNo Global Color Map.\n\n");
110         if (ColorMapFlag && GifFile->SColorMap) {
111             printf("\tGlobal Color Map:\n");
112             Len = GifFile->SColorMap->ColorCount;
113             printf("\tSort Flag: %s\n", 
114                    GifFile->SColorMap->SortFlag ? "on":"off");
115             for (i = 0; i < Len; i+=4) {
116                 for (j = 0; j < 4 && j < Len; j++) {
117                     printf("%3d: %02xh %02xh %02xh   ", i + j,
118                            GifFile->SColorMap->Colors[i + j].Red,
119                            GifFile->SColorMap->Colors[i + j].Green,
120                            GifFile->SColorMap->Colors[i + j].Blue);
121                 }
122                 printf("\n");
123             }
124         }
125     }
126
127     do {
128         if (DGifGetRecordType(GifFile, &RecordType) == GIF_ERROR) {
129             PrintGifError(GifFile->Error);
130             exit(EXIT_FAILURE);
131         }
132         switch (RecordType) {
133             case IMAGE_DESC_RECORD_TYPE:
134                 if (DGifGetImageDesc(GifFile) == GIF_ERROR) {
135                     PrintGifError(GifFile->Error);
136                     exit(EXIT_FAILURE);
137                 }
138                 if (!RawFlag) {
139                     printf("\nImage #%d:\n\n\tImage Size - Left = %d, Top = %d, Width = %d, Height = %d.\n",
140                            ImageNum++, GifFile->Image.Left, GifFile->Image.Top,
141                            GifFile->Image.Width, GifFile->Image.Height);
142                     printf("\tImage is %s",
143                            GifFile->Image.Interlace ? "Interlaced" :
144                                                     "Non Interlaced");
145                     if (GifFile->Image.ColorMap != NULL)
146                         printf(", BitsPerPixel = %d.\n",
147                                 GifFile->Image.ColorMap->BitsPerPixel);
148                     else
149                         printf(".\n");
150                     if (GifFile->Image.ColorMap)
151                         printf("\tImage Has Color Map.\n");
152                     else
153                         printf("\tNo Image Color Map.\n");
154                     if (ColorMapFlag && GifFile->Image.ColorMap) {
155                         printf("\tSort Flag: %s\n", 
156                                GifFile->Image.ColorMap->SortFlag ? "on":"off");
157                         Len = 1 << GifFile->Image.ColorMap->BitsPerPixel;
158                         for (i = 0; i < Len; i+=4) {
159                             for (j = 0; j < 4 && j < Len; j++) {
160                                 printf("%3d: %02xh %02xh %02xh   ", i + j,
161                                        GifFile->Image.ColorMap->Colors[i + j].Red,
162                                        GifFile->Image.ColorMap->Colors[i + j].Green,
163                                        GifFile->Image.ColorMap->Colors[i + j].Blue);
164                             }
165                             printf("\n");
166                         }
167                     }
168                 }
169
170                 if (EncodedFlag) {
171                     if (DGifGetCode(GifFile, &CodeSize, &CodeBlock) == GIF_ERROR) {
172                         PrintGifError(GifFile->Error);
173                         exit(EXIT_FAILURE);
174                     }
175                     printf("\nImage LZ compressed Codes (Code Size = %d):\n",
176                            CodeSize);
177                     PrintCodeBlock(GifFile, CodeBlock, true);
178                     while (CodeBlock != NULL) {
179                         if (DGifGetCodeNext(GifFile, &CodeBlock) == GIF_ERROR) {
180                             PrintGifError(GifFile->Error);
181                             exit(EXIT_FAILURE);
182                         }
183                         PrintCodeBlock(GifFile, CodeBlock, false);
184                     }
185                 }
186                 else if (LZCodesFlag) {
187                     PrintLZCodes(GifFile);
188                 }
189                 else if (PixelFlag) {
190                     Line = (GifPixelType *) malloc(GifFile->Image.Width *
191                                                 sizeof(GifPixelType));
192                     for (i = 0; i < GifFile->Image.Height; i++) {
193                         if (DGifGetLine(GifFile, Line, GifFile->Image.Width)
194                             == GIF_ERROR) {
195                             PrintGifError(GifFile->Error);
196                             exit(EXIT_FAILURE);
197                         }
198                         PrintPixelBlock(Line, GifFile->Image.Width, i == 0);
199                     }
200                     PrintPixelBlock(NULL, GifFile->Image.Width, false);
201                     free((char *) Line);
202                 }
203                 else if (RawFlag) {
204                     Line = (GifPixelType *) malloc(GifFile->Image.Width *
205                                                 sizeof(GifPixelType));
206                     for (i = 0; i < GifFile->Image.Height; i++) {
207                         if (DGifGetLine(GifFile, Line, GifFile->Image.Width)
208                             == GIF_ERROR) {
209                             PrintGifError(GifFile->Error);
210                             exit(EXIT_FAILURE);
211                         }
212                         fwrite(Line, 1, GifFile->Image.Width, stdout);
213                     }
214                     free((char *) Line);
215                 }
216                 else {
217                     /* Skip the image: */
218                     if (DGifGetCode(GifFile, &CodeSize, &CodeBlock) == GIF_ERROR) {
219                         PrintGifError(GifFile->Error);
220                         exit(EXIT_FAILURE);
221                     }
222                     while (CodeBlock != NULL) {
223                         if (DGifGetCodeNext(GifFile, &CodeBlock) == GIF_ERROR) {
224                             PrintGifError(GifFile->Error);
225                             exit(EXIT_FAILURE);
226                         }
227                     }
228
229                 }
230                 break;
231             case EXTENSION_RECORD_TYPE:
232                 if (DGifGetExtension(GifFile, &ExtCode, &Extension) == GIF_ERROR) {
233                     PrintGifError(GifFile->Error);
234                     exit(EXIT_FAILURE);
235                 }
236                 if (!RawFlag) {
237                     putchar('\n');
238                     switch (ExtCode)
239                     {
240                     case COMMENT_EXT_FUNC_CODE:
241                         printf("GIF89 comment");
242                         break;
243                     case GRAPHICS_EXT_FUNC_CODE:
244                         printf("GIF89 graphics control");
245                         break;
246                     case PLAINTEXT_EXT_FUNC_CODE:
247                         printf("GIF89 plaintext");
248                         break;
249                     case APPLICATION_EXT_FUNC_CODE:
250                         printf("GIF89 application block");
251                         break;
252                     default:
253                         printf("Extension record of unknown type");
254                         break;
255                     }
256                     printf(" (Ext Code = %d [%c]):\n",
257                            ExtCode, MAKE_PRINTABLE(ExtCode));
258                     PrintExtBlock(Extension, true);
259
260                     if (ExtCode == GRAPHICS_EXT_FUNC_CODE) {
261                         GraphicsControlBlock gcb;
262                         if (Extension == NULL) {
263                             printf("Invalid extension block\n");
264                             GifFile->Error = D_GIF_ERR_IMAGE_DEFECT;
265                             PrintGifError(GifFile->Error);
266                             exit(EXIT_FAILURE);
267                         }
268                         if (DGifExtensionToGCB(Extension[0], Extension+1, &gcb) == GIF_ERROR) {
269                             PrintGifError(GifFile->Error);
270                             exit(EXIT_FAILURE);
271                         }
272                         printf("\tDisposal Mode: %d\n", gcb.DisposalMode);
273                         printf("\tUser Input Flag: %d\n", gcb.UserInputFlag);
274                         printf("\tTransparency on: %s\n",
275                                gcb.TransparentColor != -1 ? "yes" : "no");
276                         printf("\tDelayTime: %d\n", gcb.DelayTime);
277                         printf("\tTransparent Index: %d\n", gcb.TransparentColor);
278                     }
279                 }
280                 for (;;) {
281                     if (DGifGetExtensionNext(GifFile, &Extension) == GIF_ERROR) {
282                         PrintGifError(GifFile->Error);
283                         exit(EXIT_FAILURE);
284                     }
285                     if (Extension == NULL)
286                         break;
287                     PrintExtBlock(Extension, false);
288                 }
289                 break;
290             case TERMINATE_RECORD_TYPE:
291                 break;
292             default:         /* Should be trapped by DGifGetRecordType */
293                 break;
294         }
295     }
296     while (RecordType != TERMINATE_RECORD_TYPE);
297
298     if (DGifCloseFile(GifFile, &ErrorCode) == GIF_ERROR) {
299         PrintGifError(ErrorCode);
300         exit(EXIT_FAILURE);
301     }
302
303     if (!RawFlag) printf("\nGIF file terminated normally.\n");
304
305     return 0;
306 }
307
308 /******************************************************************************
309  Print the given CodeBlock - a string in pascal notation (size in first
310  place). Save local information so printing can be performed continuously,
311  or reset to start state if Reset. If CodeBlock is NULL, output is flushed
312 ******************************************************************************/
313 static void PrintCodeBlock(GifFileType *GifFile, GifByteType *CodeBlock, bool Reset)
314 {
315     static int CrntPlace = 0; 
316     static long CodeCount = 0;
317     int i, Len;
318
319     if (Reset || CodeBlock == NULL) {
320         if (CodeBlock == NULL) {
321             long NumBytes = 0;
322             if (CrntPlace > 0) {
323                 printf("\n");
324                 CodeCount += CrntPlace - 16;
325             }
326             if (GifFile->Image.ColorMap)
327                 NumBytes = ((((long) GifFile->Image.Width) * GifFile->Image.Height)
328                                 * GifFile->Image.ColorMap->BitsPerPixel) / 8;
329             else if (GifFile->SColorMap != NULL)
330                 NumBytes = ((((long) GifFile->Image.Width) * GifFile->Image.Height)
331                                 * GifFile->SColorMap->BitsPerPixel) / 8;
332             /* FIXME: What should the compression ratio be if no color table? */
333             if (NumBytes > 0) {
334                 int Percent = 100 * CodeCount / NumBytes;
335                 printf("\nCompression ratio: %ld/%ld (%d%%).\n",
336                         CodeCount, NumBytes, Percent);
337             }
338             return;
339         }
340         CrntPlace = 0;
341         CodeCount = 0;
342     }
343
344     Len = CodeBlock[0];
345     for (i = 1; i <= Len; i++) {
346         if (CrntPlace == 0) {
347             printf("\n%05lxh:  ", CodeCount);
348             CodeCount += 16;
349         }
350         (void)printf(" %02xh", CodeBlock[i]);
351         if (++CrntPlace >= 16) CrntPlace = 0;
352     }
353 }
354
355 /******************************************************************************
356  Print the given Extension - a string in pascal notation (size in first
357  place). Save local information so printing can be performed continuously,
358  or reset to start state if Reset. If Extension is NULL, output is flushed
359 ******************************************************************************/
360 static void PrintExtBlock(GifByteType *Extension, bool Reset)
361 {
362     static int CrntPlace = 0;
363     static long ExtCount = 0;
364     static char HexForm[49], AsciiForm[17];
365
366     if (Reset || Extension == NULL) {
367         if (Extension == NULL) {
368             if (CrntPlace > 0) {
369                 HexForm[CrntPlace * 3] = 0;
370                 AsciiForm[CrntPlace] = 0;
371                 printf("\n%05lx: %-49s  %-17s\n", ExtCount, HexForm, AsciiForm);
372                 return;
373             }
374             else
375                 printf("\n");
376         }
377         CrntPlace = 0;
378         ExtCount = 0;
379     }
380
381     if (Extension != NULL) {
382         int i, Len;
383         Len = Extension[0];
384         for (i = 1; i <= Len; i++) {
385             (void)snprintf(&HexForm[CrntPlace * 3], 3,
386                            " %02x", Extension[i]);
387             (void)snprintf(&AsciiForm[CrntPlace], 3,
388                            "%c", MAKE_PRINTABLE(Extension[i]));
389             if (++CrntPlace == 16) {
390                 HexForm[CrntPlace * 3] = 0;
391                 AsciiForm[CrntPlace] = 0;
392                 printf("\n%05lx: %-49s  %-17s", ExtCount, HexForm, AsciiForm);
393                 ExtCount += 16;
394                 CrntPlace = 0;
395             }
396         }
397     }
398 }
399
400 /******************************************************************************
401  Print the given PixelBlock of length Len.
402  Save local information so printing can be performed continuously,
403  or reset to start state if Reset. If PixelBlock is NULL, output is flushed
404 ******************************************************************************/
405 static void PrintPixelBlock(GifByteType *PixelBlock, int Len, bool Reset)
406 {
407     static int CrntPlace = 0; 
408     static long ExtCount = 0;
409     static char HexForm[49], AsciiForm[17];
410     int i;
411
412     if (Reset || PixelBlock == NULL) {
413         if (PixelBlock == NULL) {
414             if (CrntPlace > 0) {
415                 HexForm[CrntPlace * 3] = 0;
416                 AsciiForm[CrntPlace] = 0;
417                 printf("\n%05lx: %-49s  %-17s\n", ExtCount, HexForm, AsciiForm);
418             }
419             else
420                 printf("\n");
421         }
422         CrntPlace = 0;
423         ExtCount = 0;
424         if (PixelBlock == NULL) return;
425     }
426
427     for (i = 0; i < Len; i++) {
428         (void)snprintf(&HexForm[CrntPlace * 3], 3,
429                        " %02x", PixelBlock[i]);
430         (void)snprintf(&AsciiForm[CrntPlace], 3,
431                        "%c", MAKE_PRINTABLE(PixelBlock[i]));
432         if (++CrntPlace == 16) {
433             HexForm[CrntPlace * 3] = 0;
434             AsciiForm[CrntPlace] = 0;
435             printf("\n%05lx: %-49s  %-17s", ExtCount, HexForm, AsciiForm);
436             ExtCount += 16;
437             CrntPlace = 0;
438         }
439     }
440 }
441
442 /******************************************************************************
443  Print the image as LZ codes (each 12bits), until EOF marker is reached.
444 ******************************************************************************/
445 static void PrintLZCodes(GifFileType *GifFile)
446 {
447     int Code, CrntPlace = 0;
448     long CodeCount = 0;
449
450     do {
451         if (CrntPlace == 0) printf("\n%05lx:", CodeCount);
452         if (DGifGetLZCodes(GifFile, &Code) == GIF_ERROR) {
453             PrintGifError(GifFile->Error);
454             exit(EXIT_FAILURE);
455         }
456         if (Code >= 0)
457             printf(" %03x", Code);            /* EOF Code is returned as -1. */
458         CodeCount++;
459         if (++CrntPlace >= 16) CrntPlace = 0;
460     }
461     while (Code >= 0);
462 }
463
464 /* end */