home *** CD-ROM | disk | FTP | other *** search
- //
- // Copyright (c) 1997,1998 Colosseum Builders, Inc.
- // All rights reserved.
- //
- // Colosseum Builders, Inc. makes no warranty, expressed or implied
- // with regards to this software. It is provided as is.
- //
- // See the README.TXT file that came with this software for restrictions
- // on the use and redistribution of this file or send E-mail to
- // info@colosseumbuilders.com
- //
-
- //
- // Title: PNG Dump Application
- //
- // Author: John M. Miano miano@colosseumbuilders.com
- //
- // Description:
- //
- // This is a simple application that prints the structure of a PNG file
- // to cout.
- //
- // pngdump filename.png
- //
-
- #include <iostream>
- #include <fstream>
- #include <errno.h>
- #include <string>
- #include <stdexcept>
-
- #include "datatype.h"
- #include "pngpvt.h"
-
- using namespace std ;
-
- UBYTE4 CrcTable [256] ;
- UBYTE4 Register ;
-
- UBYTE1 CurrentChunkType [5] ;
- UBYTE1 *ChunkData ;
- UBYTE4 ChunkDataLength ;
- UBYTE4 ChunkBufferSize ;
- unsigned int ChunkCount ;
- bool IENDReached ;
- bool PLTEReached ;
- unsigned int LastIDATChunk ;
-
- PngImageHeader ImageHeader ;
-
- unsigned long CrcRegister ;
- void CrcByte (unsigned char data)
- {
- unsigned int index = (CrcRegister ^ data) & 0xFF ;
- CrcRegister = CrcTable [index] ^ ((CrcRegister >> 8) & 0x00FFFFFF) ;
- return ;
- }
-
- unsigned long Crc (UBYTE1 type [5], UBYTE1 buffer [], unsigned int length)
- {
- CrcRegister = 0xFFFFFFFFL ;
- for (unsigned int ii = 0 ; ii < 4 ; ++ ii)
- CrcByte (type [ii]) ;
-
- for (unsigned int jj = 0 ; jj < length ; ++ jj)
- CrcByte (buffer [jj]) ;
-
- return ~CrcRegister ;
- }
-
- void MakeCrcTable ()
- {
- for (unsigned int ii = 0 ; ii < 256 ; ++ ii)
- {
- CrcTable [ii] = ii ;
- for (unsigned int jj = 0 ; jj < 8 ; ++ jj)
- {
- if ((CrcTable [ii] & 0x1) == 0)
- CrcTable [ii] >>= 1 ;
- else
- CrcTable [ii] = 0xEDB88320L ^ (CrcTable [ii] >> 1) ;
- }
- }
- return ;
- }
-
- UBYTE4 ReadLong (istream &strm)
- {
- UBYTE4 data ;
- strm.read ((char *) &data, sizeof (data)) ;
- return BigEndianToSystem (data) ;
- }
-
- void ReadSignature (istream &strm)
- {
- static const int sigsize = 8 ;
- static const unsigned char signature [sigsize] = { 137, 80, 78, 71, 13,
- 10, 26, 10, } ;
- char sigbuf [sigsize] ;
-
- strm.read (sigbuf, sigsize) ;
- if (memcmp (sigbuf, signature, sigsize) != 0)
- cout << "*** PNG Signature Invalid ***" << endl ;
- return ;
- }
-
- void ProcessHeader (istream &strm)
- {
- PngImageHeader *header = (PngImageHeader *) ChunkData ;
- ImageHeader = *header ;
-
- if (ChunkCount != 0)
- cout << "*** IHDR must be the first chunk ***" << endl ;
- if (ChunkDataLength != sizeof (PngImageHeader))
- cout << "*** Invalid IHDR Chunk Length ***" << endl ;
-
- cout << " Image Size: " << dec << BigEndianToSystem (header->height)
- << " x " << dec << BigEndianToSystem (header->width) << endl ;
- cout << " Bit Depth: " << (int) header->bitdepth << endl ;
- switch (header->colortype)
- {
- case 0:
- cout << " Color Type: Grayscale" << endl ;
- switch (header->bitdepth)
- {
- case 1: case 2: case 4: case 8: case 16: break ;
- default:
- cout << "Bad Bitdepth (" << header->bitdepth << ") for Color Type" << endl ;
- }
- break ;
- case 2:
- cout << " Color Type: RGB Triple" << endl ;
- if (header->bitdepth != 8 && header->bitdepth != 16)
- cout << "*** Bad Bitdepth for Color Type ***" << endl ;
- break ;
- case 3:
- cout << " Color Type: Palette Index" << endl ;
- switch (header->bitdepth)
- {
- case 1: case 2: case 4: case 8: break ;
- default:
- cout << "*** Bad Bitdepth (" << header->bitdepth << ") for Color Type ***"
- << endl ;
- }
- break ;
- case 4:
- cout << " Color Type: Grayscale/Alpha" << endl ;
- if (header->bitdepth != 8 && header->bitdepth != 16)
- cout << "*** Bad Bitdepth (" << header->bitdepth << ") for Color Type ***"
- << endl ;
- break ;
- case 6:
- cout << " Color Type: RGB/Alpha" << endl ;
- if (header->bitdepth != 8 && header->bitdepth != 16)
- cout << "*** Bad Bitdepth (" << header->bitdepth << ") for Color Type ***"
- << endl ;
- break ;
- default:
- cout << "*** Invalid Color Type (" << header->colortype << ") ***" << endl ;
- }
- if (header->compressionmethod == 0)
- {
- cout << " Compression Method: deflate/inflate"
- << endl ;
- }
- else
- {
- cerr << "Invalid Compression Method (" << header->compressionmethod << ")" << endl ;
- }
-
- if (header->filtermethod == 0)
- {
- cout << " Filter Method: adaptive" << endl ;
- }
- else
- {
- cout << "*** Invalid Filter Method (" << header->filtermethod << ") ***"
- << endl ;
- }
-
- switch (header->interlacemethod)
- {
- case 0:
- cout << " Interlace Method: none" << endl ;
- break ;
- case 1:
- cout << " Interlace Method: Adam7" << endl ;
- break ;
- default:
- cout << "*** Invalid Interlace Method ("
- << header->interlacemethod << ") ***" << endl ;
- }
- return ;
- }
-
- void ProcessIDAT (istream &strm)
- {
- if (LastIDATChunk != 0 && LastIDATChunk != ChunkCount - 1)
- cout << "*** IDAT blocks are not consecutive. ***" << endl ;
- if (ImageHeader.colortype == Palette && ! PLTEReached)
- cout << "*** IDAT requires PLTE chunk for this color type. ***" << endl ;
- LastIDATChunk = ChunkCount ;
- return ;
- }
-
- void ProcessPalette (istream &strm)
- {
- if (PLTEReached)
- cout << "*** File contains multiple PLTE Chunks ***" << endl ;
- if (ChunkDataLength % 3 != 0)
- cout << "*** PLTE Block length not divisible by 3 ***" << endl ;
- if (ChunkDataLength > 3 * (1 << ImageHeader.bitdepth) ||
- ChunkDataLength > 256 * 3)
- cout << "*** PLTE Block length too large ***" << endl ;
- if (LastIDATChunk != 0)
- cout << "*** PLTE May not occur after the first IDAT chunk ***" << endl ;
- if (ImageHeader.colortype == Grayscale
- || ImageHeader.colortype == GrayscaleAlpha)
- cout << "*** PLTE May not occur with Grayscale or Grayscale"
- << " with Alpha Channel. ***" << endl ;
-
- PLTEReached = true ;
- struct PaletteEntry
- {
- UBYTE1 red ;
- UBYTE1 green ;
- UBYTE1 blue ;
- } palette [256] ;
-
- unsigned int colorcount = ChunkDataLength / 3 ;
-
- cout << " Palette Color Count: " << colorcount << endl ;
- memcpy (palette, ChunkData, colorcount * sizeof (PaletteEntry));
- return ;
- }
-
- void ReadBlock (istream &strm)
- {
- ChunkDataLength = ReadLong (strm) ;
- if (strm.eof ())
- return ;
- if (ChunkDataLength > ChunkBufferSize)
- {
- ChunkBufferSize = ChunkDataLength ;
-
- delete [] ChunkData ;
- ChunkData = new UBYTE1 [ChunkBufferSize] ;
- }
- strm.read ((char*)CurrentChunkType, 4) ;
- strm.read ((char*) ChunkData, ChunkDataLength) ;
-
-
- UBYTE4 datacrc = Crc (CurrentChunkType, ChunkData, ChunkDataLength) ;
- UBYTE4 filecrc = ReadLong (strm) ;
-
- cout << "{ " << CurrentChunkType << endl ;
- cout << " Data Length: " << ChunkDataLength << endl ;
- cout << " Data CRC: " << hex << datacrc << endl ;
- cout << " File CRC: " << hex << filecrc << endl ;
- if (filecrc != datacrc)
- cout << "*** Chunk CRC is Incorrect ***" << endl ;
-
- UBYTE4 numericcode = ChunkType ((char*) CurrentChunkType) ;
- if (ChunkCount == 0 && numericcode != ChunkType ("IHDR"))
- cout << "*** First chunk is not IHDR ***" << endl ;
- if (IENDReached)
- cout << "*** Chunk follows IEND ***" << endl ;
-
- if (numericcode == ChunkType ("IHDR"))
- {
- ProcessHeader (strm) ;
- }
- else if (numericcode == ChunkType ("IDAT"))
- {
- ProcessIDAT (strm) ;
- }
- else if (numericcode == ChunkType ("PLTE"))
- {
- ProcessPalette (strm) ;
- }
- else if (numericcode == ChunkType ("IEND"))
- {
- IENDReached = true ;
- if (LastIDATChunk == 0)
- cout << "*** Image Contains No IDAT chunks ***" << endl ;
- if (ChunkDataLength != 0)
- cout << "*** IEND Chunk may not contain data ***" << endl ;
- }
- else
- {
- }
- cout << "}" << endl ;
- return ;
- }
-
- main (int argc, char *argv [])
- {
- if (argc != 2)
- {
- cerr << "Usage: " << argv [0] << " filename" << endl ;
- return 1 ;
- }
-
- ifstream in (argv [1], ios::binary) ;
- if (! in)
- {
- cerr << "Can't open file " << argv [1] << endl ;
- cerr << strerror (errno) << endl ;
- return errno ;
- }
-
- MakeCrcTable () ;
- try
- {
- ReadSignature (in) ;
- for (ChunkCount = 0 ; ! in.eof () ; ++ ChunkCount)
- ReadBlock (in) ;
- }
- catch (exception &ee)
- {
- cerr << ee.what () << endl ;
- }
- return 0 ;
- }
-