/*********************************************************************** Process JPEG files to display the pixel resolution. Optionally dump the header blocks found (-d option). Copyright (C) Rolf Howarth rolf@insect.demon.co.uk Version History 1.0 23 Dec 1996 Support for JPEGs 1.1 1 Oct 1997 Better JPEG dumping; support for JPEG PICTs 1.2 10 Oct 1997 Support for GIFs Bugs/To Do Inconsistent handling of errors and warnings (stderr? exit status?) No control over order of output if combining -c, -s and -t. GIFs should display total file size at end. ************************************************************************/ #include #include void process(FILE*); void processGIF(FILE*); void processJPEG(FILE*); int readword(FILE*); int readblock(FILE*); char* type_name(int type); #define DELIM 0xff #define SOI 0xd8 #define EOI 0xd9 #define APP0 0xe0 #define SOF0 0xc0 #define SOF2 0xc2 #define COM 0xfe #define SOS 0xda #define RST0 0xd0 #define RST1 0xd1 #define RST2 0xd2 #define RST3 0xd3 #define RST4 0xd4 #define RST5 0xd5 #define RST6 0xd6 #define RST7 0xd7 int debug = 0; int endMarker; int H,V; char* comment; int showSize = 0; int showComment = 0; int showType = 0; int htmlImage = 0; char *filename; int main(int argc, char** argv) { int i; while (argc>1 && argv[1][0]=='-') { ++argv; --argc; if (argv[0][1]=='d') ++debug; else if (argv[0][1]=='c') showComment = 1; else if (argv[0][1]=='s') showSize = 1; else if (argv[0][1]=='t') showType = 1; else if (argv[0][1]=='i') htmlImage = 1; else { fprintf(stderr, "JPEGSIZE 1.2 - display characteristics of JPEG and GIF images\nUsage: %s [-csitd] [file ...]\n -c show comments\n -s image size (default if no other options specified)\n -i generate html tags\n -t show file type\n -d debug (show blocks etc.) -d -d for extra detail\n", argv[-1]); exit(1); } } if (!debug && !showComment && !showType) showSize = 1; if (debug || htmlImage) { showSize = 0; showComment = 0; showType = 0; } if (argc<=1) { filename = "???"; process(stdin); } for (i=1; i2 && !htmlImage)) printf("%s: ", argv[i]); if (debug) printf("\n"); filename = argv[i]; f = fopen(filename, "rb"); if (f==NULL) { fprintf(stderr, "Failed to open '%s'\n", filename); exit(1); } process(f); fclose(f); } } void process(FILE *file) { int c1, c2; comment = NULL; H = -1; V = -1; if (file==NULL || ferror(file)) exit(2); c1 = fgetc(file); c2 = fgetc(file); if (c1==DELIM && c2==SOI) { if (showType) printf("JPEG\n"); processJPEG(file); } else if (c1=='G' && c2=='I') processGIF(file); else { int pos = 1; int c = 0; while (! feof(file)) { c = fgetc(file); ++pos; if (c==DELIM) { if ((c=fgetc(file)) == SOI) break; else ungetc(c, file); } } if (c==SOI) { if (showType) printf("JPEG (offset %d)\n", pos-1); else printf("Found JPEG marker after %d bytes\n", pos-1); processJPEG(file); } else { printf("Not a JPEG or GIF file\n"); return; } } if (showSize) printf("%d %d\n", H, V); if (htmlImage) printf("\n", filename, H, V); if (showComment) printf("%s\n", comment?comment:""); } /**************************** JPEG **************************/ void processJPEG(FILE *file) { endMarker = 0; while (readblock(file)) ; if (!endMarker) printf("Missing end marker\n"); } int readword(FILE *file) { return fgetc(file)*256 + fgetc(file); } int readblock(FILE *file) { int i, type, start, length; int a,b,c,x,y; unsigned char buffer[256]; int read; int h,v; if (fgetc(file) != DELIM) { printf("Expecting a block start delimeter at %ld\n", ftell(file)); return 0; } type = fgetc(file); start = ftell(file); if (typeRST7) { length = readword(file) - 2; if (feof(file)) length = 0; } else length = 0; if (debug) printf(" Type %s (%x), length %d\n", type_name(type), type, length); switch (type) { case SOF0: case SOF2: a = fgetc(file); V = readword(file); H = readword(file); if (debug) printf(" %d V=%d H=%d\n", a,V,H); break; case COM: for (i=0; i0) { fseek(file, -2L, SEEK_CUR); if (debug) printf(" (%d bytes of data read)\n", read-2); return 1; } } } while (c!=EOF); if (debug) printf(" (%d bytes of data read)\n", read-2); return 0; case EOI: endMarker = 1; if (! feof(file)) printf("Extraneous data after end marker\n"); break; case APP0: if (!debug) break; for (i=0; i>4)&7)+1, flags, a, b); // Global color table if (colorTable) { if (debug>1) printf(" Global color table (%d entries)%s\n", ctabSize, (flags&0x08) ? " [Sorted]" : ""); for (i=0; i<3*ctabSize; ++i) fgetc(file); } c = fgetc(file); while (!feof(file) && !endMarker) { switch(c) { case 0x2c: // Image descriptor a = readwordl(file); b = readwordl(file); c = readwordl(file); d = readwordl(file); flags = fgetc(file); if (debug) printf(" IMAGE w=%d h=%d ", c, d); if (debug && a!=0 || b!=0) printf("offset=(%d,%d) "); if (debug) printf("flags=0x%02x %s", flags, flags&0x40 ? "[Interlaced] " : ""); ++images; colorTable = flags & 0x80; bpp = (flags & 0x07) + 1; ctabSize = 1<1) printf(" Local color table (%d entries)%s\n", ctabSize, (flags&0x20) ? " [Sorted]" : ""); for (i=0; i<3*ctabSize; ++i) fgetc(file); } // Table based image data c = fgetc(file); subblocks = 0; totalsize = 0; while ((s=fgetc(file)) > 0) { ++subblocks; totalsize += s; for (i=0; i1) printf(" (LZW mcs = %d)\n", c); break; case 0x21: // Extension { c = fgetc(file); size = fgetc(file); subblocks = 1; for (i=0; i 0) { ++subblocks; for (i=0; i1) printf(" (Extension type 0x%02x, %d block(s), %d bytes)\n", c, subblocks, totalsize); switch(c) { case 0xfe: // Comment comment = strdup((char*)buffer); if (debug) printf(" Comment '%s'\n", comment); break; case 0xff: // Application extension if (debug) { printf(" Application extension '%.8s' [%02x %02x %02x] ", buffer, buffer[8], buffer[9], buffer[10]); for (i=11; i>2)&7 ); if (buffer[0]&2) printf(" UserInput"); if (buffer[0]&1) printf(" Transparent (index=%d)", buffer[3]); printf("\n"); } transparent |= (buffer[0]&1); break; case 0x01: // Plain text extension if (debug) printf(" Plain text '%s'\n", buffer+12); break; default: if (debug==1) printf(" Extension type 0x%02x, %d block(s), %d bytes\n", c, subblocks, totalsize); } break; } case 0x3b: // Trailer c = fgetc(file); if (debug>1) printf(" Trailer\n"); endMarker = 1; if (! feof(file)) printf("Extraneous data (0x%02x) after end marker\n", c); break; default: printf("Unknown block 0x%02x\n", c); break; } c = fgetc(file); } if (!endMarker) printf("Missing end marker\n"); if (debug) printf(" %d image(s) in total\n", images); if (showType) { printf("GIF%s", ver); if (transparent) printf(" Transparent"); if (images != 1) printf(" (%d images)", images); printf("\n"); } }