jpegSize.cpp

Go to the documentation of this file.
00001 #include "jpegSize.h"
00002 
00003 #include <stdio.h>
00004 
00005 /*
00006   Most of the code that follows was adapted from IJG's rdjpgcom.c file.
00007  
00008  * Copyright (C) 1994-1997, Thomas G. Lane.
00009  * This file is part of the Independent JPEG Group's software.
00010  *
00011  * This file contains a very simple stand-alone application that displays
00012  * the text in COM (comment) markers in a JFIF file.
00013  * This may be useful as an example of the minimum logic needed to parse
00014  * JPEG markers.
00015  */
00016 
00017 /* Return next input byte, or EOF if no more */
00018 #define NEXTBYTE()  getc(infile)
00019 
00020 /*
00021  * JPEG markers consist of one or more 0xFF bytes, followed by a marker
00022  * code byte (which is not an FF).  Here are the marker codes of interest
00023  * in this program.  (See jdmarker.c for a more complete list.)
00024  */
00025 
00026 #define M_SOF0  0xC0    /* Start Of Frame N */
00027 #define M_SOF1  0xC1    /* N indicates which compression process */
00028 #define M_SOF2  0xC2    /* Only SOF0-SOF2 are now in common use */
00029 #define M_SOF3  0xC3
00030 #define M_SOF5  0xC5    /* NB: codes C4 and CC are NOT SOF markers */
00031 #define M_SOF6  0xC6
00032 #define M_SOF7  0xC7
00033 #define M_SOF9  0xC9
00034 #define M_SOF10 0xCA
00035 #define M_SOF11 0xCB
00036 #define M_SOF13 0xCD
00037 #define M_SOF14 0xCE
00038 #define M_SOF15 0xCF
00039 #define M_SOI   0xD8  /* Start Of Image (beginning of datastream) */
00040 #define M_EOI   0xD9    /* End Of Image (end of datastream) */
00041 #define M_SOS   0xDA    /* Start Of Scan (begins compressed data) */
00042 #define M_APP0  0xE0    /* Application-specific marker, type N */
00043 #define M_APP12 0xEC    /* (we don't bother to list all 16 APPn's) */
00044 #define M_COM   0xFE    /* COMment */
00045 
00046 #ifdef DONT_USE_B_MODE    /* define mode parameters for fopen() */
00047 #define READ_BINARY "r"
00048 #else
00049 #ifdef VMS      /* VMS is very nonstandard */
00050 #define READ_BINARY "rb", "ctx=stm"
00051 #else       /* standard ANSI-compliant case */
00052 #define READ_BINARY "rb"
00053 #endif
00054 #endif
00055 
00056 FILE * infile;
00057 
00058 bool process_SOFn (int& width, int& height);
00059 bool skip_variable ();
00060 bool read_1_byte (int* res);
00061 bool read_2_bytes (unsigned int* res);
00062 bool first_marker (int* res);
00063 bool next_marker (int* res);
00064 
00065 bool getJPEGSize( const char* filename, int& width, int& height )
00066 {
00067   //open file
00068   if ((infile = fopen(filename, READ_BINARY)) == NULL)
00069     return false;
00070 
00071   //this is scan_JPEG_header (int verbose)
00072   //Parse the marker stream until SOFn is seen;
00073   int marker;
00074   
00075   //Expect SOI at start of file
00076   if (!first_marker(&marker))
00077   {
00078     fclose(infile);
00079     return false;
00080   }
00081     
00082     /* Scan miscellaneous markers until we reach SOFn. */
00083   for (;;) 
00084   {
00085     if(!next_marker(&marker))
00086     {
00087       fclose(infile);
00088       return false;
00089     }
00090 
00091     switch (marker) 
00092     {
00093       /* Note that marker codes 0xC4, 0xC8, 0xCC are not, and must not be,
00094        * treated as SOFn.  C4 in particular is actually DHT.
00095        */
00096     case M_SOF0:    /* Baseline */
00097     case M_SOF1:    /* Extended sequential, Huffman */
00098     case M_SOF2:    /* Progressive, Huffman */
00099     case M_SOF3:    /* Lossless, Huffman */
00100     case M_SOF5:    /* Differential sequential, Huffman */
00101     case M_SOF6:    /* Differential progressive, Huffman */
00102     case M_SOF7:    /* Differential lossless, Huffman */
00103     case M_SOF9:    /* Extended sequential, arithmetic */
00104     case M_SOF10:   /* Progressive, arithmetic */
00105     case M_SOF11:   /* Lossless, arithmetic */
00106     case M_SOF13:   /* Differential sequential, arithmetic */
00107     case M_SOF14:   /* Differential progressive, arithmetic */
00108     case M_SOF15:   /* Differential lossless, arithmetic */      
00109       if(!process_SOFn(width, height))
00110       {
00111         fclose(infile);
00112         return false;
00113       }
00114       else
00115       {
00116         fclose(infile);
00117         return true;
00118       }
00119     case M_SOS:     /* stop before hitting compressed data */
00120     {
00121       fclose(infile);
00122       return false;
00123     }
00124     case M_EOI:     /* in case it's a tables-only JPEG stream */
00125     {
00126       fclose(infile);
00127       return false;
00128     }
00129     default:      /* Anything else just gets skipped */
00130       skip_variable();    /* we assume it has a parameter count... */
00131       break;
00132     }
00133   } /* end loop */
00134 
00135 
00136 //cout << "ERROR!\n";
00137 return false;
00138 
00139 }
00140 
00141 
00142 /*
00143  * Read the initial marker, which should be SOI.
00144  * For a JFIF file, the first two bytes of the file should be literally
00145  * 0xFF M_SOI.  To be more general, we could use next_marker, but if the
00146  * input file weren't actually JPEG at all, next_marker might read the whole
00147  * file and then return a misleading error message...
00148  */
00149 bool first_marker (int* res)
00150 {
00151   int c1, c2;
00152   c1 = NEXTBYTE();
00153   c2 = NEXTBYTE();
00154   if (c1 != 0xFF || c2 != M_SOI)
00155     return false;
00156   else
00157   {
00158     *res = c2;
00159     return true;
00160   }
00161 }
00162 
00163 /*
00164  * Find the next JPEG marker and return its marker code.
00165  * We expect at least one FF byte, possibly more if the compressor used FFs
00166  * to pad the file.
00167  * There could also be non-FF garbage between markers.  The treatment of such
00168  * garbage is unspecified; we choose to skip over it but emit a warning msg.
00169  * NB: this routine must not be used after seeing SOS marker, since it will
00170  * not deal correctly with FF/00 sequences in the compressed image data...
00171  */
00172 bool next_marker (int* res)
00173 {
00174   int c;
00175   int discarded_bytes = 0;
00176 
00177   /* Find 0xFF byte; count and skip any non-FFs. */
00178   if(!read_1_byte(&c))
00179     return false;
00180   while (c != 0xFF) 
00181   {
00182     discarded_bytes++;
00183     if(!read_1_byte(&c))
00184       return false;
00185   }
00186   /* Get marker code byte, swallowing any duplicate FF bytes.  Extra FFs
00187    * are legal as pad bytes, so don't count them in discarded_bytes.
00188    */
00189   do 
00190   {
00191     if(!read_1_byte(&c))
00192       return false;
00193   } while (c == 0xFF);
00194 
00195 //  if (discarded_bytes != 0) { cout << "Warning: garbage data found in JPEG file\n"; }
00196 
00197   *res = c;
00198   return true;
00199 }
00200 
00201 /* Read one byte, testing for EOF */
00202 bool read_1_byte (int* res)
00203 {
00204   int c = NEXTBYTE();
00205   if (c == EOF)
00206     return false;
00207   else
00208   {
00209     *res = c;
00210     return true;
00211   }
00212 }
00213 
00214 /* Read 2 bytes, convert to unsigned int */
00215 /* All 2-byte quantities in JPEG markers are MSB first */
00216 bool read_2_bytes (unsigned int* res)
00217 {
00218   int c1, c2;
00219   c1 = NEXTBYTE();
00220   if (c1 == EOF)
00221     return false;
00222   c2 = NEXTBYTE();
00223   if (c2 == EOF)
00224     return false;
00225   *res = (((unsigned int) c1) << 8) + ((unsigned int) c2);
00226   return true;
00227 }
00228 
00229 /*
00230  * Most types of marker are followed by a variable-length parameter segment.
00231  * This routine skips over the parameters for any marker we don't otherwise
00232  * want to process.
00233  * Note that we MUST skip the parameter segment explicitly in order not to
00234  * be fooled by 0xFF bytes that might appear within the parameter segment;
00235  * such bytes do NOT introduce new markers.
00236  */
00237 bool skip_variable ()
00238 /* Skip over an unknown or uninteresting variable-length marker */
00239 {
00240   unsigned int length;
00241 
00242   /* Get the marker parameter length count */
00243   if(!read_2_bytes(&length))
00244     return false;
00245   /* Length includes itself, so must be at least 2 */
00246   if (length < 2)
00247     return false;
00248   length -= 2;
00249   /* Skip over the remaining bytes */
00250   while (length > 0) 
00251   {
00252     int tmp;
00253     if(!read_1_byte(&tmp))
00254       return false;
00255     length--;
00256   }
00257   return false;
00258 }
00259 
00260 //Process a SOFn marker - get image dimensions
00261 bool process_SOFn (int& width, int& height)
00262 {
00263   unsigned int length;
00264   unsigned int image_height, image_width;
00265   int data_precision;
00266   
00267   if(!read_2_bytes(&length) ||
00268       !read_1_byte(&data_precision) ||
00269       !read_2_bytes(&image_height) ||
00270       !read_2_bytes(&image_width) )
00271       return false;
00272 
00273   width = (int) image_width;
00274   height = (int) image_height;
00275   return true;   
00276 }

Generated on Wed Jan 24 05:38:28 2007 for AlbumShaper by  doxygen 1.5.1