ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

rdjpgcom.c
Go to the documentation of this file.
00001 /*
00002  * rdjpgcom.c
00003  *
00004  * Copyright (C) 1994-1997, Thomas G. Lane.
00005  * Modified 2009 by Bill Allombert, Guido Vollbeding.
00006  * This file is part of the Independent JPEG Group's software.
00007  * For conditions of distribution and use, see the accompanying README file.
00008  *
00009  * This file contains a very simple stand-alone application that displays
00010  * the text in COM (comment) markers in a JFIF file.
00011  * This may be useful as an example of the minimum logic needed to parse
00012  * JPEG markers.
00013  */
00014 
00015 #define JPEG_CJPEG_DJPEG    /* to get the command-line config symbols */
00016 #include "jinclude.h"       /* get auto-config symbols, <stdio.h> */
00017 
00018 #ifdef HAVE_LOCALE_H
00019 #include <locale.h>     /* Bill Allombert: use locale for isprint */
00020 #endif
00021 #include <ctype.h>      /* to declare isupper(), tolower() */
00022 #ifdef USE_SETMODE
00023 #include <fcntl.h>      /* to declare setmode()'s parameter macros */
00024 /* If you have setmode() but not <io.h>, just delete this line: */
00025 #include <io.h>         /* to declare setmode() */
00026 #endif
00027 
00028 #ifdef USE_CCOMMAND     /* command-line reader for Macintosh */
00029 #ifdef __MWERKS__
00030 #include <SIOUX.h>              /* Metrowerks needs this */
00031 #include <console.h>        /* ... and this */
00032 #endif
00033 #ifdef THINK_C
00034 #include <console.h>        /* Think declares it here */
00035 #endif
00036 #endif
00037 
00038 #ifdef DONT_USE_B_MODE      /* define mode parameters for fopen() */
00039 #define READ_BINARY "r"
00040 #else
00041 #ifdef VMS          /* VMS is very nonstandard */
00042 #define READ_BINARY "rb", "ctx=stm"
00043 #else               /* standard ANSI-compliant case */
00044 #define READ_BINARY "rb"
00045 #endif
00046 #endif
00047 
00048 #ifndef EXIT_FAILURE        /* define exit() codes if not provided */
00049 #define EXIT_FAILURE  1
00050 #endif
00051 #ifndef EXIT_SUCCESS
00052 #ifdef VMS
00053 #define EXIT_SUCCESS  1     /* VMS is very nonstandard */
00054 #else
00055 #define EXIT_SUCCESS  0
00056 #endif
00057 #endif
00058 
00059 
00060 /*
00061  * These macros are used to read the input file.
00062  * To reuse this code in another application, you might need to change these.
00063  */
00064 
00065 static FILE * infile;       /* input JPEG file */
00066 
00067 /* Return next input byte, or EOF if no more */
00068 #define NEXTBYTE()  getc(infile)
00069 
00070 
00071 /* Error exit handler */
00072 #define ERREXIT(msg)  (fprintf(stderr, "%s\n", msg), exit(EXIT_FAILURE))
00073 
00074 
00075 /* Read one byte, testing for EOF */
00076 static int
00077 read_1_byte (void)
00078 {
00079   int c;
00080 
00081   c = NEXTBYTE();
00082   if (c == EOF)
00083     ERREXIT("Premature EOF in JPEG file");
00084   return c;
00085 }
00086 
00087 /* Read 2 bytes, convert to unsigned int */
00088 /* All 2-byte quantities in JPEG markers are MSB first */
00089 static unsigned int
00090 read_2_bytes (void)
00091 {
00092   int c1, c2;
00093 
00094   c1 = NEXTBYTE();
00095   if (c1 == EOF)
00096     ERREXIT("Premature EOF in JPEG file");
00097   c2 = NEXTBYTE();
00098   if (c2 == EOF)
00099     ERREXIT("Premature EOF in JPEG file");
00100   return (((unsigned int) c1) << 8) + ((unsigned int) c2);
00101 }
00102 
00103 
00104 /*
00105  * JPEG markers consist of one or more 0xFF bytes, followed by a marker
00106  * code byte (which is not an FF).  Here are the marker codes of interest
00107  * in this program.  (See jdmarker.c for a more complete list.)
00108  */
00109 
00110 #define M_SOF0  0xC0        /* Start Of Frame N */
00111 #define M_SOF1  0xC1        /* N indicates which compression process */
00112 #define M_SOF2  0xC2        /* Only SOF0-SOF2 are now in common use */
00113 #define M_SOF3  0xC3
00114 #define M_SOF5  0xC5        /* NB: codes C4 and CC are NOT SOF markers */
00115 #define M_SOF6  0xC6
00116 #define M_SOF7  0xC7
00117 #define M_SOF9  0xC9
00118 #define M_SOF10 0xCA
00119 #define M_SOF11 0xCB
00120 #define M_SOF13 0xCD
00121 #define M_SOF14 0xCE
00122 #define M_SOF15 0xCF
00123 #define M_SOI   0xD8        /* Start Of Image (beginning of datastream) */
00124 #define M_EOI   0xD9        /* End Of Image (end of datastream) */
00125 #define M_SOS   0xDA        /* Start Of Scan (begins compressed data) */
00126 #define M_APP0  0xE0        /* Application-specific marker, type N */
00127 #define M_APP12 0xEC        /* (we don't bother to list all 16 APPn's) */
00128 #define M_COM   0xFE        /* COMment */
00129 
00130 
00131 /*
00132  * Find the next JPEG marker and return its marker code.
00133  * We expect at least one FF byte, possibly more if the compressor used FFs
00134  * to pad the file.
00135  * There could also be non-FF garbage between markers.  The treatment of such
00136  * garbage is unspecified; we choose to skip over it but emit a warning msg.
00137  * NB: this routine must not be used after seeing SOS marker, since it will
00138  * not deal correctly with FF/00 sequences in the compressed image data...
00139  */
00140 
00141 static int
00142 next_marker (void)
00143 {
00144   int c;
00145   int discarded_bytes = 0;
00146 
00147   /* Find 0xFF byte; count and skip any non-FFs. */
00148   c = read_1_byte();
00149   while (c != 0xFF) {
00150     discarded_bytes++;
00151     c = read_1_byte();
00152   }
00153   /* Get marker code byte, swallowing any duplicate FF bytes.  Extra FFs
00154    * are legal as pad bytes, so don't count them in discarded_bytes.
00155    */
00156   do {
00157     c = read_1_byte();
00158   } while (c == 0xFF);
00159 
00160   if (discarded_bytes != 0) {
00161     fprintf(stderr, "Warning: garbage data found in JPEG file\n");
00162   }
00163 
00164   return c;
00165 }
00166 
00167 
00168 /*
00169  * Read the initial marker, which should be SOI.
00170  * For a JFIF file, the first two bytes of the file should be literally
00171  * 0xFF M_SOI.  To be more general, we could use next_marker, but if the
00172  * input file weren't actually JPEG at all, next_marker might read the whole
00173  * file and then return a misleading error message...
00174  */
00175 
00176 static int
00177 first_marker (void)
00178 {
00179   int c1, c2;
00180 
00181   c1 = NEXTBYTE();
00182   c2 = NEXTBYTE();
00183   if (c1 != 0xFF || c2 != M_SOI)
00184     ERREXIT("Not a JPEG file");
00185   return c2;
00186 }
00187 
00188 
00189 /*
00190  * Most types of marker are followed by a variable-length parameter segment.
00191  * This routine skips over the parameters for any marker we don't otherwise
00192  * want to process.
00193  * Note that we MUST skip the parameter segment explicitly in order not to
00194  * be fooled by 0xFF bytes that might appear within the parameter segment;
00195  * such bytes do NOT introduce new markers.
00196  */
00197 
00198 static void
00199 skip_variable (void)
00200 /* Skip over an unknown or uninteresting variable-length marker */
00201 {
00202   unsigned int length;
00203 
00204   /* Get the marker parameter length count */
00205   length = read_2_bytes();
00206   /* Length includes itself, so must be at least 2 */
00207   if (length < 2)
00208     ERREXIT("Erroneous JPEG marker length");
00209   length -= 2;
00210   /* Skip over the remaining bytes */
00211   while (length > 0) {
00212     (void) read_1_byte();
00213     length--;
00214   }
00215 }
00216 
00217 
00218 /*
00219  * Process a COM marker.
00220  * We want to print out the marker contents as legible text;
00221  * we must guard against non-text junk and varying newline representations.
00222  */
00223 
00224 static void
00225 process_COM (int raw)
00226 {
00227   unsigned int length;
00228   int ch;
00229   int lastch = 0;
00230 
00231   /* Bill Allombert: set locale properly for isprint */
00232 #ifdef HAVE_LOCALE_H
00233   setlocale(LC_CTYPE, "");
00234 #endif
00235 
00236   /* Get the marker parameter length count */
00237   length = read_2_bytes();
00238   /* Length includes itself, so must be at least 2 */
00239   if (length < 2)
00240     ERREXIT("Erroneous JPEG marker length");
00241   length -= 2;
00242 
00243   while (length > 0) {
00244     ch = read_1_byte();
00245     if (raw) {
00246       putc(ch, stdout);
00247     /* Emit the character in a readable form.
00248      * Nonprintables are converted to \nnn form,
00249      * while \ is converted to \\.
00250      * Newlines in CR, CR/LF, or LF form will be printed as one newline.
00251      */
00252     } else if (ch == '\r') {
00253       printf("\n");
00254     } else if (ch == '\n') {
00255       if (lastch != '\r')
00256     printf("\n");
00257     } else if (ch == '\\') {
00258       printf("\\\\");
00259     } else if (isprint(ch)) {
00260       putc(ch, stdout);
00261     } else {
00262       printf("\\%03o", ch);
00263     }
00264     lastch = ch;
00265     length--;
00266   }
00267   printf("\n");
00268 
00269   /* Bill Allombert: revert to C locale */
00270 #ifdef HAVE_LOCALE_H
00271   setlocale(LC_CTYPE, "C");
00272 #endif
00273 }
00274 
00275 
00276 /*
00277  * Process a SOFn marker.
00278  * This code is only needed if you want to know the image dimensions...
00279  */
00280 
00281 static void
00282 process_SOFn (int marker)
00283 {
00284   unsigned int length;
00285   unsigned int image_height, image_width;
00286   int data_precision, num_components;
00287   const char * process;
00288   int ci;
00289 
00290   length = read_2_bytes();  /* usual parameter length count */
00291 
00292   data_precision = read_1_byte();
00293   image_height = read_2_bytes();
00294   image_width = read_2_bytes();
00295   num_components = read_1_byte();
00296 
00297   switch (marker) {
00298   case M_SOF0:  process = "Baseline";  break;
00299   case M_SOF1:  process = "Extended sequential";  break;
00300   case M_SOF2:  process = "Progressive";  break;
00301   case M_SOF3:  process = "Lossless";  break;
00302   case M_SOF5:  process = "Differential sequential";  break;
00303   case M_SOF6:  process = "Differential progressive";  break;
00304   case M_SOF7:  process = "Differential lossless";  break;
00305   case M_SOF9:  process = "Extended sequential, arithmetic coding";  break;
00306   case M_SOF10: process = "Progressive, arithmetic coding";  break;
00307   case M_SOF11: process = "Lossless, arithmetic coding";  break;
00308   case M_SOF13: process = "Differential sequential, arithmetic coding";  break;
00309   case M_SOF14: process = "Differential progressive, arithmetic coding"; break;
00310   case M_SOF15: process = "Differential lossless, arithmetic coding";  break;
00311   default:  process = "Unknown";  break;
00312   }
00313 
00314   printf("JPEG image is %uw * %uh, %d color components, %d bits per sample\n",
00315      image_width, image_height, num_components, data_precision);
00316   printf("JPEG process: %s\n", process);
00317 
00318   if (length != (unsigned int) (8 + num_components * 3))
00319     ERREXIT("Bogus SOF marker length");
00320 
00321   for (ci = 0; ci < num_components; ci++) {
00322     (void) read_1_byte();   /* Component ID code */
00323     (void) read_1_byte();   /* H, V sampling factors */
00324     (void) read_1_byte();   /* Quantization table number */
00325   }
00326 }
00327 
00328 
00329 /*
00330  * Parse the marker stream until SOS or EOI is seen;
00331  * display any COM markers.
00332  * While the companion program wrjpgcom will always insert COM markers before
00333  * SOFn, other implementations might not, so we scan to SOS before stopping.
00334  * If we were only interested in the image dimensions, we would stop at SOFn.
00335  * (Conversely, if we only cared about COM markers, there would be no need
00336  * for special code to handle SOFn; we could treat it like other markers.)
00337  */
00338 
00339 static int
00340 scan_JPEG_header (int verbose, int raw)
00341 {
00342   int marker;
00343 
00344   /* Expect SOI at start of file */
00345   if (first_marker() != M_SOI)
00346     ERREXIT("Expected SOI marker first");
00347 
00348   /* Scan miscellaneous markers until we reach SOS. */
00349   for (;;) {
00350     marker = next_marker();
00351     switch (marker) {
00352       /* Note that marker codes 0xC4, 0xC8, 0xCC are not, and must not be,
00353        * treated as SOFn.  C4 in particular is actually DHT.
00354        */
00355     case M_SOF0:        /* Baseline */
00356     case M_SOF1:        /* Extended sequential, Huffman */
00357     case M_SOF2:        /* Progressive, Huffman */
00358     case M_SOF3:        /* Lossless, Huffman */
00359     case M_SOF5:        /* Differential sequential, Huffman */
00360     case M_SOF6:        /* Differential progressive, Huffman */
00361     case M_SOF7:        /* Differential lossless, Huffman */
00362     case M_SOF9:        /* Extended sequential, arithmetic */
00363     case M_SOF10:       /* Progressive, arithmetic */
00364     case M_SOF11:       /* Lossless, arithmetic */
00365     case M_SOF13:       /* Differential sequential, arithmetic */
00366     case M_SOF14:       /* Differential progressive, arithmetic */
00367     case M_SOF15:       /* Differential lossless, arithmetic */
00368       if (verbose)
00369     process_SOFn(marker);
00370       else
00371     skip_variable();
00372       break;
00373 
00374     case M_SOS:         /* stop before hitting compressed data */
00375       return marker;
00376 
00377     case M_EOI:         /* in case it's a tables-only JPEG stream */
00378       return marker;
00379 
00380     case M_COM:
00381       process_COM(raw);
00382       break;
00383 
00384     case M_APP12:
00385       /* Some digital camera makers put useful textual information into
00386        * APP12 markers, so we print those out too when in -verbose mode.
00387        */
00388       if (verbose) {
00389     printf("APP12 contains:\n");
00390     process_COM(raw);
00391       } else
00392     skip_variable();
00393       break;
00394 
00395     default:            /* Anything else just gets skipped */
00396       skip_variable();      /* we assume it has a parameter count... */
00397       break;
00398     }
00399   } /* end loop */
00400 }
00401 
00402 
00403 /* Command line parsing code */
00404 
00405 static const char * progname;   /* program name for error messages */
00406 
00407 
00408 static void
00409 usage (void)
00410 /* complain about bad command line */
00411 {
00412   fprintf(stderr, "rdjpgcom displays any textual comments in a JPEG file.\n");
00413 
00414   fprintf(stderr, "Usage: %s [switches] [inputfile]\n", progname);
00415 
00416   fprintf(stderr, "Switches (names may be abbreviated):\n");
00417   fprintf(stderr, "  -raw        Display non-printable characters in comments (unsafe)\n");
00418   fprintf(stderr, "  -verbose    Also display dimensions of JPEG image\n");
00419 
00420   exit(EXIT_FAILURE);
00421 }
00422 
00423 
00424 static int
00425 keymatch (char * arg, const char * keyword, int minchars)
00426 /* Case-insensitive matching of (possibly abbreviated) keyword switches. */
00427 /* keyword is the constant keyword (must be lower case already), */
00428 /* minchars is length of minimum legal abbreviation. */
00429 {
00430   register int ca, ck;
00431   register int nmatched = 0;
00432 
00433   while ((ca = *arg++) != '\0') {
00434     if ((ck = *keyword++) == '\0')
00435       return 0;         /* arg longer than keyword, no good */
00436     if (isupper(ca))        /* force arg to lcase (assume ck is already) */
00437       ca = tolower(ca);
00438     if (ca != ck)
00439       return 0;         /* no good */
00440     nmatched++;         /* count matched characters */
00441   }
00442   /* reached end of argument; fail if it's too short for unique abbrev */
00443   if (nmatched < minchars)
00444     return 0;
00445   return 1;         /* A-OK */
00446 }
00447 
00448 
00449 /*
00450  * The main program.
00451  */
00452 
00453 int
00454 main (int argc, char **argv)
00455 {
00456   int argn;
00457   char * arg;
00458   int verbose = 0, raw = 0;
00459 
00460   /* On Mac, fetch a command line. */
00461 #ifdef USE_CCOMMAND
00462   argc = ccommand(&argv);
00463 #endif
00464 
00465   progname = argv[0];
00466   if (progname == NULL || progname[0] == 0)
00467     progname = "rdjpgcom";  /* in case C library doesn't provide it */
00468 
00469   /* Parse switches, if any */
00470   for (argn = 1; argn < argc; argn++) {
00471     arg = argv[argn];
00472     if (arg[0] != '-')
00473       break;            /* not switch, must be file name */
00474     arg++;          /* advance over '-' */
00475     if (keymatch(arg, "verbose", 1)) {
00476       verbose++;
00477     } else if (keymatch(arg, "raw", 1)) {
00478       raw = 1;
00479     } else
00480       usage();
00481   }
00482 
00483   /* Open the input file. */
00484   /* Unix style: expect zero or one file name */
00485   if (argn < argc-1) {
00486     fprintf(stderr, "%s: only one input file\n", progname);
00487     usage();
00488   }
00489   if (argn < argc) {
00490     if ((infile = fopen(argv[argn], READ_BINARY)) == NULL) {
00491       fprintf(stderr, "%s: can't open %s\n", progname, argv[argn]);
00492       exit(EXIT_FAILURE);
00493     }
00494   } else {
00495     /* default input file is stdin */
00496 #ifdef USE_SETMODE      /* need to hack file mode? */
00497     setmode(fileno(stdin), O_BINARY);
00498 #endif
00499 #ifdef USE_FDOPEN       /* need to re-open in binary mode? */
00500     if ((infile = fdopen(fileno(stdin), READ_BINARY)) == NULL) {
00501       fprintf(stderr, "%s: can't open stdin\n", progname);
00502       exit(EXIT_FAILURE);
00503     }
00504 #else
00505     infile = stdin;
00506 #endif
00507   }
00508 
00509   /* Scan the JPEG headers. */
00510   (void) scan_JPEG_header(verbose, raw);
00511 
00512   /* All done. */
00513   exit(EXIT_SUCCESS);
00514   return 0;         /* suppress no-return-value warnings */
00515 }

Generated on Sat May 26 2012 04:18:14 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.