home *** CD-ROM | disk | FTP | other *** search
/ Computer Shopper 275 / DPCS0111DVD.ISO / Toolkit / Audio-Visual / VirtualDub / Source / VirtualDub-1.9.10-src.7z / src / Meia / source / decode_png.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2009-09-14  |  12.1 KB  |  441 lines

  1. //    VirtualDub - Video processing and capture application
  2. //    Video decoding library
  3. //    Copyright (C) 1998-2004 Avery Lee
  4. //
  5. //    This program is free software; you can redistribute it and/or modify
  6. //    it under the terms of the GNU General Public License as published by
  7. //    the Free Software Foundation; either version 2 of the License, or
  8. //    (at your option) any later version.
  9. //
  10. //    This program is distributed in the hope that it will be useful,
  11. //    but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. //    GNU General Public License for more details.
  14. //
  15. //    You should have received a copy of the GNU General Public License
  16. //    along with this program; if not, write to the Free Software
  17. //    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  
  19. #include <vd2/system/error.h>
  20. #include <vd2/system/vdtypes.h>
  21. #include <vd2/system/vdstl.h>
  22. #include <vd2/system/zip.h>
  23. #include <vd2/system/binary.h>
  24. #include <vd2/Kasumi/pixmap.h>
  25. #include <vd2/Kasumi/pixmaputils.h>
  26. #include <vd2/Meia/decode_png.h>
  27. #include "common_png.h"
  28. #include <stdio.h>
  29.  
  30. using namespace nsVDPNG;
  31.  
  32. ///////////////////////////////////////////////////////////////////////////
  33.  
  34. namespace {
  35.     struct PNGHeader {
  36.         uint32    width;
  37.         uint32    height;
  38.         uint8    depth;
  39.         uint8    colortype;
  40.         uint8    compression;
  41.         uint8    filter;
  42.         uint8    interlacing;
  43.     };
  44.  
  45.     unsigned long PNGDecodeNetwork32(const uint8 *src) {
  46.         return (src[0]<<24) + (src[1]<<16) + (src[2]<<8) + src[3];
  47.     }
  48.  
  49.     int PNGPaethPredictor(int a, int b, int c) {
  50.         int p  = a + b - c;
  51.         int pa = abs(p - a);
  52.         int pb = abs(p - b);
  53.         int pc = abs(p - c);
  54.  
  55.         if (pa <= pb && pa <= pc)
  56.             return a;
  57.         else if (pb <= pc)
  58.             return b;
  59.         else
  60.             return c;
  61.     }
  62.  
  63.     void PNGPredictSub(uint8 *row, const uint8 *prevrow, int rowuint8s, int bpp) {
  64.         for(int i=bpp; i<rowuint8s; ++i)
  65.             row[i] += row[i-bpp];
  66.     }
  67.  
  68.     void PNGPredictUp(uint8 *row, const uint8 *prevrow, int rowbytes, int bpp) {
  69.         if (prevrow)
  70.             for(int i=0; i<rowbytes; ++i)
  71.                 row[i] += prevrow[i];
  72.     }
  73.  
  74.     void PNGPredictAverage(uint8 *row, const uint8 *prevrow, int rowbytes, int bpp) {
  75.         if (prevrow) {
  76.             for(int i=0; i<bpp; ++i)
  77.                 row[i] += prevrow[i]>>1;
  78.             for(int j=bpp; j<rowbytes; ++j)
  79.                 row[j] += (prevrow[j] + row[j-bpp])>>1;
  80.         } else {
  81.             for(int j=bpp; j<rowbytes; ++j)
  82.                 row[j] += row[j-bpp]>>1;
  83.         }
  84.     }
  85.  
  86.     void PNGPredictPaeth(uint8 *row, const uint8 *prevrow, int rowbytes, int bpp) {
  87.         if (prevrow) {
  88.             for(int i=0; i<bpp; ++i)
  89.                 row[i] += PNGPaethPredictor(0, prevrow[i], 0);
  90.             for(int j=bpp; j<rowbytes; ++j)
  91.                 row[j] += PNGPaethPredictor(row[j-bpp], prevrow[j], prevrow[j-bpp]);
  92.         } else {
  93.             for(int j=bpp; j<rowbytes; ++j)
  94.                 row[j] += PNGPaethPredictor(row[j-bpp], 0, 0);
  95.         }
  96.     }
  97.  
  98.     void PNGUnpackIndices1Bit(uint8 *dst, const uint8 *src, int w) {
  99.         uint8 v;
  100.  
  101.         dst += (w-1) & ~7;
  102.         src += (w+7)>>3;
  103.  
  104.         v = *--src;
  105.  
  106.         switch(w & 7) {
  107.                 while(w > 0) {
  108.                     v = *--src;
  109.         case 0:        dst[7] = (v   )&1;
  110.         case 7:        dst[6] = (v>>1)&1;
  111.         case 6:        dst[5] = (v>>2)&1;
  112.         case 5:        dst[4] = (v>>3)&1;
  113.         case 4:        dst[3] = (v>>4)&1;
  114.         case 3:        dst[2] = (v>>5)&1;
  115.         case 2:        dst[1] = (v>>6)&1;
  116.         case 1:        dst[0] = (v>>7)&1;
  117.                     dst -= 8;
  118.                     w -= 8;
  119.                 }
  120.         }
  121.     }
  122.  
  123.     void PNGUnpackIndices2Bit(uint8 *dst, const uint8 *src, int w) {
  124.         uint8 v;
  125.  
  126.         dst += (w-1) & ~3;
  127.         src += (w+3)>>2;
  128.  
  129.         v = *--src;
  130.  
  131.         switch(w & 3) {
  132.                 while(w > 0) {
  133.                     v = *--src;
  134.         case 0:        dst[3] = (v   )&3;
  135.         case 3:        dst[2] = (v>>2)&3;
  136.         case 2:        dst[1] = (v>>4)&3;
  137.         case 1:        dst[0] = (v>>6)&3;
  138.                     dst -= 4;
  139.                     w -= 4;
  140.                 }
  141.         }
  142.     }
  143.  
  144.     void PNGUnpackIndices4Bit(uint8 *dst, const uint8 *src, int w) {
  145.         int x = w>>1;
  146.  
  147.         if (x)
  148.             do {
  149.                 dst[0] = (src[0]>>4)&15;
  150.                 dst[1] = (src[0]   )&15;
  151.                 dst += 2;
  152.                 ++src;
  153.             } while(--x);
  154.  
  155.         if (w & 1)
  156.             *dst = (*src >> 4) & 15;
  157.     }
  158. }
  159.  
  160. class VDImageDecoderPNG : public IVDImageDecoderPNG {
  161. public:
  162.     PNGDecodeError Decode(const void *src0, uint32 size);
  163.     const VDPixmap& GetFrameBuffer() { return mFrameBuffer; }
  164.  
  165. protected:
  166.     VDPixmapBuffer    mFrameBuffer;
  167. };
  168.  
  169. IVDImageDecoderPNG *VDCreateImageDecoderPNG() {
  170.     return new VDImageDecoderPNG;
  171. }
  172.  
  173. PNGDecodeError VDImageDecoderPNG::Decode(const void *src0, uint32 size) {
  174.     const uint8 *src = (const uint8 *)src0;
  175.     const uint8 *const src_end = src+size;
  176.  
  177.     if (size < 8)
  178.         return kPNGDecodeNotPNG;
  179.  
  180.     if (memcmp(src, kPNGSignature, 8))
  181.         return kPNGDecodeNotPNG;
  182.  
  183.     src += 8;
  184.  
  185.     PNGHeader hdr;
  186.  
  187.     bool header_found = false;
  188.  
  189.     vdfastvector<uint8> packeddata;
  190.     unsigned char pal[768];
  191.  
  192.     // decode chunks
  193.     VDCRCChecker checker;
  194.  
  195.     while(src < src_end) {
  196.         if (src_end-src < 12)
  197.             break;
  198.  
  199.         uint32 length = PNGDecodeNetwork32(src);
  200.  
  201.         if ((uint32)(src_end-src) < length+12)
  202.             return kPNGDecodeTruncatedChunk;
  203.  
  204.         uint32 crc = PNGDecodeNetwork32(src + length + 8);
  205.  
  206.         // verify the crc
  207.         checker.Init(VDCRCChecker::kCRC32);
  208.         checker.Process(src + 4, length + 4);
  209.         if (checker.CRC() != crc)
  210.             return kPNGDecodeChecksumFailed;
  211.  
  212.         uint32 type = PNGDecodeNetwork32(src + 4);
  213.  
  214.         if (type == 'IHDR') {
  215.             if (length < 13)
  216.                 return kPNGDecodeBadHeader;
  217.  
  218.             hdr.width        = PNGDecodeNetwork32(src+8);
  219.             hdr.height        = PNGDecodeNetwork32(src+12);
  220.             hdr.depth        = src[16];
  221.             hdr.colortype    = src[17];
  222.             hdr.compression    = src[18];
  223.             hdr.filter        = src[19];
  224.             hdr.interlacing    = src[20];
  225.  
  226.             if (hdr.compression != 0)
  227.                 return kPNGDecodeUnsupportedCompressionAlgorithm;
  228.             if (hdr.filter != 0)
  229.                 return kPNGDecodeUnsupportedFilterAlgorithm;
  230.             if (hdr.interlacing > 1)
  231.                 return kPNGDecodeUnsupportedInterlacingAlgorithm;
  232.  
  233.             header_found = true;
  234.         } else if (type == 'IDAT') {
  235.             packeddata.resize(packeddata.size()+length);
  236.             memcpy(&packeddata[packeddata.size()-length], src+8, length);
  237.         } else if (type == 'PLTE') {
  238.             if (length%3)
  239.                 return kPNGDecodeBadPalette;
  240.  
  241.             memcpy(pal, src+8, length<768?length:768);
  242.         } else if (type == 'IEND') {
  243.             break;
  244.         } else if (src[0] & 0x20) {
  245.             return kPNGDecodeUnknownRequiredChunk;
  246.         }
  247.  
  248.         src += length+12;
  249.     }
  250.  
  251.     if (!header_found)
  252.         return kPNGDecodeBadHeader;
  253.  
  254.     if (packeddata.size() < 6)
  255.         return kPNGDecodeDecompressionFailed;
  256.  
  257.     // if grayscale, initialize palette and make it paletted
  258.     if (hdr.colortype == 0) {
  259.         for(int i=0; i<256; ++i) {
  260.             pal[i*3+0] = pal[i*3+1] = pal[i*3+2] = i;
  261.         }
  262.  
  263.         hdr.colortype = 3;
  264.     }
  265.  
  266.     unsigned bitsperpixel = hdr.depth;
  267.  
  268.     switch(hdr.colortype) {
  269.     case 2:        // RGB
  270.         bitsperpixel *= 3;
  271.         break;
  272.     case 4:        // IA
  273.         bitsperpixel += 8;
  274.         break;
  275.     case 6:        // RGBA
  276.         bitsperpixel = (bitsperpixel * 3) + 8;
  277.         break;
  278.     }
  279.  
  280.     unsigned pitch = (hdr.width*3+3)&~3;
  281.     unsigned pngrowbytes    = (hdr.width * bitsperpixel + 7) >> 3;
  282.     unsigned pngbpp            = (bitsperpixel+7) >> 3;
  283.  
  284.     // decompress here
  285.     vdblock<uint8> dstbuf((pngrowbytes + 1) * hdr.height);
  286.  
  287.     VDMemoryStream packedStream(&packeddata[2], packeddata.size() - 6);
  288.     VDZipStream unpackedStream(&packedStream, packeddata.size() - 6, false);
  289.  
  290.     try {
  291.         unpackedStream.Read(dstbuf.data(), dstbuf.size());
  292.     } catch(const MyError&) {
  293.         return kPNGDecodeDecompressionFailed;
  294.     }
  295.  
  296.     // check image data
  297.     uint32 adler32 = VDReadUnalignedBEU32(packeddata.data() + packeddata.size() - 4);
  298.     if (adler32 != VDAdler32Checker::Adler32(dstbuf.data(), dstbuf.size()))
  299.         return kPNGDecodeChecksumFailed;
  300.  
  301.     mFrameBuffer.init(hdr.width, hdr.height, nsVDPixmap::kPixFormat_RGB888);
  302.  
  303.     uint8 *srcp = &dstbuf[0];
  304.     int x, y;
  305.  
  306.     vdblock<uint8> tempindices;
  307.  
  308.     if (hdr.colortype == 3 && hdr.depth != 8)    // If paletted and not 8bpp....
  309.         tempindices.resize(hdr.width);
  310.  
  311.     const uint8 *srcprv = NULL;
  312.     for(y=0; (uint32)y<hdr.height; ++y) {
  313.         switch(*srcp++) {
  314.         case 0:            break;
  315.         case 1:            PNGPredictSub(srcp, srcprv, pngrowbytes, pngbpp);        break;
  316.         case 2:            PNGPredictUp(srcp, srcprv, pngrowbytes, pngbpp);        break;
  317.         case 3:            PNGPredictAverage(srcp, srcprv, pngrowbytes, pngbpp);    break;
  318.         case 4:            PNGPredictPaeth(srcp, srcprv, pngrowbytes, pngbpp);        break;
  319.         default:        return kPNGDecodeBadFilterMode;
  320.         }
  321.  
  322.         const uint8 *rowsrc = srcp;
  323.               uint8 *rowdst = (uint8 *)vdptroffset(mFrameBuffer.data, mFrameBuffer.pitch * y);
  324.  
  325.         if (hdr.colortype == 2) {                    // RGB: depths 8, 16
  326.             if (hdr.depth == 8) {
  327.                 for(x=0; (uint32)x<hdr.width; ++x) {
  328.                     rowdst[x*3+0] = rowsrc[x*3+2];
  329.                     rowdst[x*3+1] = rowsrc[x*3+1];
  330.                     rowdst[x*3+2] = rowsrc[x*3+0];
  331.                 }
  332.             } else if (hdr.depth == 16) {
  333.                 for(x=0; (uint32)x<hdr.width; ++x) {
  334.                     rowdst[x*3+0] = rowsrc[x*6+4];
  335.                     rowdst[x*3+1] = rowsrc[x*6+2];
  336.                     rowdst[x*3+2] = rowsrc[x*6+0];
  337.                 }
  338.             }
  339.         } else if (hdr.colortype == 6) {            // RGBA: depths 8, 16
  340.             if (hdr.depth == 8) {
  341.                 for(x=0; (uint32)x<hdr.width; ++x) {
  342.                     rowdst[x*3+0] = rowsrc[x*4+2];
  343.                     rowdst[x*3+1] = rowsrc[x*4+1];
  344.                     rowdst[x*3+2] = rowsrc[x*4+0];
  345.                 }
  346.             } else if (hdr.depth == 16) {
  347.                 for(x=0; (uint32)x<hdr.width; ++x) {
  348.                     rowdst[x*3+0] = rowsrc[x*8+4];
  349.                     rowdst[x*3+1] = rowsrc[x*8+2];
  350.                     rowdst[x*3+2] = rowsrc[x*8+0];
  351.                 }
  352.             }
  353.         } else if (hdr.colortype == 4) {            // grayscale with alpha: depths 8, 16
  354.             if (hdr.depth == 8) {
  355.                 for(x=0; (uint32)x<hdr.width; ++x) {
  356.                     rowdst[x*3+0] = rowdst[x*3+1] = rowdst[x*3+2] = rowsrc[x*2];
  357.                 }
  358.             } else if (hdr.depth == 16) {
  359.                 for(x=0; (uint32)x<hdr.width; ++x) {
  360.                     rowdst[x*3+0] =    rowdst[x*3+1] =    rowdst[x*3+2] = rowsrc[x*3];
  361.                 }
  362.             }
  363.         } else if (hdr.colortype == 3) {            // paletted: depths 1, 2, 4, 8
  364.             if (hdr.depth != 8) {
  365.                 switch(hdr.depth) {
  366.                 case 1:        PNGUnpackIndices1Bit(tempindices.data(), rowsrc, hdr.width);    break;
  367.                 case 2:        PNGUnpackIndices2Bit(tempindices.data(), rowsrc, hdr.width);    break;
  368.                 case 4:        PNGUnpackIndices4Bit(tempindices.data(), rowsrc, hdr.width);    break;
  369.                 }
  370.  
  371.                 rowsrc = tempindices.data();
  372.             }
  373.             for(x=0; (uint32)x<hdr.width; ++x) {
  374.                 unsigned idx = rowsrc[x];
  375.                 rowdst[x*3+0] = pal[idx*3+2];
  376.                 rowdst[x*3+1] = pal[idx*3+1];
  377.                 rowdst[x*3+2] = pal[idx*3+0];
  378.             }
  379.         }
  380.  
  381.         srcprv = srcp;
  382.         srcp += pngrowbytes;
  383.     }
  384.  
  385.     return kPNGDecodeOK;
  386. }
  387.  
  388. const char *PNGGetErrorString(PNGDecodeError err) {
  389.     switch(err) {
  390.     case kPNGDecodeOK:                                    return "No error.";
  391.     case kPNGDecodeNotPNG:                                return "Not a PNG file.";
  392.     case kPNGDecodeTruncatedChunk:                        return "A chunk in the PNG file is damaged.";
  393.     case kPNGDecodeBadHeader:                            return "The PNG header is invalid.";
  394.     case kPNGDecodeUnsupportedCompressionAlgorithm:        return "The compression algorithm used by the PNG file is not supported.";
  395.     case kPNGDecodeUnsupportedInterlacingAlgorithm:        return "The interlacing algorithm used by the PNG file is not supported.";
  396.     case kPNGDecodeUnsupportedFilterAlgorithm:            return "The filtering algorithm used by the PNG file is not supported.";
  397.     case kPNGDecodeBadPalette:                            return "The PNG palette structure is bad.";
  398.     case kPNGDecodeDecompressionFailed:                    return "A decompression error occurred while unpacking the raw PNG image data.";
  399.     case kPNGDecodeBadFilterMode:                        return "The image data specifies an unknown PNG filtering mode.";
  400.     case kPNGDecodeUnknownRequiredChunk:                return "The PNG file contains data that is required to decode the image but which this decoder does not support.";
  401.     case kPNGDecodeChecksumFailed:                        return "A chunk in the PNG file is corrupted (bad checksum).";
  402.     default:                                            return "?";
  403.     }
  404. }
  405.  
  406. bool VDDecodePNGHeader(const void *src0, uint32 len, int& w, int& h, bool& hasalpha) {
  407.     const uint8 *src = (const uint8 *)src0;
  408.  
  409.     if (len < 29)
  410.         return false;
  411.  
  412.     if (memcmp(src, kPNGSignature, 8))
  413.         return false;
  414.  
  415.     // Next four bytes must be IHDR and length >= 13
  416.     const uint32 hlen = PNGDecodeNetwork32(src + 8);
  417.     const uint32 ckid = PNGDecodeNetwork32(src + 12);
  418.  
  419.     if (ckid != 'IHDR')
  420.         return false;
  421.  
  422.     if (hlen < 13)
  423.         return false;
  424.  
  425.     PNGHeader hdr;
  426.  
  427.     hdr.width        = PNGDecodeNetwork32(src+16);
  428.     hdr.height        = PNGDecodeNetwork32(src+20);
  429.     hdr.depth        = src[24];
  430.     hdr.colortype    = src[25];
  431.     hdr.compression    = src[26];
  432.     hdr.filter        = src[27];
  433.     hdr.interlacing    = src[28];
  434.  
  435.     hasalpha = false;
  436.     w = hdr.width;
  437.     h = hdr.height;
  438.  
  439.     return true;
  440. }
  441.