home *** CD-ROM | disk | FTP | other *** search
/ Compressed Image File Formats / CompressedImageFileFormatsJohnMiano.iso / pc / Examples / c13 / src / pngdump.cpp
Encoding:
C/C++ Source or Header  |  1998-12-18  |  8.5 KB  |  325 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: PNG Dump Application
  15. //
  16. //  Author:  John M. Miano miano@colosseumbuilders.com
  17. //
  18. //  Description:
  19. //
  20. //    This is a simple application that prints the structure of a PNG file
  21. //    to cout.
  22. //
  23. //    pngdump filename.png
  24. //
  25.  
  26. #include <iostream>
  27. #include <fstream>
  28. #include <errno.h>
  29. #include <string>
  30. #include <stdexcept>
  31.  
  32. #include "datatype.h"
  33. #include "pngpvt.h"
  34.  
  35. using namespace std ;
  36.  
  37. UBYTE4 CrcTable [256] ;
  38. UBYTE4 Register ;
  39.  
  40. UBYTE1 CurrentChunkType [5] ;
  41. UBYTE1 *ChunkData ;
  42. UBYTE4 ChunkDataLength ;
  43. UBYTE4 ChunkBufferSize ;
  44. unsigned int ChunkCount ;
  45. bool IENDReached ;
  46. bool PLTEReached ;
  47. unsigned int LastIDATChunk ;
  48.  
  49. PngImageHeader ImageHeader ;
  50.  
  51. unsigned long CrcRegister ;
  52. void CrcByte (unsigned char data)
  53. {
  54.   unsigned int index = (CrcRegister ^ data) & 0xFF ;
  55.   CrcRegister = CrcTable [index] ^ ((CrcRegister >> 8) & 0x00FFFFFF) ;
  56.   return ;
  57. }
  58.  
  59. unsigned long Crc (UBYTE1 type [5], UBYTE1 buffer [], unsigned int length)
  60. {
  61.   CrcRegister = 0xFFFFFFFFL ;
  62.   for (unsigned int ii = 0 ; ii < 4 ; ++ ii)
  63.     CrcByte (type [ii]) ;
  64.  
  65.   for (unsigned int jj = 0 ; jj < length ; ++ jj)
  66.     CrcByte (buffer [jj]) ;
  67.  
  68.   return ~CrcRegister ;
  69. }
  70.  
  71. void MakeCrcTable ()
  72. {
  73.   for (unsigned int ii = 0 ; ii < 256 ; ++ ii)
  74.   {
  75.     CrcTable [ii] = ii ;
  76.     for (unsigned int jj = 0 ; jj < 8 ; ++ jj)
  77.     {
  78.       if ((CrcTable [ii] & 0x1) == 0)
  79.         CrcTable [ii] >>= 1 ;
  80.       else
  81.         CrcTable [ii] = 0xEDB88320L ^ (CrcTable [ii] >> 1) ;
  82.     }
  83.   }
  84.   return ;
  85. }
  86.  
  87. UBYTE4 ReadLong (istream &strm)
  88. {
  89.   UBYTE4 data ;
  90.   strm.read ((char *) &data, sizeof (data)) ;
  91.   return BigEndianToSystem (data) ;
  92. }
  93.  
  94. void ReadSignature (istream &strm)
  95. {
  96.   static const int sigsize = 8 ;
  97.   static const unsigned char signature [sigsize] = { 137, 80, 78, 71, 13,
  98.                                                      10, 26, 10, } ;
  99.   char sigbuf [sigsize] ;
  100.  
  101.   strm.read (sigbuf, sigsize) ;
  102.   if (memcmp (sigbuf, signature, sigsize) != 0)
  103.     cout << "*** PNG Signature Invalid ***" << endl ;
  104.   return ;
  105. }
  106.  
  107. void ProcessHeader (istream &strm)
  108. {
  109.   PngImageHeader *header = (PngImageHeader *) ChunkData ;
  110.   ImageHeader = *header ;
  111.  
  112.   if (ChunkCount != 0)
  113.     cout << "*** IHDR must be the first chunk ***" << endl ;
  114.   if (ChunkDataLength != sizeof (PngImageHeader))
  115.     cout << "*** Invalid IHDR Chunk Length ***" << endl ;
  116.  
  117.   cout << "  Image Size: " << dec << BigEndianToSystem (header->height)
  118.        << " x " << dec << BigEndianToSystem (header->width) << endl ;
  119.   cout << "  Bit Depth: " << (int) header->bitdepth << endl ;
  120.   switch (header->colortype)
  121.   {
  122.   case 0:
  123.     cout << "  Color Type: Grayscale" << endl ;
  124.     switch (header->bitdepth)
  125.     {
  126.     case 1: case 2: case 4: case 8: case 16: break ;
  127.     default:
  128.       cout << "Bad Bitdepth (" << header->bitdepth << ") for Color Type" << endl ;
  129.     }
  130.     break ;
  131.   case 2:
  132.     cout << "  Color Type: RGB Triple" << endl ;
  133.     if (header->bitdepth != 8 && header->bitdepth != 16)
  134.       cout << "*** Bad Bitdepth for Color Type ***" << endl ;
  135.     break ;
  136.   case 3:
  137.     cout << "  Color Type: Palette Index" << endl ;
  138.     switch (header->bitdepth)
  139.     {
  140.     case 1: case 2: case 4: case 8: break ;
  141.     default:
  142.       cout << "*** Bad Bitdepth (" << header->bitdepth << ") for Color Type ***"
  143.            << endl ;
  144.     }
  145.     break ;
  146.   case 4:
  147.     cout << "  Color Type: Grayscale/Alpha" << endl ;
  148.     if (header->bitdepth != 8 && header->bitdepth != 16)
  149.       cout << "*** Bad Bitdepth (" << header->bitdepth << ") for Color Type ***"
  150.            << endl ;
  151.     break ;
  152.   case 6:
  153.     cout << " Color Type: RGB/Alpha" << endl ;
  154.     if (header->bitdepth != 8 && header->bitdepth != 16)
  155.       cout << "*** Bad Bitdepth (" << header->bitdepth << ") for Color Type ***"
  156.            << endl ;
  157.     break ;
  158.   default:
  159.     cout << "*** Invalid Color Type (" << header->colortype << ") ***" << endl ;
  160.   }
  161.   if (header->compressionmethod == 0)
  162.   {
  163.     cout << "  Compression Method: deflate/inflate"
  164.          << endl ;
  165.   }
  166.   else
  167.   {
  168.     cerr << "Invalid Compression Method (" << header->compressionmethod << ")" << endl ;
  169.   }
  170.  
  171.   if (header->filtermethod == 0)
  172.   {
  173.     cout << "  Filter Method: adaptive" << endl ;
  174.   }
  175.   else
  176.   {
  177.     cout << "*** Invalid Filter Method (" << header->filtermethod << ") ***"
  178.          << endl ;
  179.   }
  180.  
  181.   switch (header->interlacemethod)
  182.   {
  183.   case 0:
  184.     cout << "  Interlace Method:  none" << endl ;
  185.     break ;
  186.   case 1:
  187.     cout << "  Interlace Method:  Adam7" << endl ;
  188.     break ;
  189.   default:
  190.     cout << "*** Invalid Interlace Method ("
  191.          << header->interlacemethod << ") ***" << endl ;
  192.   }
  193.   return ;
  194. }
  195.  
  196. void ProcessIDAT (istream &strm)
  197. {
  198.   if (LastIDATChunk != 0 && LastIDATChunk != ChunkCount - 1)
  199.     cout << "*** IDAT blocks are not consecutive. ***" << endl ;
  200.   if (ImageHeader.colortype == Palette && ! PLTEReached)
  201.     cout << "*** IDAT requires PLTE chunk for this color type. ***" << endl ;
  202.   LastIDATChunk = ChunkCount ;
  203.   return ;
  204. }
  205.  
  206. void ProcessPalette (istream &strm)
  207. {
  208.   if (PLTEReached)
  209.     cout << "*** File contains multiple PLTE Chunks ***" << endl ;
  210.   if (ChunkDataLength % 3 != 0)
  211.     cout << "*** PLTE Block length not divisible by 3 ***" << endl ;
  212.   if (ChunkDataLength > 3 * (1 << ImageHeader.bitdepth) ||
  213.       ChunkDataLength > 256 * 3)
  214.     cout << "*** PLTE Block length too large ***" << endl ;
  215.   if (LastIDATChunk != 0)
  216.     cout << "*** PLTE May not occur after the first IDAT chunk ***" << endl ;
  217.   if (ImageHeader.colortype == Grayscale
  218.       || ImageHeader.colortype == GrayscaleAlpha)
  219.     cout << "*** PLTE May not occur with Grayscale or Grayscale"
  220.          << " with Alpha Channel. ***" << endl ;
  221.  
  222.   PLTEReached = true ;
  223.   struct PaletteEntry
  224.   {
  225.     UBYTE1 red ;
  226.     UBYTE1 green ;
  227.     UBYTE1 blue ;
  228.   } palette [256] ;
  229.  
  230.   unsigned int colorcount = ChunkDataLength / 3 ;
  231.  
  232.   cout << "  Palette Color Count: " << colorcount << endl ;
  233.   memcpy (palette, ChunkData, colorcount * sizeof (PaletteEntry));
  234.   return ;
  235. }
  236.  
  237. void ReadBlock (istream &strm)
  238. {
  239.   ChunkDataLength = ReadLong (strm) ;
  240.   if (strm.eof ())
  241.     return ;
  242.   if (ChunkDataLength > ChunkBufferSize)
  243.   {
  244.     ChunkBufferSize = ChunkDataLength ;
  245.  
  246.     delete [] ChunkData ;
  247.     ChunkData = new UBYTE1 [ChunkBufferSize] ;
  248.   }
  249.   strm.read ((char*)CurrentChunkType, 4) ;
  250.   strm.read ((char*) ChunkData, ChunkDataLength) ;
  251.  
  252.  
  253.   UBYTE4 datacrc = Crc (CurrentChunkType, ChunkData, ChunkDataLength) ;
  254.   UBYTE4 filecrc = ReadLong (strm) ;
  255.  
  256.   cout << "{ " << CurrentChunkType << endl ;
  257.   cout << "  Data Length: " << ChunkDataLength << endl ;
  258.   cout << "  Data CRC:    " << hex << datacrc << endl ;
  259.   cout << "  File CRC:    " << hex << filecrc << endl ;
  260.   if (filecrc != datacrc)
  261.     cout << "*** Chunk CRC is Incorrect ***" << endl ;
  262.  
  263.   UBYTE4 numericcode = ChunkType ((char*) CurrentChunkType) ;
  264.   if (ChunkCount == 0 && numericcode != ChunkType ("IHDR"))
  265.     cout << "*** First chunk is not IHDR ***" << endl ;
  266.   if (IENDReached)
  267.     cout << "*** Chunk follows IEND ***" << endl ;
  268.  
  269.   if (numericcode == ChunkType ("IHDR"))
  270.   {
  271.     ProcessHeader (strm) ;
  272.   }
  273.   else if (numericcode == ChunkType ("IDAT"))
  274.   {
  275.     ProcessIDAT (strm) ;
  276.   }
  277.   else if (numericcode == ChunkType ("PLTE"))
  278.   {
  279.     ProcessPalette (strm) ;
  280.   }
  281.   else if (numericcode == ChunkType ("IEND"))
  282.   {
  283.     IENDReached = true ;
  284.     if (LastIDATChunk == 0)
  285.       cout << "*** Image Contains No IDAT chunks ***" << endl ;
  286.     if (ChunkDataLength != 0)
  287.       cout << "*** IEND Chunk may not contain data ***" << endl ;
  288.   }
  289.   else
  290.   {
  291.   }
  292.   cout << "}" << endl ;
  293.   return ;
  294. }
  295.  
  296. main (int argc, char *argv [])
  297. {
  298.   if (argc != 2)
  299.   {
  300.     cerr << "Usage: " << argv [0] << " filename" << endl ;
  301.     return 1 ;
  302.   }
  303.  
  304.   ifstream in (argv [1], ios::binary) ;
  305.   if (! in)
  306.   {
  307.     cerr << "Can't open file " << argv [1] << endl ;
  308.     cerr << strerror (errno) << endl ;
  309.     return errno ;
  310.   }
  311.  
  312.   MakeCrcTable () ;
  313.   try
  314.   {
  315.     ReadSignature (in) ;
  316.     for (ChunkCount = 0 ; ! in.eof () ; ++ ChunkCount)
  317.       ReadBlock (in) ;
  318.   }
  319.   catch (exception &ee)
  320.   {
  321.     cerr << ee.what () << endl ;
  322.   }
  323.   return 0 ;
  324. }
  325.