/*============================================================== MODULE NAME: TIFFY.C FUNCTION: Decodes TIFF file tags. To compile the tiffy program, type the following commands: cc tiffy.c mv a.out tiffy To run the program type: tiffy [-v] file_name The -v (verbose) parameter is optional. It provides more data output for some of the tags. file_name is the name of a TIFF file. ================================================================ (c) Copyright 1994-1996. Northern Development Group, Inc. All Rights Reserved. This software is the sole property of Northern Development Group, Inc. This document contains proprietary information which is protected by copyright. No part of this document may be photocopied, reproduced, or translated to another programming language without the prior written consent of Northern Development Group, Inc. ==============================================================*/ #include #ifndef SEEK_SET #define SEEK_SET 0 #endif #ifndef SEEK_END #define SEEK_END 2 #endif #define USHORT unsigned short int #define ULONG unsigned long static FILE *fp; /* THE FILE STREAM POINTER */ static ULONG ThisIfd = 0L; /* OFFSET TO THE IFD */ static int LittleEndian; /* TRUE = INTEL BYTE ORDER */ static int verbose = 0; /* TRUE = VERBOSE OUTPUT */ /* SET THE OPEN MODE */ #if defined(MSDOS) || defined(_WINDOWS) static char *FopenMode = "rb"; #else static char *FopenMode = "r"; #endif /* FORWARD DECLARATIONS */ ULONG ReadLong(); USHORT ReadWord(); char *GetTagName(); main (argc, argv) int argc; char *argv[]; { char *fname; /* USAGE */ if (argc < 2) { usage: printf ("\n\nusage: tiffy [-v] file_name\n"); printf (" -v = verbose (optional)\n"); printf (" file_name = TIFF file name\n\n"); printf ("Copyright (c) 1994-2008 SwiftView, Inc.\n"); printf ("All rights reserved.\n\n"); printf ("SwiftView is a leader in print-formatted business document solutions.\n"); printf ("This program is provided in support of our customers.\n"); printf ("You may freely distribute copies of this program.\n"); printf ("You may obtain the source code at http://www.swiftview.com\n"); printf (" or e-mail tech@swiftview.com with your request.\n\n"); exit(0); } /* VERBOSE FLAG */ if (*argv[1] == '-' && (*(argv[1]+1) == 'v' || *(argv[1]+1) == 'V')) { if (argc < 3) goto usage; verbose = 1; fname = argv[2]; } else fname = argv[1]; /* DECODE THE FILE */ tiff_decode(fname); exit(0); } /******************************************************** DECODE TIFF DATA *********************************************************/ int tiff_decode(filen) char *filen; { int c1; char buff[8]; long size; long ftell(); /* OPEN THE FILE */ fp = fopen(filen, FopenMode); if (fp == NULL) { printf ("The file: %s, did not open.\n",filen); return (0); } /* GET THE FILE SIZE */ fseek(fp, 0L, SEEK_END); printf ("\nReading file: %s \n", filen); printf ("The file size is %lu bytes.\n",ftell(fp)); fseek(fp, 0L, SEEK_SET); /* READ THE FIRST 4 CHARACTERS */ c1 = fread (buff, 1, 4, fp); if (c1 < 4) { printf ("Error reading TIFF header\n"); goto done; } /* GET THE ENDIAN */ if (buff[0] == 'I' && buff[1] == 'I' && buff[2] == 42) { LittleEndian = 1; printf ("Intel (little endian) byte order\n"); } else if (buff[0] == 'M' && buff[1] == 'M' && buff[3] == 42) { LittleEndian = 0; printf ("Motorola (big endian) byte order\n"); } else { printf("%s, is not a TIFF file\n",filen); goto done; } /* SET THE NEXT IFD */ ThisIfd = ReadLong(4L); /* PRINT ALL TAGS ALL IFDs */ while (ThisIfd != 0L) WriteAllTags(); /* FINISHED */ done: fclose(fp); return (0); } /******************************************************** WRITE ALL TAGS *********************************************************/ int WriteAllTags() { USHORT NumTags; int c1; printf ("IFD OFFSET = %lu\n",ThisIfd); /* GET THE NUMBER OF TAGS */ NumTags = ReadWord(ThisIfd); printf ("The number of tags = %u \n\n",NumTags); printf ("Tag Type Length Value\n"); /* READ ALL TAGS */ for (c1=0; c1 < (int)NumTags; ++c1) ReadTag(c1); printf ("\n"); /* GET THE NEXT IFD */ ThisIfd = ReadLong(ThisIfd + NumTags * 12 + 2); return (0); } /******************************************************** WRITE DATA FOR ONE TAG *********************************************************/ int ReadTag(index) int index; { USHORT tag, type; ULONG offset, len; char *str, buff[40]; /* GET THE TAG VALUE */ offset = ThisIfd + index * 12 + 2; tag = ReadWord(offset); if (tag < (unsigned)32768) printf ("%u %-20s ",tag, GetTagName(tag)); else printf ("%u %-18s ",tag, GetTagName(tag)); /* GET DATA TYPE */ type = ReadWord(offset+2); if (type == 1) str = "BYTE"; else if (type == 2) str = "ASCII"; else if (type == 3) str = "SHORT"; else if (type == 4) str = "LONG"; else if (type == 5) str = "RATIONAL"; else if (type == 6) str = "SBYTE"; else if (type == 7) str = "UNDEF(txt)"; else { printf ("Illegal data type %d \n",type); return (0); } printf (" %-8s ",str); /* GET THE DATA LENGTH */ len = ReadLong(offset+4); sprintf (buff,"%lu",len); printf ("%-5s ",buff); if (len == 0) { printf ("Error, tag length = 0\n"); return (0); } /* WRITE TAG DATA */ switch (type) { case 1: case 6: return (WriteBytes(index, len)); case 7: case 2: return (WriteAscii(index, len)); case 3: return (WriteShort(index, len)); case 4: return (WriteLong(index, len)); case 5: return (WriteRational(index, len)); } return (0); } /******************************************************** READ LONG VALUE *********************************************************/ ULONG ReadLong (offset) ULONG offset; { unsigned char buff[4]; int cnt; ULONG value; fseek (fp, offset, SEEK_SET); cnt = fread(buff, 1, 4, fp); if (cnt != 4) { printf("\nError reading long value, offset = %lu\n",offset); exit(0); } /* CONVERT TO LONG */ if (LittleEndian) { value = buff[0] + 256L * buff[1] + 65536L * buff[2] + 16777216L * buff[3]; } else { value = buff[3] + 256L * buff[2] + 65536L * buff[1] + 16777216L * buff[0]; } return (value); } /******************************************************** READ WORD VALUE *********************************************************/ USHORT ReadWord (offset) ULONG offset; { unsigned char buff[2]; int cnt; USHORT value; fseek (fp, offset, SEEK_SET); cnt = fread(buff, 1, 2, fp); if (cnt != 2) { printf("\nError reading short value, offset = %lu\n",offset); exit(0); } /* CONVERT TO WORD */ if (LittleEndian) value = buff[0] + (USHORT)256 * (USHORT)buff[1]; else value = buff[1] + (USHORT)256 * (USHORT)buff[0]; return (value); } /******************************************************** GET A TAG NAME *********************************************************/ char *GetTagName(tag) USHORT tag; { switch (tag) { case 254: return("New Subfile Type"); case 255: return("Subfile Type"); case 256: return("Image Width"); case 257: return("Image Length"); case 258: return("Bits Per Sample"); case 259: return("Compression"); case 262: return("Photometric"); case 263: return("Thresholding"); case 264: return("Cell Width"); case 265: return("Cell Length"); case 266: return("Fill Order"); case 269: return("Document Name"); case 270: return("Image Description"); case 271: return("Make"); case 272: return("Model"); case 273: return("Strip Offsets"); case 274: return("Orientation"); case 277: return("Samples Per Pixel"); case 278: return("Rows Per Strip"); case 279: return("Strip Byte Counts"); case 280: return("Min Sample Value"); case 281: return("Max Sample Value"); case 282: return("X Resolution"); case 283: return("Y Resolution"); case 284: return("Planar Configuration"); case 285: return("Page Name"); case 286: return("X Position"); case 287: return("Y Position"); case 288: return("Free Offsets"); case 289: return("Free Byte Counts"); case 290: return("Gray Response Unit"); case 291: return("Gray Response Curve"); case 292: return("Group 3 Options"); case 293: return("Group 4 Options"); case 296: return("Resolution Unit"); case 297: return("Page Number"); case 300: return("Color Response Unit"); case 301: return("Transfer Function"); case 305: return("Software"); case 306: return("Date Time"); case 315: return("Artist"); case 316: return("Host Computer"); case 317: return("Predictor"); case 318: return("White Point"); case 319: return("Primary Chromaticities"); case 320: return("Color Map"); case 321: return("Halftone Hints"); case 322: return("Tile Width"); case 323: return("Tile Length"); case 324: return("Tile Offsets"); case 325: return("Tile Byte Counts"); case 326: return("Bad FAX Lines"); case 327: return("Clean FAX Data"); case 328: return("Consecutive Bad FAX Lines"); case 332: return("Ink Set"); case 333: return("Ink Names"); case 334: return("Number Of Inks"); case 336: return("Dot Range"); case 337: return("Target Printer"); case 338: return("Extra Samples"); case 339: return("Sample Format"); case 340: return("SMin Sample Value"); case 341: return("SMax Sample Value"); case 342: return("Transfer Range"); case 512: return("JPEG Proc"); case 513: return("JPEG Interchange Format"); case 514: return("JPEG Interchange Format Length"); case 515: return("JPEG Restart Interval"); case 517: return("JPEG Lossless Predictors"); case 518: return("JPEG Point Transforms"); case 519: return("JPEG Q Tables"); case 520: return("JPEG DCT Tables"); case 521: return("JPEG ACT Tables"); case 529: return("YCbCr Coefficients"); case 530: return("YCbCr Sub-sampling"); case 531: return("YCbCr Positioning"); case 532: return("Reference Black White"); case 33432: return("Copyright"); } /* NONE OF THE ABOVE */ if (tag > (unsigned)32768) return ("Private Tag"); return ("Unrecognized Tag"); } /******************************************************** WRITE BYTE TAG DATA *********************************************************/ int WriteBytes(index, count) int index; ULONG count; { ULONG TagOffset, DataOffset, c1; char buff[80]; /* GET THE TAG VALUE */ TagOffset = ThisIfd + index * 12 + 2; /* IF COUNT > 4, OUTSIDE THE TAG */ if (count > 4) { DataOffset = ReadLong(TagOffset+8); sprintf(buff,"<%lu>",DataOffset); printf (" %-8s ",buff); } else DataOffset = TagOffset + 8; if (count > 4 && verbose) printf("\n "); if (count > 4 && !verbose) { printf("\n"); return (0); } printf (" "); fseek (fp, DataOffset, SEEK_SET); for (c1=0; c1 < count; ++c1) { printf ("%.2x ",(unsigned char)fgetc(fp)); if ((c1 & 0xF) == 0xF) printf ("\n "); } printf ("\n"); return (0); } /******************************************************** WRITE ASCII TAG DATA *********************************************************/ int WriteAscii(index, count) int index; ULONG count; { ULONG TagOffset, DataOffset, c1; char buff[80]; int v = 0; /* GET THE TAG VALUE */ TagOffset = ThisIfd + index * 12 + 2; /* IF COUNT > 4, OUTSIDE THE TAG */ if (count > 4) { DataOffset = ReadLong(TagOffset+8); sprintf(buff,"data at: %lu:",DataOffset); printf (" %-17s ",buff); } else DataOffset = TagOffset + 8; if (count > 30 && verbose) printf("\n"); else if (count > 30 && count < 80) printf ("\n"); else if (count > 80 && !verbose) { count=80; v = 1; } fseek (fp, DataOffset, SEEK_SET); for (c1=0; c1 < count; ++c1) printf ("%c",fgetc(fp)); printf(v ?"...\n" : "\n"); return (0); } /******************************************************** WRITE SHORT TAG DATA *********************************************************/ int WriteShort(index, count) int index; ULONG count; { ULONG TagOffset, DataOffset, c1; USHORT s1; char buff[80]; /* GET THE TAG VALUE */ TagOffset = ThisIfd + index * 12 + 2; /* IF COUNT > 2, OUTSIDE THE TAG */ if (count > 2) { DataOffset = ReadLong(TagOffset+8); sprintf(buff,"<%lu>",DataOffset); printf (" %-8s ",buff); } else DataOffset = TagOffset + 8; /* PRINT UP TO 3 VALUES IN NON - VERBOSE MODE */ if (count <= 3) { for (c1 = 0; c1 < count; ++c1, DataOffset += 2L) { s1 = ReadWord(DataOffset); sprintf(buff,"%u",s1); printf (" %-6s ",buff); } } else if (verbose) { printf ("\n "); for (c1 = 0; c1 < count; ++c1, DataOffset += 2L) { s1 = ReadWord(DataOffset); sprintf(buff,"%u",s1); printf ("%-6s ",buff); if ((c1 & 7) == 7) printf ("\n "); } } printf ("\n"); return (0); } /******************************************************** WRITE LONG TAG DATA *********************************************************/ int WriteLong(index, count) int index; ULONG count; { ULONG TagOffset, DataOffset, c1, k1; char buff[80]; /* GET THE TAG VALUE */ TagOffset = ThisIfd + index * 12 + 2; /* IF COUNT > 1, OUTSIDE THE TAG */ if (count > 1) { DataOffset = ReadLong(TagOffset+8); sprintf(buff,"<%lu>",DataOffset); printf (" %-8s ",buff); } else DataOffset = TagOffset + 8; if (count > 1 && verbose) printf ("\n "); if (count > 1 && !verbose) { printf("\n"); return (0); } for (c1 = 0; c1 < count; ++c1, DataOffset += 4L) { k1 = ReadLong(DataOffset); sprintf(buff,"%lu",k1); printf (" %-7s ",buff); if (count == 1L) printf (" (%lx Hex)",k1); if ((c1 & 7) == 7) printf ("\n "); } printf ("\n"); return (0); } /******************************************************** WRITE RATIONAL TAG DATA *********************************************************/ int WriteRational(index, count) int index; ULONG count; { ULONG TagOffset, DataOffset, c1, k1, k2; USHORT s1; char buff[80]; float f1; /* GET THE TAG VALUE */ TagOffset = ThisIfd + index * 12 + 2; DataOffset = ReadLong(TagOffset+8); sprintf(buff,"<%lu>",DataOffset); printf (" %-8s ",buff); if (count > 1 && verbose) printf ("\n "); if (count > 1 && !verbose) { printf("\n"); return (0); } /* PRINT VALUES */ for (c1 = 0; c1 < count; ++c1, DataOffset += 8L) { k1 = ReadLong(DataOffset); k2 = ReadLong(DataOffset+4L); if (k2 == 0L) { printf ("%lu / %lu = ?",k1, k2); printf (" Error, the denominator should not be zero\n"); return(0); } f1 = (float)k1 / (float)k2; printf ("%lu / %lu = %.3f",k1, k2, f1); if (c1 & 1) printf ("\n "); } printf ("\n"); return (0); }