1 /*****************************************************************************
3 giftext - dump GIF pixels and metadata as text
5 *****************************************************************************/
20 #define PROGRAM_NAME "giftext"
22 #define MAKE_PRINTABLE(c) (isprint(c) ? (c) : ' ')
29 __DATE__ ", " __TIME__ "\n"
30 "(C) Copyright 1989 Gershon Elber.\n";
34 " v%- c%- e%- z%- p%- r%- h%- GifFile!*s";
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);
41 /******************************************************************************
42 Interpret the command line and scan the given GIF file.
43 ******************************************************************************/
44 int main(int argc, char **argv)
46 int i, j, ExtCode, ErrorCode, CodeSize, NumFiles, Len, ImageNum = 1;
48 ColorMapFlag = false, EncodedFlag = false, LZCodesFlag = false,
49 PixelFlag = false, HelpFlag = false, RawFlag = false;
50 char *GifFileName, **FileName = NULL;
52 GifRecordType RecordType;
53 GifByteType *CodeBlock, *Extension;
56 if ((Error = GAGetArgs(argc, argv, CtrlStr,
57 &GifNoisyPrint, &ColorMapFlag, &EncodedFlag,
58 &LZCodesFlag, &PixelFlag, &RawFlag, &HelpFlag,
59 &NumFiles, &FileName)) != false ||
60 (NumFiles > 1 && !HelpFlag)) {
63 else if (NumFiles > 1)
64 GIF_MESSAGE("Error in command line parsing - one GIF file please.");
65 GAPrintHowTo(CtrlStr);
70 (void)fprintf(stderr, VersionStr, GIFLIB_MAJOR, GIFLIB_MINOR);
71 GAPrintHowTo(CtrlStr);
76 GifFileName = *FileName;
77 if ((GifFile = DGifOpenFileName(*FileName, &ErrorCode)) == NULL) {
78 PrintGifError(ErrorCode);
83 /* Use stdin instead: */
84 GifFileName = "Stdin";
85 if ((GifFile = DGifOpenFileHandle(0, &ErrorCode)) == NULL) {
86 PrintGifError(ErrorCode);
91 /* Because we write binary data - make sure no text will be written. */
93 ColorMapFlag = EncodedFlag = LZCodesFlag = PixelFlag = false;
95 _setmode(1, O_BINARY); /* Make sure it is in binary mode. */
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");
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);
128 if (DGifGetRecordType(GifFile, &RecordType) == GIF_ERROR) {
129 PrintGifError(GifFile->Error);
132 switch (RecordType) {
133 case IMAGE_DESC_RECORD_TYPE:
134 if (DGifGetImageDesc(GifFile) == GIF_ERROR) {
135 PrintGifError(GifFile->Error);
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" :
145 if (GifFile->Image.ColorMap != NULL)
146 printf(", BitsPerPixel = %d.\n",
147 GifFile->Image.ColorMap->BitsPerPixel);
150 if (GifFile->Image.ColorMap)
151 printf("\tImage Has Color Map.\n");
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);
171 if (DGifGetCode(GifFile, &CodeSize, &CodeBlock) == GIF_ERROR) {
172 PrintGifError(GifFile->Error);
175 printf("\nImage LZ compressed Codes (Code Size = %d):\n",
177 PrintCodeBlock(GifFile, CodeBlock, true);
178 while (CodeBlock != NULL) {
179 if (DGifGetCodeNext(GifFile, &CodeBlock) == GIF_ERROR) {
180 PrintGifError(GifFile->Error);
183 PrintCodeBlock(GifFile, CodeBlock, false);
186 else if (LZCodesFlag) {
187 PrintLZCodes(GifFile);
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)
195 PrintGifError(GifFile->Error);
198 PrintPixelBlock(Line, GifFile->Image.Width, i == 0);
200 PrintPixelBlock(NULL, GifFile->Image.Width, false);
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)
209 PrintGifError(GifFile->Error);
212 fwrite(Line, 1, GifFile->Image.Width, stdout);
217 /* Skip the image: */
218 if (DGifGetCode(GifFile, &CodeSize, &CodeBlock) == GIF_ERROR) {
219 PrintGifError(GifFile->Error);
222 while (CodeBlock != NULL) {
223 if (DGifGetCodeNext(GifFile, &CodeBlock) == GIF_ERROR) {
224 PrintGifError(GifFile->Error);
231 case EXTENSION_RECORD_TYPE:
232 if (DGifGetExtension(GifFile, &ExtCode, &Extension) == GIF_ERROR) {
233 PrintGifError(GifFile->Error);
240 case COMMENT_EXT_FUNC_CODE:
241 printf("GIF89 comment");
243 case GRAPHICS_EXT_FUNC_CODE:
244 printf("GIF89 graphics control");
246 case PLAINTEXT_EXT_FUNC_CODE:
247 printf("GIF89 plaintext");
249 case APPLICATION_EXT_FUNC_CODE:
250 printf("GIF89 application block");
253 printf("Extension record of unknown type");
256 printf(" (Ext Code = %d [%c]):\n",
257 ExtCode, MAKE_PRINTABLE(ExtCode));
258 PrintExtBlock(Extension, true);
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);
268 if (DGifExtensionToGCB(Extension[0], Extension+1, &gcb) == GIF_ERROR) {
269 PrintGifError(GifFile->Error);
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);
281 if (DGifGetExtensionNext(GifFile, &Extension) == GIF_ERROR) {
282 PrintGifError(GifFile->Error);
285 if (Extension == NULL)
287 PrintExtBlock(Extension, false);
290 case TERMINATE_RECORD_TYPE:
292 default: /* Should be trapped by DGifGetRecordType */
296 while (RecordType != TERMINATE_RECORD_TYPE);
298 if (DGifCloseFile(GifFile, &ErrorCode) == GIF_ERROR) {
299 PrintGifError(ErrorCode);
303 if (!RawFlag) printf("\nGIF file terminated normally.\n");
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)
315 static int CrntPlace = 0;
316 static long CodeCount = 0;
319 if (Reset || CodeBlock == NULL) {
320 if (CodeBlock == NULL) {
324 CodeCount += CrntPlace - 16;
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? */
334 int Percent = 100 * CodeCount / NumBytes;
335 printf("\nCompression ratio: %ld/%ld (%d%%).\n",
336 CodeCount, NumBytes, Percent);
345 for (i = 1; i <= Len; i++) {
346 if (CrntPlace == 0) {
347 printf("\n%05lxh: ", CodeCount);
350 (void)printf(" %02xh", CodeBlock[i]);
351 if (++CrntPlace >= 16) CrntPlace = 0;
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)
362 static int CrntPlace = 0;
363 static long ExtCount = 0;
364 static char HexForm[49], AsciiForm[17];
366 if (Reset || Extension == NULL) {
367 if (Extension == NULL) {
369 HexForm[CrntPlace * 3] = 0;
370 AsciiForm[CrntPlace] = 0;
371 printf("\n%05lx: %-49s %-17s\n", ExtCount, HexForm, AsciiForm);
381 if (Extension != NULL) {
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);
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)
407 static int CrntPlace = 0;
408 static long ExtCount = 0;
409 static char HexForm[49], AsciiForm[17];
412 if (Reset || PixelBlock == NULL) {
413 if (PixelBlock == NULL) {
415 HexForm[CrntPlace * 3] = 0;
416 AsciiForm[CrntPlace] = 0;
417 printf("\n%05lx: %-49s %-17s\n", ExtCount, HexForm, AsciiForm);
424 if (PixelBlock == NULL) return;
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);
442 /******************************************************************************
443 Print the image as LZ codes (each 12bits), until EOF marker is reached.
444 ******************************************************************************/
445 static void PrintLZCodes(GifFileType *GifFile)
447 int Code, CrntPlace = 0;
451 if (CrntPlace == 0) printf("\n%05lx:", CodeCount);
452 if (DGifGetLZCodes(GifFile, &Code) == GIF_ERROR) {
453 PrintGifError(GifFile->Error);
457 printf(" %03x", Code); /* EOF Code is returned as -1. */
459 if (++CrntPlace >= 16) CrntPlace = 0;