home *** CD-ROM | disk | FTP | other *** search
/ Compressed Image File Formats / CompressedImageFileFormatsJohnMiano.iso / pc / Examples / c05 / src / jpegdump.cpp
Encoding:
C/C++ Source or Header  |  1998-12-17  |  17.6 KB  |  656 lines

  1. //
  2. // Copyright (c) 1997,1998 Colosseum Builders, Inc.
  3. // All rights reserved.
  4. //
  5. // Colosseum Builders, Inc. makes no warranty, expressed or implied
  6. // with regards to this software. It is provided as is.
  7. //
  8. // See the README.TXT file that came with this software for restrictions
  9. // on the use and redistribution of this file or send E-mail to
  10. // info@colosseumbuilders.com
  11. //
  12.  
  13. //
  14. //  Title: JPEGDump
  15. //
  16. //  Author:  John M. Miano
  17. //
  18. //  Description:
  19. //
  20. //    This is a simple application for displaying the block structure
  21. //    of a JFIF (JPEG) file.
  22. //
  23. //    jpegdump filename.jpg
  24. //
  25.  
  26. #include <fstream>
  27. #include <iostream>
  28. #include <iomanip>
  29. #include <string.h>
  30. #include <errno.h>
  31.  
  32. using namespace std ;
  33.  
  34. #include "datatype.h"
  35. #include "jpmarker.h"
  36. #include "jfif.h"
  37.  
  38.  
  39. // This function reads a single byte from the input stream.
  40. UBYTE1 ReadByte (istream &strm)
  41. {
  42.   UBYTE1 data ;
  43.   strm.read ((char*) &data, sizeof (data)) ;
  44.   return data ;
  45. }
  46.  
  47. // This function returns the next two byte integer in the input stream in
  48. // the correct format for the processor.
  49. UBYTE2 ReadWord (istream &strm)
  50. {
  51.   UBYTE1 hi = ReadByte (strm) ;
  52.   UBYTE1 lo = ReadByte (strm) ;
  53.   return (hi << 8 | lo) ;
  54. }
  55.  
  56. // This function dumps the contents of a start of frame or DHP marker to the
  57. // output stream. The start of frame marker defines the size of the image,
  58. // the number of components, and the attributes of the components.
  59. void ReadStartOfFrame (istream &strm, unsigned int type)
  60. {
  61.   if (type == DHP)
  62.   {
  63.     cout << "( Define Hierarchical Progression" << endl ;
  64.   }
  65.   else
  66.   {
  67.     cout << "{ Start Of Frame " << endl ;
  68.     switch (type)
  69.     {
  70.     case SOF0:
  71.       cout << "  Type: Baseline (Huffman)" << endl ;
  72.       break ;
  73.     case SOF1:
  74.       cout << "  Type: Sequential DCT (Huffman)" << endl ;
  75.       break ;
  76.     case SOF2:
  77.       cout << "  Type: Progressive DCT (Huffman)" << endl ;
  78.       break ;
  79.     case SOF3:
  80.       cout << "  Type: Spatial (sequential) lossless (Huffman)" << endl ;
  81.       break ;
  82.     case SOF5:
  83.       cout << "  Type: Differential Sequential DCT" << endl ;
  84.       break ;
  85.     case SOF6:
  86.       cout << "  Type: Differential Progressive DCT" << endl ;
  87.       break ;
  88.     case SOF7:
  89.       cout << "  Type: Differential Spatial" << endl ;
  90.       break ;
  91.     case SOF9:
  92.       cout << "  Type: Extended Sequential DCT" << endl ;
  93.       break ;
  94.     case SOFA:
  95.       cout << "  Type: Progressive DCT" << endl ;
  96.       break ;
  97.     case SOFB:
  98.       cout << "  Type: Spacial (sequential) Lossless (Arithmetic)" << endl ;
  99.       break ;
  100.     case SOFD:
  101.       cout << "  Type: Differential Sequential DCT (Arithmetic)" << endl ;
  102.       break ;
  103.     case SOFE:
  104.       cout << "  Type: Differential Progressive DCT (Arithmetic)" << endl ;
  105.       break ;
  106.     case SOFF:
  107.       cout << "  Type: Differential Spatial (Arithmetic)" << endl ;
  108.       break ;
  109.     }
  110.   }
  111.   // Section B.2.2 (SOF)
  112.   // Section B.3.2 (DHP - which says is identical to B.2.2)
  113.  
  114.   cout << "  Length: " << dec << ReadWord (strm) << endl ;
  115.   cout << "  Precision: " << dec << (unsigned int)ReadByte (strm) << endl ; // P in standard
  116.   cout << "  Height: " << dec << ReadWord (strm) << endl ;            // Y in standard
  117.   cout << "  Width: " << dec << ReadWord (strm) << endl ;             // X in standard
  118.   int component_count = ReadByte (strm) ;     // Nf in standard
  119.   cout << "  Component Count: " << component_count << endl ;
  120.  
  121.   for (int ii = 0 ; ii < component_count ; ++ ii)
  122.   {
  123.     cout << "   Component " << (unsigned int) ReadByte (strm) << endl ; // Ci in standard
  124.     UBYTE1 data = ReadByte (strm) ;
  125.     cout << "    Horizontal Frequency: " << (data >> 4) << endl ; // Hi in standard
  126.     cout << "    Vertical Frequency: " << (data & 0xF) << endl ; // Vi in standard
  127.     cout << "    Quantization Table: " << (unsigned int) ReadByte (strm) << endl ;  // Tqi in standard
  128.   }
  129.   cout << "}" << endl ;
  130.   return ;
  131. }
  132.  
  133. // This function dumps the contents of a DHT marker to the output stream.
  134. // Huffman tables are stored in two parts. First there is an array containing
  135. // 16 values where each value is the count of codes for with a given length.
  136. // The next is a variable array that contains the Huffman values. The number
  137. // of values is the sum of all the counts.
  138. void ReadDefineHuffmanTables (istream &strm)
  139. {
  140.   unsigned int jj ;
  141.  
  142.   cout << "{ Define Huffman Table" << endl ;
  143.  
  144.   // Section B.2.4.2
  145.  
  146.    UBYTE2 length = ReadWord (strm) ;
  147.    cout << "  Length: " << dec << length << endl ;
  148.    int remaining = length - sizeof (length) ;
  149.    while (remaining > 0 && ! strm.eof ())
  150.    {
  151.       UBYTE1 data = ReadByte (strm) ; -- remaining ;
  152.       unsigned int tableclass = data >> 4 ;    // Tc in standard 0=>DC, 1=>AC
  153.       unsigned int id = data & 0x0F ;          // Th in standard
  154.  
  155.       cout << "   Table Index " << (int) id << endl ;
  156.       if (tableclass == 0)
  157.         cout << "    Table Class: DC" << endl ;
  158.       else
  159.         cout << "    Table Class: AC" << endl ;
  160.  
  161.       cout << "    Code Counts: " ;
  162.       int count = 0 ;
  163.       for (jj = 0 ; jj < 16 ; ++ jj)
  164.       {
  165.         UBYTE1 codecount = ReadByte (strm) ;
  166.         // These values are called Li in the standard.
  167.         cout << hex << (unsigned int) codecount << " " ; -- remaining ;
  168.         count += codecount ;
  169.       }
  170.       cout << endl ;
  171.       cout << "    Code Values: " ;
  172.       for (jj = 0 ; jj < count ; ++ jj)
  173.       {
  174.         // These values are called Vi in the standard.
  175.         if (jj % 16 == 0 && jj != 0)
  176.           cout << endl << "                 " ;
  177.         cout << setw (2) << hex << (unsigned int) ReadByte (strm)
  178.              << " "  ; -- remaining ;
  179.       }
  180.       cout << endl ;
  181.    }
  182.    if (remaining < 0)
  183.     cout << "-- Error in block size -- " << - remaining << endl ;
  184.    cout << "}" << endl ;
  185.  
  186.    return ;
  187. }
  188.  
  189. // This function reads a DAC block from the input stream. Since Arithmetic
  190. // coding is covered by patents we ignore the contents and just dump them
  191. // to the output stream.
  192. void ReadDefineArithmeticCoding (istream &strm)
  193. {
  194.   // The actual format is in B.2.4.3
  195.  
  196.   cout << "{ Define Arithmetic Coding " << endl ;
  197.   unsigned int length = ReadWord (strm) ;
  198.   cout << "  Length: " << dec << length << endl ;
  199.  
  200.   int count = 0 ;
  201.   for (length -= sizeof (length) ; length > 0 ; -- length)
  202.   {
  203.     cout << " " << hex << (int) ReadByte (strm) ;
  204.     if (count >= 15)
  205.     {
  206.       count = 0 ;
  207.       cout << endl ;
  208.     }
  209.     else
  210.     {
  211.       ++ count ;
  212.     }
  213.   }
  214.   cout << "}" << endl ;
  215.   return ;
  216. }
  217.  
  218. // This function reads an SOS marker and dumps its contents to the output
  219. // stream. The scan data immediately follows the header but the data is not
  220. // dumped here.
  221. void ReadStartOfScan (istream &strm)
  222. {
  223.   cout << "{ Start Of Scan " << endl ;
  224.   // Section B.2.3
  225.  
  226.   cout << "  Length:  " << dec << ReadWord (strm) << endl ;
  227.  
  228.   int scan_component_count = ReadByte (strm) ;  // Ns in standard
  229.   cout << "  Scan Count: " << dec << scan_component_count << endl ;
  230.   for (int ii = 0 ; ii < scan_component_count ; ++ ii)
  231.   {
  232.     cout << "   Component ID: " << dec << (unsigned int) ReadByte (strm) << endl ;  // Csi in standard
  233.     UBYTE1 rb = ReadByte (strm) ;
  234.     cout << "    AC Entropy Table: " << dec << (rb & 0x0F) << endl  ;  // Tai in standard
  235.     cout << "    DC Entropy Table: " << dec << (rb >> 4) << endl  ;    // Tdi in standard
  236.   }
  237.  
  238.   cout << "  Spectral Selection Start: " << dec << (unsigned int) ReadByte (strm) << endl ; // Ss in standard
  239.   cout << "  Spectral Selection End: " << dec << (unsigned int) ReadByte (strm) << endl ;  // Se in standard
  240.   UBYTE1 ssa = ReadByte (strm) ;
  241.   cout << "  Sucessive Approximation High: " << dec <<(ssa >> 4) << endl ;  // Ah in standard
  242.   cout << "  Sucessive Approximation Low: " <<  dec << (ssa & 0x0F) << endl  ; // Al in standard
  243.  
  244.   cout << "}" << endl ;
  245.   return ;
  246. }
  247.  
  248. // This function reads the contents of a DQT marker and dumps it to the
  249. // output stream. The quantization values can either be 8 or 16 bits. The
  250. // values are stored in the file in zigzag order.
  251. void ReadDefineQuantizationTable (istream &strm)
  252. {
  253.   cout << "{ Define Quantization Table" << endl ;
  254.   // Defined in Section B.2.4.1
  255.  
  256.   UBYTE2 length = ReadWord (strm) ;
  257.  
  258.   UBYTE1 data ;
  259.   int remaining = length - sizeof (length) ;
  260.   cout << "  Length:  " << dec << length << endl ;
  261.  
  262.   while (remaining > 0)
  263.   {
  264.     data = ReadByte (strm) ; -- remaining ;
  265.     unsigned int precision = data >> 4 ;    // Pq in standard
  266.     unsigned int index = data & 0x0F ;      // Tq in standard
  267.     cout << "  Table Index: " << dec << index << endl ;
  268.     cout << "  Table Precision: " << dec << precision << endl ;
  269.  
  270.     cout << "  Table Values: " ;
  271.     if ((precision & 0xF0) != 0)
  272.     {
  273.       for (unsigned int ii = 0 ; ii < 64 ;)
  274.       {
  275.         cout << endl << "        " ;
  276.         for (int jj = 0 ; jj < 8 && ii < 64 ; ++ ii, ++ jj)
  277.         {
  278.           cout << dec << ReadWord (strm) << " " ;
  279.           remaining -= 2 ;
  280.         }
  281.       }
  282.     }
  283.     else
  284.     {
  285.       for (unsigned int ii = 0 ; ii < 64 ;)
  286.       {
  287.         cout << endl << "        "  ;
  288.         for (int jj = 0 ; jj < 8 && ii < 64 ; ++ ii, ++ jj)
  289.         {
  290.           cout << dec << (unsigned int) ReadByte (strm) << " " ;
  291.           -- remaining ;
  292.         }
  293.       }
  294.     }
  295.     cout << endl ;
  296.   }
  297.  
  298.   cout << endl << "}" << endl ;
  299.   return ;
  300. }
  301.  
  302. // This function reads a DNL marker from the stream.
  303. void ReadDefineNumberOfLines (istream &strm)
  304. {
  305.   // Defined in Section B.2.5
  306.   cout << "{ Define Number of Lines" << endl ;
  307.   cout << "  Length: " << dec << ReadWord (strm) << endl ; // Should be 4
  308.   cout << "  Number of Lines: " << dec << ReadWord (strm) << endl ;
  309.   cout << "}" << endl ;
  310.   return ;
  311. }
  312.  
  313. // This function reads a DRI marker from the input stream.
  314. void ReadDefineRestartInterval (istream &strm)
  315. {
  316.   cout << "{ Define Restart Interval" << endl ;
  317.   // Defined in Section B.2.4.4
  318.   cout << "  Length:  " << dec << ReadWord (strm) << endl ; // Should be 4
  319.   cout << "  Interval: " << dec << ReadWord (strm) << endl ;
  320.   cout << "}" << endl ;
  321.   return ;
  322. }
  323.  
  324. // This function reads an EXP marker from the input stream.
  325. void ReadExpandReferenceComponents (istream &strm)
  326. {
  327.   cout << "{ Expand Reference Components" << endl ;
  328.   cout << "  Length: " << ReadWord (strm) << endl ; // Should be 3 ;
  329.   UBYTE1 exp = ReadByte (strm) ;
  330.   if ((exp & 0xF0) == 0)
  331.     cout << "  Expand Horizontally: False" << endl ;
  332.   else
  333.     cout << "  Expand Horizontally: True" << endl ;
  334.   if ((exp & 0x0F) == 0)
  335.     cout << "  Expand Vertically: False" << endl ;
  336.   else
  337.     cout << "  Expand Vertically: True" << endl ;
  338.   return ;
  339. }
  340.  
  341. // This function reads a JFIF header.
  342. void ReadApp0 (istream &strm)
  343. {
  344.   cout << "{ APP0 Marker" << endl ;
  345.  
  346.   // Information for decoding the APP0 block comes from:
  347.   // JPEG File Interchange Format
  348.   // Version 1.02
  349.  
  350.   JfifHeader header ;
  351.   strm.read ((char *) &header, sizeof (header)) ;
  352.  
  353.   cout << "  Length: " << dec << BigEndianToSystem (header.length) << endl ;
  354.  
  355.   cout << "  Version: " << dec << (unsigned int) header.version [0] << "." << (unsigned int) header.version [0] << endl ;
  356.  
  357.   // density unit = 0 => Only the aspect ratio is specified.
  358.   // density unit = 1 => Density in pixels per inch.
  359.   // density unit = 2 => Density in pixels per centimeter.
  360.   cout << "  Density Unit: " ;
  361.   switch (header.units)
  362.   {
  363.   case 0:
  364.     cout << " (aspect ratio)" << endl ;
  365.     break ;
  366.   case 1:
  367.     cout << " (pixels per inch)" << endl ;
  368.     break ;
  369.   case 2:
  370.     cout << " (pixels/cm)" << endl ;
  371.     break ;
  372.   default:
  373.     cout << " (????)" << endl ;
  374.     break ;
  375.   }
  376.   cout << "  X Density: " << dec << BigEndianToSystem (header.xdensity) << endl ;
  377.   cout << "  Y Density: " << dec << BigEndianToSystem (header.xdensity) << endl ;
  378.  
  379.   cout << "  Thumbnail Width: " << dec << (unsigned int) header.xthumbnail << endl ;
  380.   cout << "  Thumbnail Height: " << dec << (unsigned int) header.xthumbnail << endl ;
  381.  
  382.   for (int ii = sizeof (header) ; ii < BigEndianToSystem (header.length) ; ++ ii)
  383.     (void) ReadByte (strm) ;
  384.  
  385.   cout << "}" << endl ;
  386.     return ;
  387. }
  388. // This function read an APPx or COM marker from the input stream and
  389. // dumps its contents.
  390. void ReadApp (istream &strm, unsigned int data)
  391. {
  392.   switch (data)
  393.   {
  394.   case APP1:
  395.     cout << "{ APP1 Marker" << endl ;
  396.     break ;
  397.   case APP2:
  398.     cout << "{ APP2 Marker" << endl ;
  399.     break ;
  400.   case APP3:
  401.     cout << "{ APP3 Marker" << endl ;
  402.     break ;
  403.   case APP4:
  404.     cout << "{ APP4 Marker" << endl ;
  405.     break ;
  406.   case APP5:
  407.     cout << "{ APP5 Marker" << endl ;
  408.     break ;
  409.   case APP6:
  410.     cout << "{ APP6 Marker" << endl ;
  411.     break ;
  412.   case APP7:
  413.     cout << "{ APP7 Marker" << endl ;
  414.     break ;
  415.   case APP8:
  416.     cout << "{ APP8 Marker" << endl ;
  417.     break ;
  418.   case APP9:
  419.     cout << "{ APP9 Marker" << endl ;
  420.     break ;
  421.   case APPA:
  422.     cout << "{ APPA Marker" << endl ;
  423.     break ;
  424.   case APPB:
  425.     cout << "{ APPB Marker" << endl ;
  426.     break ;
  427.   case APPC:
  428.     cout << "{ APPC Marker" << endl ;
  429.     break ;
  430.   case APPD:
  431.     cout << "{ APPD Marker" << endl ;
  432.     break ;
  433.   case APPE:
  434.     cout << "{ APPE Marker" << endl ;
  435.     break ;
  436.   case APPF:
  437.     cout << "{ APPF Marker" << endl ;
  438.     break ;
  439.   case COM:
  440.     cout << "{ Comment Marker" << endl ;
  441.     break ;
  442.   }
  443.  
  444.   // Defined in Section B.2.4.5 (COM)
  445.   // Defined in Section B.2.4.6 (APPx)
  446.  
  447.   char buffer [512] ;
  448.   UBYTE2 length = ReadWord (strm) ;
  449.   cout << "  Length: " << dec << length << endl ;
  450.  
  451.   volatile int ii = 0 ;
  452.   buffer [ii] = ReadByte (strm) ;
  453.   for (ii = 1 ; buffer [ii - 1] != '\000'
  454.                 && ii < sizeof (buffer)
  455.                 && ii < length - sizeof (length) ; ++ ii)
  456.   {
  457.     buffer [ii] = ReadByte (strm) ;
  458.   }
  459.  
  460.   cout << buffer << endl ;
  461.   // If there are any remaining header bytes then send them to the
  462.   // bit bucket.
  463.   for ( ; ii < length - sizeof (length) ; ++ ii)
  464.     (void) ReadByte (strm) ;
  465.   cout << "}" << endl ;
  466.   return ;
  467. }
  468.  
  469. void ReadMarker (istream &strm, bool verbose)
  470. {
  471.   // Find the next marker in the input stream. Dump data that is not a
  472.   // marker. We expect to dump raw data following a SOS marker. We
  473.   // also dump data when we have a bad marker.
  474.   UBYTE1 data = ReadByte (strm) ;
  475.   if (data != SOB)
  476.   {
  477.     unsigned int count = 0 ;
  478.     while (data != SOB)
  479.     {
  480. ff00: // Special case of FF00 marker
  481.       if (strm.eof ())
  482.         return ;
  483.       if (verbose)
  484.       {
  485.         cout << hex << (unsigned int) data << " " ;
  486.         if (count >= 15)
  487.         {
  488.           cout << endl ;
  489.           count = 0 ;
  490.         }
  491.         else
  492.         {
  493.           ++ count ;
  494.         }
  495.       }
  496.       data = ReadByte (strm) ;
  497.     }
  498.     data = ReadByte (strm) ;
  499.     if (data == 0)
  500.     {
  501.       // FF00 is used to represent the value FF in the output stream.
  502.       data = 0xFF ;
  503.       goto ff00 ;
  504.     }
  505.     cout << endl ;
  506.   }
  507.   else
  508.   {
  509.     data = ReadByte (strm) ;
  510.     // According to E.1.2, 0xFF is allowed as fill when a marker is
  511.     // expected.
  512.     while (data == SOB && ! strm.eof ())
  513.       data = ReadByte (strm) ;
  514.   }
  515.   switch (data)
  516.   {
  517.   case SOF0:
  518.   case SOF1:
  519.   case SOF2:
  520.   case SOF3:
  521.   case SOF5:
  522.   case SOF6:
  523.   case SOF7:
  524.   case SOF9:
  525.   case SOFA:
  526.   case SOFB:
  527.   case SOFD:
  528.   case SOFE:
  529.   case SOFF:
  530.   case DHP:
  531.     ReadStartOfFrame (strm, data) ;
  532.     break ;
  533.   case DHT:
  534.     ReadDefineHuffmanTables (strm) ;
  535.     break ;
  536.   case DAC:
  537.     ReadDefineArithmeticCoding (strm) ;
  538.     break ;
  539.   case RST0:
  540.     cout << "{ Restart 0 }" << endl ;
  541.     break ;
  542.   case RST1:
  543.     cout << "{ Restart 1 }" << endl ;
  544.     break ;
  545.   case RST2:
  546.     cout << "{ Restart 2 }" << endl ;
  547.     break ;
  548.   case RST3:
  549.     cout << "{ Restart 3 }" << endl ;
  550.     break ;
  551.   case RST4:
  552.     cout << "{ Restart 4 }" << endl ;
  553.     break ;
  554.   case RST5:
  555.     cout << "{ Restart 5 }" << endl ;
  556.     break ;
  557.   case RST6:
  558.     cout << "{ Restart 6 }" << endl ;
  559.     break ;
  560.   case RST7:
  561.     cout << "{ Restart 7 }" << endl ;
  562.     break ;
  563.   case SOI:
  564.     cout << "{ Start Of Image }" << endl ;
  565.     break ;
  566.   case EOI:
  567.     cout << "{ End Of Image }" << endl ;
  568.     break ;
  569.   case SOS:
  570.     ReadStartOfScan (strm) ;
  571.     break ;
  572.   case DQT:
  573.     ReadDefineQuantizationTable (strm) ;
  574.     break ;
  575.   case DNL:
  576.     ReadDefineNumberOfLines (strm) ;
  577.     break ;
  578.   case DRI:
  579.     ReadDefineRestartInterval (strm) ;
  580.     break ;
  581.   case EXP:
  582.     ReadExpandReferenceComponents (strm) ;
  583.     break ;
  584.   case APP0:
  585.     ReadApp0 (strm) ;
  586.     break ;
  587.   case APP1:
  588.   case APP2:
  589.   case APP3:
  590.   case APP4:
  591.   case APP5:
  592.   case APP6:
  593.   case APP7:
  594.   case APP8:
  595.   case APP9:
  596.   case APPA:
  597.   case APPB:
  598.   case APPC:
  599.   case APPD:
  600.   case APPE:
  601.   case APPF:
  602.   case COM:
  603.     ReadApp (strm, data) ;
  604.   }
  605.   return ;
  606. }
  607.  
  608. void Usage (char *program)
  609. {
  610.   cerr << "Usage: " << program << " [options] file-name" << endl << flush ;
  611.   cerr << " -V Verbose (Dump Raw Data)" << endl ;
  612.   return ;
  613. }
  614.  
  615. main (int argc, char *argv [])
  616. {
  617.   ifstream strm ;
  618.   bool verbose = false ;
  619.  
  620.   int argn ;
  621.   for (argn = 1 ; argn < argc && argv [argn][0] == '-' ; ++ argn)
  622.   {
  623.     if (strcmp (argv [argn], "-v") == 0)
  624.       verbose = true ;
  625.     else
  626.     {
  627.       Usage (argv [0]) ;
  628.       return 1 ;
  629.     }
  630.   }
  631.   if (argn == argc)
  632.   {
  633.     Usage (argv [0]) ;
  634.     return 1 ;
  635.   }
  636.  
  637.   for ( ; argn < argc ; ++ argn)
  638.   {
  639.     strm.open (argv [argn], ios::binary) ;
  640.     if (! strm)
  641.     {
  642.       cerr << "Can't open file '" << argv [1] << "'" << endl
  643.            << strerror (errno) << endl << flush ;
  644.       return errno ;
  645.     }
  646.  
  647.     while (! strm.eof ())
  648.       ReadMarker (strm, verbose) ;
  649.  
  650.     strm.close () ;
  651.   }
  652.  
  653.   return 0 ;
  654. }
  655.  
  656.