Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of RA8875 by
Diff: PNG.cpp
- Revision:
- 63:ed787f5fcdc4
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/PNG.cpp Sun Mar 23 16:27:55 2014 +0000
@@ -0,0 +1,1912 @@
+//#include <Windows.h>
+//#include <stdio.h>
+
+#include "PNG.h"
+#include "SlidingWindow.h"
+
+#define DEBUG "PNG "
+// ...
+// INFO("Stuff to show %d", var); // new-line is automatically appended
+//
+#if (defined(DEBUG) && !defined(TARGET_LPC11U24))
+#define INFO(x, ...) std::printf("[INF %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
+#define WARN(x, ...) std::printf("[WRN %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
+#define ERR(x, ...) std::printf("[ERR %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
+#else
+#define INFO(x, ...)
+#define WARN(x, ...)
+#define ERR(x, ...)
+#endif
+
+#if 0
+static int maxUsed = 0;
+static int usedLocs[50000];
+
+void DSTrackClear(void)
+{
+ maxUsed = 0;
+ for (int i=0; i<5000; i++)
+ usedLocs[i] = 0;
+}
+void DSTrackMax(int loc)
+{
+#if 0
+ char buf[1000];
+ sprintf(buf, "using: %5d: ", loc);
+ for (int i=0; i<loc/100; i++)
+ strcat(buf," ");
+ strcat(buf,"*\r\n");
+ OutputDebugStringA(buf);
+ if (loc > maxUsed)
+ maxUsed = loc;
+ usedLocs[loc] |= 1;
+#endif
+}
+void DSTrackReport(void)
+{
+#if 0
+ int totalUsed = 0;
+ char buf[100];
+ for (int i=0; i<5000; i++)
+ totalUsed += usedLocs[i];
+ sprintf(buf, "Highest used: %d of %d total used\r\n", maxUsed, totalUsed);
+ OutputDebugStringA(buf);
+ buf[0] = '\0';
+#endif
+}
+#endif
+
+
+
+
+// Updates
+// 2005/03/02
+// Started
+// 2005/03/03
+// Support:
+// 8bit Grayscale, True color, 4bit Indexed color, 8bit Indexed color
+// 2005/03/04
+// Added support for true color with alpha and grayscale with alpha
+// 2005/03/14
+// Support:
+// Interlaced 8bit True color
+// 2005/03/15
+// Support:
+// Interlaced/Non-Interlaced 16bit True color
+// Interlaced 8bit Grayscale
+// Interlaced 8bit Indexed color
+// Interlaced 8bit Grayscale with alpha
+// Interlaced 8bit Truecolor with alpha
+// Cleaned up a little bit.
+// 2005/04/08
+// Support:
+// Non-Interlace 1 bit Grayscale
+// 2010/09/18
+// Fixed transparency check in interlaced 16-bit true-color mode.
+// Based on a bug-report from a viewer. Thanks for the good catch!
+// 2011/12/28
+// Fixed transparent color reading based on the user-report. Thanks for the good catch!
+
+
+/* Supported color and depth
+
+Non-Interlaced
+ 1bit Grayscale
+ 4bit Indexed Color
+ 8bit Grayscale
+ 8bit Grayscale with Alpha
+ 8bit Indexed Color
+ 8bit True Color (24bit per pixel)
+ 8bit True Color with Alpha (32bit per pixel)
+ 16bit True Color (48bit per pixel)
+
+Interlaced
+ 8bit Grayscale
+ 8bit Grayscale with Alpha
+ 8bit Indexed Color
+ 8bit True color (24bit per pixel)
+ 8bit True Color with Alpha (32bit per pixel)
+ 16bit True Color (48bit per pixel)
+
+*/
+
+
+
+// Memo
+// PNG Data Format http://www.w3.org/TR/PNG
+
+
+#define MakeDword(a,b,c,d) ((a)*0x1000000+(b)*0x10000+(c)*0x100+(d))
+
+#define IHDR MakeDword('I','H','D','R')
+#define IDAT MakeDword('I','D','A','T')
+#define PLTE MakeDword('P','L','T','E')
+#define IEND MakeDword('I','E','N','D')
+#define pHYs MakeDword('p','H','y','s')
+#define tRNS MakeDword('t','R','N','S')
+#define gAMA MakeDword('g','A','M','A')
+
+static inline unsigned int PngGetUnsignedInt(const unsigned char dat[4])
+{
+ return (unsigned)dat[3]+(unsigned)dat[2]*0x100+(unsigned)dat[1]*0x10000+(unsigned)dat[0]*0x1000000;
+}
+
+////////////////////////////////////////////////////////////
+
+void YsPngHeader::Decode(unsigned char dat[])
+{
+ width=PngGetUnsignedInt(dat);
+ height=PngGetUnsignedInt(dat+4);
+ bitDepth=dat[8];
+ colorType=dat[9];
+ compressionMethod=dat[10];
+ filterMethod=dat[11];
+ interlaceMethod=dat[12];
+
+ INFO("Width=%d Height=%d",width,height);
+ INFO("bitDepth=%d",bitDepth);
+ INFO("colorType=%d",colorType);
+ INFO("compressionMethod=%d",compressionMethod);
+ INFO("filterMethod=%d",filterMethod);
+ INFO("interlaceMethod=%d",interlaceMethod);
+}
+
+YsPngPalette::YsPngPalette()
+{
+ nEntry=0;
+ entry=NULL;
+}
+
+YsPngPalette::~YsPngPalette()
+{
+ if(entry!=NULL)
+ {
+ delete [] entry;
+ }
+}
+
+int YsPngPalette::Decode(unsigned length,unsigned char dat[])
+{
+ if(length%3!=0)
+ {
+ return YSERR;
+ }
+
+ if(entry!=NULL)
+ {
+ delete [] entry;
+ nEntry=0;
+ entry=NULL;
+ }
+
+ if(length>0)
+ {
+ entry=new unsigned char [length];
+ if(entry!=NULL)
+ {
+ unsigned int i;
+ nEntry=length/3;
+
+ INFO("%d palette entries",nEntry);
+ for(i=0; i<length; i++)
+ {
+ entry[i]=dat[i];
+ }
+ }
+ }
+
+ return YSOK;
+}
+
+////////////////////////////////////////////////////////////
+
+int YsPngTransparency::Decode(unsigned int length,unsigned char dat[],unsigned int colorType)
+{
+ unsigned int i;
+ switch(colorType)
+ {
+ case 0:
+ if(length>=2)
+ {
+ col[0]=(unsigned int)dat[0]*256+(unsigned int)dat[1];
+ return YSOK;
+ }
+ break;
+ case 2:
+ if(length>=6)
+ {
+ col[0]=(unsigned int)dat[0]*256+(unsigned int)dat[1]; // 2011/12/28 Bug fix based on the user-report. Thanks!
+ col[1]=(unsigned int)dat[2]*256+(unsigned int)dat[3];
+ col[2]=(unsigned int)dat[4]*256+(unsigned int)dat[5];
+ return YSOK;
+ }
+ break;
+ case 3:
+ for(i=0; i<3 && i<length; i++)
+ {
+ col[i]=dat[i];
+ }
+ return YSOK;
+ }
+ return YSERR;
+}
+
+////////////////////////////////////////////////////////////
+
+YsGenericPngDecoder::YsGenericPngDecoder()
+{
+ Initialize();
+}
+
+void YsGenericPngDecoder::Initialize(void)
+{
+ gamma=gamma_default;
+ trns.col[0]=0x7fffffff;
+ trns.col[1]=0x7fffffff;
+ trns.col[2]=0x7fffffff;
+}
+
+int YsGenericPngDecoder::CheckSignature(FILE *fp)
+{
+ unsigned char buf[8];
+ fread(buf,1,8,fp);
+ if(buf[0]==0x89 && buf[1]==0x50 && buf[2]==0x4e && buf[3]==0x47 &&
+ buf[4]==0x0d && buf[5]==0x0a && buf[6]==0x1a && buf[7]==0x0a)
+ {
+ return YSOK;
+ }
+ return YSERR;
+}
+
+int YsGenericPngDecoder::ReadChunk(unsigned &length,unsigned char *&buf,unsigned &chunkType,unsigned &crc,FILE *fp)
+{
+ unsigned char dwBuf[4];
+
+ if(fread(dwBuf,1,4,fp)<4)
+ {
+ return YSERR;
+ }
+ length=PngGetUnsignedInt(dwBuf);
+
+ if(fread(dwBuf,1,4,fp)<4)
+ {
+ return YSERR;
+ }
+ chunkType=PngGetUnsignedInt(dwBuf);
+
+ INFO("Chunk name=%c%c%c%c",dwBuf[0],dwBuf[1],dwBuf[2],dwBuf[3]);
+
+ if(length>0)
+ {
+ buf=new unsigned char [length];
+ if(fread(buf,1,length,fp)<length)
+ {
+ return YSERR;
+ }
+ }
+ else
+ {
+ buf=NULL;
+ }
+
+ if(fread(dwBuf,1,4,fp)<4)
+ {
+ return YSERR;
+ }
+ crc=PngGetUnsignedInt(dwBuf);
+
+ return YSOK;
+}
+
+////////////////////////////////////////////////////////////
+
+int YsPngHuffmanTree::leakTracker=0;
+
+YsPngHuffmanTree::YsPngHuffmanTree()
+{
+ zero=NULL;
+ one=NULL;
+ dat=0x7fffffff;
+ weight=0;
+ depth=1;
+ leakTracker++;
+}
+
+YsPngHuffmanTree::~YsPngHuffmanTree()
+{
+ leakTracker--;
+}
+
+void YsPngHuffmanTree::DeleteHuffmanTree(YsPngHuffmanTree *node)
+{
+ if(node!=NULL)
+ {
+ DeleteHuffmanTree(node->zero);
+ DeleteHuffmanTree(node->one);
+ delete node;
+ }
+}
+
+////////////////////////////////////////////////////////////
+
+void YsPngUncompressor::MakeFixedHuffmanCode(unsigned hLength[288],unsigned hCode[288])
+{
+ unsigned i;
+ for(i=0; i<=143; i++)
+ {
+ hLength[i]=8;
+ hCode[i]=0x30+i;
+ }
+ for(i=144; i<=255; i++)
+ {
+ hLength[i]=9;
+ hCode[i]=0x190+(i-144);
+ }
+ for(i=256; i<=279; i++)
+ {
+ hLength[i]=7;
+ hCode[i]=i-256;
+ }
+ for(i=280; i<=287; i++)
+ {
+ hLength[i]=8;
+ hCode[i]=0xc0+(i-280);
+ }
+}
+
+void YsPngUncompressor::MakeDynamicHuffmanCode(unsigned hLength[],unsigned hCode[],unsigned nLng,unsigned lng[])
+{
+ unsigned i,maxLng,code,*bl_count,*next_code,bits,n;
+
+ for(i=0; i<nLng; i++)
+ {
+ hLength[i]=lng[i];
+ hCode[i]=0;
+ }
+
+ maxLng=0;
+ for(i=0; i<nLng; i++)
+ {
+ if(maxLng<lng[i])
+ {
+ maxLng=lng[i];
+ }
+ }
+
+ bl_count=new unsigned [maxLng+1];
+ next_code=new unsigned [maxLng+1];
+ for(i=0; i<maxLng+1; i++)
+ {
+ bl_count[i]=0;
+ next_code[i]=0;
+ }
+ for(i=0; i<nLng; i++)
+ {
+ bl_count[lng[i]]++;
+ }
+
+ // for(i=0; i<maxLng+1; i++)
+ // {
+ // INFO("bl_count[%d]=%d",i,bl_count[i]);
+ // }
+
+ // See RFC1951 Specification
+ code=0;
+ bl_count[0]=0;
+ for(bits=1; bits<=maxLng; bits++)
+ {
+ code=(code+bl_count[bits-1])<<1;
+ next_code[bits]=code;
+ }
+
+ for(n=0; n<nLng; n++)
+ {
+ unsigned len;
+ len=lng[n];
+ if(len>0)
+ {
+ hCode[n]=next_code[len]++;
+ }
+ }
+
+ if(bl_count!=NULL)
+ {
+ delete [] bl_count;
+ }
+ if(next_code!=NULL)
+ {
+ delete [] next_code;
+ }
+}
+
+int YsPngUncompressor::DecodeDynamicHuffmanCode
+ (unsigned int &hLit,unsigned int &hDist,unsigned int &hCLen,
+ unsigned int *&hLengthLiteral,unsigned int *&hCodeLiteral,
+ unsigned int *&hLengthDist,unsigned int *&hCodeDist,
+ unsigned int hLengthBuf[322],unsigned int hCodeBuf[322],
+ const unsigned char dat[],unsigned int &bytePtr,unsigned int &bitPtr)
+{
+ unsigned int i;
+ hLit=0;
+ hDist=0;
+ hCLen=0;
+
+ hLit=GetNextMultiBit(dat,bytePtr,bitPtr,5);
+ hDist=GetNextMultiBit(dat,bytePtr,bitPtr,5);
+ hCLen=GetNextMultiBit(dat,bytePtr,bitPtr,4);
+
+ INFO("hLit=%d hDist=%d hCLen=%d",hLit,hDist,hCLen);
+
+ const unsigned int codeLengthLen=19;
+ unsigned codeLengthOrder[codeLengthLen]=
+ {
+ 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15
+ };
+ unsigned codeLengthCode[codeLengthLen];
+ for(i=0; i<codeLengthLen; i++)
+ {
+ codeLengthCode[i]=0;
+ }
+ for(i=0; i<hCLen+4; i++)
+ {
+ codeLengthCode[codeLengthOrder[i]]=GetNextMultiBit(dat,bytePtr,bitPtr,3);
+ // INFO("Code length code[%d]=%d (for %d)",
+ // codeLengthOrder[i],codeLengthCode[i],codeLengthOrder[i]);
+ }
+
+ unsigned hLengthCode[codeLengthLen],hCodeCode[codeLengthLen];
+ MakeDynamicHuffmanCode(hLengthCode,hCodeCode,codeLengthLen,codeLengthCode);
+
+ for(i=0; i<hCLen+4; i++)
+ {
+ INFO("CodeLengthLen[%3d]=%d HuffmanCode=%08x",i,codeLengthCode[i],hCodeCode[i]);
+ }
+
+ // for(i=0; i<codeLengthLen; i++)
+ // {
+ // INFO("[%d] %08x %08xx",i,hLengthCode[i],hCodeCode[i]);
+ // }
+
+ hLengthLiteral=hLengthBuf;
+ hCodeLiteral=hCodeBuf;
+ hLengthDist=hLengthBuf+hLit+257;
+ hCodeDist=hCodeBuf+hLit+257;
+
+ YsPngHuffmanTree *lengthTree,*lengthTreePtr;
+ lengthTree=MakeHuffmanTree(codeLengthLen,hLengthCode,hCodeCode);
+
+ unsigned int nExtr;
+ nExtr=0;
+ lengthTreePtr=lengthTree;
+ while(nExtr<hLit+257+hDist+1)
+ {
+ if(GetNextBit(dat,bytePtr,bitPtr))
+ {
+ lengthTreePtr=lengthTreePtr->one;
+ }
+ else
+ {
+ lengthTreePtr=lengthTreePtr->zero;
+ }
+ if(lengthTreePtr->zero==NULL && lengthTreePtr->one==NULL)
+ {
+ unsigned value,copyLength;
+ value=lengthTreePtr->dat;
+
+ // INFO("Value=%d",value);
+
+ if(value<=15)
+ {
+ hLengthBuf[nExtr++]=value;
+ }
+ else if(value==16)
+ {
+ copyLength=3+GetNextMultiBit(dat,bytePtr,bitPtr,2);
+ // INFO("copyLength=%d",copyLength);
+ while(copyLength>0)
+ {
+ hLengthBuf[nExtr]=hLengthBuf[nExtr-1];
+ nExtr++;
+ copyLength--;
+ }
+ }
+ else if(value==17)
+ {
+ copyLength=3+GetNextMultiBit(dat,bytePtr,bitPtr,3);
+ // INFO("copyLength=%d",copyLength);
+ while(copyLength>0)
+ {
+ hLengthBuf[nExtr++]=0;
+ copyLength--;
+ }
+ }
+ else if(value==18)
+ {
+ copyLength=11+GetNextMultiBit(dat,bytePtr,bitPtr,7);
+ // INFO("copyLength=%d",copyLength);
+ while(copyLength>0)
+ {
+ hLengthBuf[nExtr++]=0;
+ copyLength--;
+ }
+ }
+
+ lengthTreePtr=lengthTree;
+
+ // INFO("nExtr=%d/%d",nExtr,hLit+257+hDist+1);
+ }
+ }
+
+ for(i=0; i<hLit+257; i++)
+ {
+ INFO("LiteralLength[%3d]=%d",i,hLengthLiteral[i]);
+ }
+ for(i=0; i<hDist+1; i++)
+ {
+ INFO("Dist [%d] Length %d",i,hLengthDist[i]);
+ }
+ INFO("Making Huffman Code from Code Lengths");
+
+ MakeDynamicHuffmanCode(hLengthLiteral,hCodeLiteral,hLit+257,hLengthLiteral);
+ MakeDynamicHuffmanCode(hLengthDist,hCodeDist,hDist+1,hLengthDist);
+
+ DeleteHuffmanTree(lengthTree);
+
+ return YSOK;
+}
+
+YsPngHuffmanTree *YsPngUncompressor::MakeHuffmanTree(unsigned n,unsigned hLength[],unsigned hCode[])
+{
+ unsigned i,j,mask;
+ YsPngHuffmanTree *root,*ptr;
+ root=new YsPngHuffmanTree;
+
+ for(i=0; i<n; i++)
+ {
+ INFO(" MakeHuffmanTree %d of %d", i, n);
+ if(hLength[i]>0)
+ {
+ ptr=root;
+ mask=(1<<(hLength[i]-1));
+ for(j=0; j<hLength[i]; j++)
+ {
+ INFO(" j: %d of %d", j, hLength[i]);
+ if(hCode[i]&mask)
+ {
+ if(ptr->one==NULL)
+ {
+ ptr->one=new YsPngHuffmanTree;
+ }
+ ptr=ptr->one;
+ }
+ else
+ {
+ if(ptr->zero==NULL)
+ {
+ ptr->zero=new YsPngHuffmanTree;
+ }
+ ptr=ptr->zero;
+ }
+ mask>>=1;
+ }
+ ptr->dat=i;
+ }
+ }
+
+ return root;
+}
+
+void YsPngUncompressor::DeleteHuffmanTree(YsPngHuffmanTree *node)
+{
+ INFO("DeleteHuffmanTree");
+ YsPngHuffmanTree::DeleteHuffmanTree(node);
+}
+
+unsigned YsPngUncompressor::GetCopyLength(unsigned value,unsigned char dat[],unsigned &bytePtr,unsigned &bitPtr)
+{
+ unsigned copyLength;
+
+ if(value<=264)
+ {
+ copyLength=3+(value-257);
+ }
+ else if(value>=285)
+ {
+ copyLength=258;
+ }
+ else
+ {
+ unsigned base,offset,extBits;
+ extBits=1+(value-265)/4;
+ base=(8<<((value-265)/4))+3;
+ offset=((value-265)&3)*(2<<((value-265)/4));
+
+ copyLength=GetNextMultiBit(dat,bytePtr,bitPtr,extBits);
+ copyLength+=base+offset;
+ }
+
+ return copyLength;
+}
+
+unsigned YsPngUncompressor::GetBackwardDistance
+ (unsigned distCode,unsigned char dat[],unsigned &bytePtr,unsigned &bitPtr)
+{
+ unsigned backDist;
+
+ if(distCode<=3)
+ {
+ backDist=distCode+1;
+ }
+ else
+ {
+ unsigned base,offset,extBits;
+
+ base=(4<<((distCode-4)/2))+1;
+ offset=(distCode&1)*(2<<((distCode-4)/2));
+ extBits=(distCode-2)/2;
+
+ backDist=GetNextMultiBit(dat,bytePtr,bitPtr,extBits);
+ backDist+=base+offset;
+ }
+
+ return backDist;
+}
+
+int YsPngUncompressor::Uncompress(unsigned length,unsigned char dat[])
+{
+ unsigned windowUsed;
+ //unsigned char *windowBuf;
+ unsigned nByteExtracted;
+ //windowBuf=NULL;
+ SlidingWindow * windowBuf = NULL;
+
+ unsigned bytePtr,bitPtr;
+ bytePtr=0;
+ bitPtr=1;
+ nByteExtracted=0;
+
+ //DSTrackClear();
+ INFO("Begin zLib block length=%d bytePtr=%d bitPtr=0x%02x",length,bytePtr,bitPtr);
+
+ unsigned char cmf,flg;
+ cmf=dat[bytePtr++];
+ flg=dat[bytePtr++];
+
+ unsigned cm,cInfo,windowSize;
+ cm=cmf&0x0f;
+ if(cm!=8)
+ {
+ ERR("Unsupported compression method! (%d)",cm);
+ goto ERREND;
+ }
+
+ cInfo=(cmf&0xf0)>>4;
+ windowSize=1<<(cInfo+8);
+
+ INFO("cInfo=%d, Window Size=%d",cInfo,windowSize);
+
+ //windowBuf = new unsigned char [windowSize];
+ //windowBuf = (unsigned char *) malloc(windowSize);
+ windowBuf = new SlidingWindow(windowSize, 3000); // windowSize);
+
+ if (windowBuf->status() == SlidingWindow::outofmemory)
+ goto ERREND;
+
+ windowUsed=0;
+
+
+ unsigned fCheck,fDict,fLevel;
+ fCheck=(flg&15);
+ fDict=(flg&32)>>5;
+ fLevel=(flg&192)>>6;
+
+ INFO("fCheck=%d fDict=%d fLevel=%d",fCheck,fDict,fLevel);
+
+ if(fDict!=0)
+ {
+ ERR("PNG is not supposed to have a preset dictionary.");
+ goto ERREND;
+ }
+
+
+ YsPngHuffmanTree *codeTree,*codeTreePtr;
+ YsPngHuffmanTree *distTree,*distTreePtr;
+ codeTree=NULL;
+ distTree=NULL;
+
+ while(1)
+ {
+ unsigned bFinal,bType;
+
+ bFinal=GetNextBit(dat,bytePtr,bitPtr);
+ bType=GetNextMultiBit(dat,bytePtr,bitPtr,2);
+
+ if(bytePtr>=length)
+ {
+ ERR("Buffer overflow");
+ goto ERREND;
+ }
+
+ INFO("bFinal=%d bType=%d",bFinal,bType);
+
+ if(bType==0) // No Compression
+ {
+ unsigned len;
+ if(bitPtr!=1)
+ {
+ bitPtr=1;
+ bytePtr++;
+ }
+ if(bytePtr>=length)
+ {
+ ERR("Buffer overflow");
+ goto ERREND;
+ }
+
+ len=dat[bytePtr]+dat[bytePtr+1]*256;
+ bytePtr+=4;
+
+ // Feed len bytes
+ int i;
+ for(i=0; i<len; i++) // 2010/02/08
+ {
+ output->Output(dat[bytePtr+i]);
+ if (!windowBuf->set(windowUsed++, dat[bytePtr + i]))
+ goto ERREND;
+ }
+ bytePtr+=len;
+ }
+ else if(bType==1 || bType==2)
+ {
+ INFO("bType: %d", bType);
+ codeTree=NULL;
+
+ if(bType==1)
+ {
+ unsigned hLength[288],hCode[288];
+ MakeFixedHuffmanCode(hLength,hCode);
+ INFO(" created fixed huffman code");
+ codeTree=MakeHuffmanTree(288,hLength,hCode);
+ INFO(" created huffman tree");
+ distTree=NULL;
+ }
+ else
+ {
+ unsigned hLit,hDist,hCLen;
+ unsigned *hLengthLiteral,*hCodeLiteral;
+ unsigned *hLengthDist,*hCodeDist;
+ unsigned hLengthBuf[322],hCodeBuf[322];
+
+ DecodeDynamicHuffmanCode
+ (hLit,hDist,hCLen,
+ hLengthLiteral,hCodeLiteral,hLengthDist,hCodeDist,hLengthBuf,hCodeBuf,
+ dat,bytePtr,bitPtr);
+
+ INFO("Making Huffman Tree");
+ codeTree=MakeHuffmanTree(hLit+257,hLengthLiteral,hCodeLiteral);
+ distTree=MakeHuffmanTree(hDist+1,hLengthDist,hCodeDist);
+ }
+
+ INFO("Huffman table prepared");
+
+ codeTreePtr=codeTree;
+ if(codeTree!=NULL)
+ {
+ while(1)
+ {
+ if(GetNextBit(dat,bytePtr,bitPtr))
+ {
+ codeTreePtr=codeTreePtr->one;
+ }
+ else
+ {
+ codeTreePtr=codeTreePtr->zero;
+ }
+
+ if(codeTreePtr==NULL)
+ {
+ ERR("Huffman Decompression: Reached NULL node.");
+ goto ERREND;
+ }
+
+ if(codeTreePtr->zero==NULL && codeTreePtr->one==NULL)
+ {
+ // INFO("[%d]",codeTreePtr->dat);
+
+ unsigned value;
+ value=codeTreePtr->dat;
+ if(value<256)
+ {
+ // windowBuf[windowUsed++]=value;
+ if (!windowBuf->set(windowUsed++, value))
+ goto ERREND;
+ //DSTrackMax(windowUsed-1);
+ //windowUsed&=(windowSize-1);
+ if(output->Output(value)!=YSOK)
+ {
+ goto ERREND;
+ }
+ nByteExtracted++;
+ }
+ else if(value==256)
+ {
+ break;
+ }
+ else if(value<=285)
+ {
+ unsigned copyLength,distCode,backDist;
+ copyLength=GetCopyLength(value,dat,bytePtr,bitPtr);
+ // INFO("CopyLength %d",copyLength);
+
+ if(bType==1)
+ {
+ distCode=16*GetNextBit(dat,bytePtr,bitPtr); // 5 bits fixed
+ distCode+=8*GetNextBit(dat,bytePtr,bitPtr); // Reversed order
+ distCode+=4*GetNextBit(dat,bytePtr,bitPtr);
+ distCode+=2*GetNextBit(dat,bytePtr,bitPtr);
+ distCode+= GetNextBit(dat,bytePtr,bitPtr);
+ }
+ else
+ {
+ distTreePtr=distTree;
+ while(distTreePtr->zero!=NULL || distTreePtr->one!=NULL)
+ {
+ if(GetNextBit(dat,bytePtr,bitPtr))
+ {
+ distTreePtr=distTreePtr->one;
+ }
+ else
+ {
+ distTreePtr=distTreePtr->zero;
+ }
+ }
+ distCode=distTreePtr->dat;
+ }
+ backDist=GetBackwardDistance(distCode,dat,bytePtr,bitPtr);
+ // INFO("DistCode %d BackDist %d",distCode,backDist);
+
+
+ unsigned i;
+ for(i=0; i<copyLength; i++)
+ {
+ unsigned char dat;
+ //dat=windowBuf[(windowUsed-backDist)&(windowSize-1)];
+ dat = windowBuf->get(windowUsed, backDist);
+ //DSTrackMax((windowUsed-backDist)&(windowSize-1));
+ if(output->Output(dat)!=YSOK)
+ {
+ goto ERREND;
+ }
+ nByteExtracted++;
+ //windowBuf[windowUsed++]=dat;
+ windowBuf->set(windowUsed++, dat);
+ //DSTrackMax(windowUsed-1);
+ //windowUsed&=(windowSize-1);
+ }
+ }
+
+ codeTreePtr=codeTree;
+ }
+
+ if(length<=bytePtr)
+ {
+ goto ERREND;
+ }
+ }
+ }
+
+
+ DeleteHuffmanTree(codeTree);
+ DeleteHuffmanTree(distTree);
+ codeTree=NULL;
+ distTree=NULL;
+ }
+ else
+ {
+ ERR("Unknown compression type (bType=3)");
+ goto ERREND;
+ }
+
+
+ if(bFinal!=0)
+ {
+ break;
+ }
+ }
+ //DSTrackReport();
+ //delete [] windowBuf;
+ //free(windowBuf);
+ delete windowBuf;
+ //windowBuf=NULL;
+
+ INFO("End zLib block length=%d bytePtr=%d bitPtr=0x%02x",length,bytePtr,bitPtr);
+ INFO("Huffman Tree Leak Tracker = %d",YsPngHuffmanTree::leakTracker);
+ INFO("Output %d bytes.",nByteExtracted);
+
+ return YSOK;
+
+ERREND:
+ ERR("ERREND:");
+ if(windowBuf!=NULL)
+ {
+ //delete [] windowBuf;
+ //free(windowBuf);
+ delete windowBuf;
+ }
+ if(codeTree!=NULL)
+ {
+ DeleteHuffmanTree(codeTree);
+ }
+ if(distTree!=NULL)
+ {
+ DeleteHuffmanTree(distTree);
+ }
+ return YSERR;
+}
+
+////////////////////////////////////////////////////////////
+
+int YsGenericPngDecoder::Decode(const char fn[])
+{
+ FILE *fp;
+ unsigned fileSize;
+
+ fp=fopen(fn,"rb");
+ if(fp!=NULL)
+ {
+ fseek(fp,0,2 /* SEEK_END */);
+ fileSize=ftell(fp);
+ fseek(fp,0,0 /* SEEK_SET */);
+
+ if(CheckSignature(fp)!=YSOK)
+ {
+ ERR("The file does not have PNG signature.");
+ goto ERREND;
+ }
+
+ unsigned datBufUsed;
+ unsigned char *datBuf;
+
+
+ datBufUsed=0;
+ datBuf = new unsigned char [fileSize];
+
+ INFO("datBuf allocated %d bytes", fileSize);
+
+ unsigned char *buf;
+ unsigned length,chunkType,crc;
+ while(ReadChunk(length,buf,chunkType,crc,fp)==YSOK && chunkType!=IEND)
+ {
+ switch(chunkType)
+ {
+ default:
+ if(buf!=NULL)
+ {
+ delete [] buf;
+ }
+ break;
+ case IHDR:
+ if(buf!=NULL)
+ {
+ if(length>=13)
+ {
+ hdr.Decode(buf);
+ }
+ delete [] buf;
+ }
+ break;
+ case PLTE:
+ if(buf!=NULL)
+ {
+ if(plt.Decode(length,buf)!=YSOK)
+ {
+ delete [] buf;
+ goto ERREND;
+ }
+ delete [] buf;
+ }
+ break;
+ case tRNS:
+ if(buf!=NULL)
+ {
+ trns.Decode(length,buf,hdr.colorType);
+ delete [] buf;
+ }
+ break;
+ case gAMA:
+ if(buf!=NULL && length>=4)
+ {
+ gamma=PngGetUnsignedInt(buf);
+ INFO("Gamma %d (default=%d)",gamma,gamma_default);
+ delete [] buf;
+ }
+ break;
+ case IDAT:
+ if(buf!=NULL)
+ {
+ unsigned i;
+ for(i=0; i<length; i++)
+ {
+ datBuf[datBufUsed+i]=buf[i];
+ }
+ datBufUsed+=length;
+ delete [] buf;
+ }
+ }
+ }
+
+
+ if(PrepareOutput()==YSOK)
+ {
+ YsPngUncompressor uncompressor;
+ uncompressor.output=this;
+ uncompressor.Uncompress(datBufUsed,datBuf);
+ EndOutput();
+ }
+
+ delete [] datBuf;
+ fclose(fp);
+ return YSOK;
+ }
+
+ERREND:
+ if(fp!=NULL)
+ {
+ fclose(fp);
+ }
+ return -1;
+}
+
+int YsGenericPngDecoder::PrepareOutput(void)
+{
+ return YSOK;
+}
+
+int YsGenericPngDecoder::Output(unsigned char dat)
+{
+ return YSOK;
+}
+
+int YsGenericPngDecoder::EndOutput(void)
+{
+ return YSOK;
+}
+
+
+
+////////////////////////////////////////////////////////////
+
+static inline unsigned char Paeth(unsigned int ua,unsigned int ub,unsigned int uc)
+{
+ int a,b,c,p,pa,pb,pc;
+
+ a=(int)ua;
+ b=(int)ub;
+ c=(int)uc;
+
+ p=a+b-c;
+ pa=(p>a ? p-a : a-p);
+ pb=(p>b ? p-b : b-p);
+ pc=(p>c ? p-c : c-p);
+
+ if(pa<=pb && pa<=pc)
+ {
+ return a;
+ }
+ else if(pb<=pc)
+ {
+ return b;
+ }
+ else
+ {
+ return c;
+ }
+}
+
+static inline void Filter8(unsigned char curLine[],unsigned char prvLine[],int x,int y,int unitLng,int filter)
+{
+ int i;
+ switch(filter)
+ {
+ case 1:
+ if(x>0)
+ {
+ for(i=0; i<unitLng; i++)
+ {
+ curLine[x*unitLng+i]+=curLine[x*unitLng+i-unitLng];
+ }
+ }
+ break;
+ case 2:
+ if(y>0)
+ {
+ for(i=0; i<unitLng; i++)
+ {
+ curLine[x*unitLng+i]+=prvLine[x*unitLng+i];
+ }
+ }
+ break;
+ case 3:
+ for(i=0; i<unitLng; i++)
+ {
+ unsigned int a;
+ a=(x>0 ? curLine[x*unitLng+i-unitLng] : 0);
+ a+=(y>0 ? prvLine[x*unitLng+i] : 0);
+ curLine[x*unitLng+i]+=a/2;
+ }
+ break;
+ case 4:
+ for(i=0; i<unitLng; i++)
+ {
+ unsigned int a,b,c;
+ a=(x>0 ? curLine[x*unitLng+i-unitLng] : 0);
+ b=(y>0 ? prvLine[x*unitLng+i] : 0);
+ c=((x>0 && y>0) ? prvLine[x*unitLng-unitLng+i] : 0);
+ curLine[x*unitLng+i]+=Paeth(a,b,c);
+ }
+ break;
+ }
+}
+
+YsRawPngDecoder::YsRawPngDecoder()
+{
+ wid=0;
+ hei=0;
+ rgba=NULL;
+ twoLineBuf8=NULL;
+
+ curLine8=NULL;
+ prvLine8=NULL;
+
+ autoDeleteRgbaBuffer=1;
+}
+
+YsRawPngDecoder::~YsRawPngDecoder()
+{
+ if(autoDeleteRgbaBuffer==1 && rgba!=NULL)
+ {
+ delete [] rgba;
+ }
+ if(twoLineBuf8!=NULL)
+ {
+ delete [] twoLineBuf8;
+ }
+}
+
+void YsRawPngDecoder::ShiftTwoLineBuf(void)
+{
+ if(twoLineBuf8!=NULL)
+ {
+ unsigned char *swap;
+ swap=curLine8;
+ curLine8=prvLine8;
+ prvLine8=swap;
+ }
+}
+
+int YsRawPngDecoder::PrepareOutput(void)
+{
+ int supported;
+
+ supported=0;
+ switch(hdr.colorType)
+ {
+ case 0: // Greyscale
+ switch(hdr.bitDepth)
+ {
+ case 8:
+ case 1:
+ supported=1;
+ break;
+ case 2:
+ case 4:
+ case 16:
+ break;
+ }
+ break;
+ case 2: // Truecolor
+ switch(hdr.bitDepth)
+ {
+ case 8:
+ case 16:
+ supported=1;
+ break;
+ }
+ break;
+ case 3: // Indexed-color
+ switch(hdr.bitDepth)
+ {
+ case 4:
+ case 8:
+ supported=1;
+ break;
+ case 1:
+ case 2:
+ break;
+ }
+ break;
+ case 4: // Greyscale with alpha
+ switch(hdr.bitDepth)
+ {
+ case 8:
+ supported=1;
+ break;
+ case 16:
+ break;
+ }
+ break;
+ case 6: // Truecolor with alpha
+ switch(hdr.bitDepth)
+ {
+ case 8:
+ supported=1;
+ break;
+ case 16:
+ break;
+ }
+ break;
+ }
+
+ if(supported==0)
+ {
+ ERR("Unsupported colorType-bitDepth combination.");
+ return YSERR;
+ }
+
+
+
+ wid=hdr.width;
+ hei=hdr.height;
+ if(autoDeleteRgbaBuffer==1 && rgba!=NULL)
+ {
+ delete [] rgba;
+ rgba=NULL;
+ }
+ rgba=new unsigned char [wid*hei*4];
+ x=-1;
+ y=0;
+ filter=0;
+ inLineCount=0;
+ inPixelCount=0;
+ firstByte=1;
+ index=0;
+ interlacePass=1;
+
+ if(twoLineBuf8!=NULL)
+ {
+ delete [] twoLineBuf8;
+ twoLineBuf8=NULL;
+ }
+
+
+ // See PNG Specification 11.2 for Allowed combinations of color type and bit depth
+ unsigned int twoLineBufLngPerLine;
+ switch(hdr.colorType)
+ {
+ case 0: // Greyscale
+ switch(hdr.bitDepth)
+ {
+ case 1:
+ twoLineBufLngPerLine=(hdr.width+7)/8;
+ break;
+ case 2:
+ twoLineBufLngPerLine=(hdr.width+3)/4;
+ break;
+ case 4:
+ twoLineBufLngPerLine=(hdr.width+1)/2;
+ break;
+ case 8:
+ twoLineBufLngPerLine=hdr.width;
+ break;
+ case 16:
+ twoLineBufLngPerLine=hdr.width*2;
+ break;
+ }
+ break;
+ case 2: // Truecolor
+ switch(hdr.bitDepth)
+ {
+ case 8:
+ twoLineBufLngPerLine=hdr.width*3;
+ break;
+ case 16:
+ twoLineBufLngPerLine=hdr.width*6;
+ break;
+ }
+ break;
+ case 3: // Indexed-color
+ switch(hdr.bitDepth)
+ {
+ case 1:
+ twoLineBufLngPerLine=(hdr.width+7)/8;
+ break;
+ case 2:
+ twoLineBufLngPerLine=(hdr.width+3)/4;
+ break;
+ case 4:
+ twoLineBufLngPerLine=(hdr.width+1)/2;
+ break;
+ case 8:
+ twoLineBufLngPerLine=hdr.width;
+ break;
+ }
+ break;
+ case 4: // Greyscale with alpha
+ switch(hdr.bitDepth)
+ {
+ case 8:
+ twoLineBufLngPerLine=hdr.width*2;
+ break;
+ case 16:
+ twoLineBufLngPerLine=hdr.width*4;
+ break;
+ }
+ break;
+ case 6: // Truecolor with alpha
+ switch(hdr.bitDepth)
+ {
+ case 8:
+ twoLineBufLngPerLine=hdr.width*4;
+ break;
+ case 16:
+ twoLineBufLngPerLine=hdr.width*8;
+ break;
+ }
+ break;
+ }
+
+ twoLineBuf8=new unsigned char [twoLineBufLngPerLine*2];
+ curLine8=twoLineBuf8;
+ prvLine8=twoLineBuf8+twoLineBufLngPerLine;
+
+ return YSOK;
+}
+
+int YsRawPngDecoder::Output(unsigned char dat)
+{
+ unsigned int i;
+ unsigned int colIdx;
+ unsigned int interlaceWid,interlaceHei,interlaceX,interlaceY;
+
+ if(y>=hei)
+ {
+ return YSERR;
+ }
+
+ if(x==-1) // First byte is filter type for the line.
+ {
+ filter=dat; // See PNG Specification 4.5.4 Filtering, 9 Filtering
+ inLineCount=0;
+ inPixelCount=0;
+ x++;
+ // INFO("y=%d filter=%d",y,filter);
+ return YSOK;
+ }
+ else
+ {
+ switch(hdr.interlaceMethod)
+ {
+ // Non-Interlace
+ case 0:
+ switch(hdr.colorType) // See PNG Specification 6.1 Colour types and values
+ {
+ // Grayscale
+ case 0:
+ switch(hdr.bitDepth)
+ {
+ case 1:
+ curLine8[x/8]=dat;
+ Filter8(curLine8,prvLine8,x/8,y,1,filter);
+
+ for(i=0; i<8 && x<wid; i++)
+ {
+ colIdx=(curLine8[x/8]>>(7-i))&1;
+ colIdx=(colIdx<<1)+colIdx;
+ colIdx=(colIdx<<2)+colIdx;
+ colIdx=(colIdx<<4)+colIdx;
+
+ rgba[index ]=colIdx;
+ rgba[index+1]=colIdx;
+ rgba[index+2]=colIdx;
+ rgba[index+3]=0;
+ x++;
+ index+=4;
+ }
+ break;
+
+ case 8:
+ curLine8[x]=dat;
+ Filter8(curLine8,prvLine8,x,y,1,filter);
+ colIdx=curLine8[x];
+
+ rgba[index ]=curLine8[x];
+ rgba[index+1]=curLine8[x];
+ rgba[index+2]=curLine8[x];
+ if(curLine8[x]==trns.col[0] || curLine8[x]==trns.col[1] || curLine8[x]==trns.col[2])
+ {
+ rgba[index+3]=0;
+ }
+ else
+ {
+ rgba[index+3]=255;
+ }
+
+ x++;
+ index+=4;
+ break;
+ }
+ break;
+
+
+
+ // True color
+ case 2:
+ switch(hdr.bitDepth)
+ {
+ case 8:
+ curLine8[inLineCount+inPixelCount]=dat;
+ inPixelCount++;
+ if(inPixelCount==3)
+ {
+ Filter8(curLine8,prvLine8,x,y,3,filter);
+ rgba[index ]=curLine8[inLineCount];
+ rgba[index+1]=curLine8[inLineCount+1];
+ rgba[index+2]=curLine8[inLineCount+2];
+
+ if(curLine8[inLineCount ]==trns.col[0] &&
+ curLine8[inLineCount+1]==trns.col[1] &&
+ curLine8[inLineCount+2]==trns.col[2])
+ {
+ rgba[index+3]=0;
+ }
+ else
+ {
+ rgba[index+3]=255;
+ }
+
+ x++;
+ index+=4;
+ inLineCount+=3;
+ inPixelCount=0;
+ }
+ break;
+ case 16:
+ curLine8[inLineCount+inPixelCount]=dat;
+ inPixelCount++;
+ if(inPixelCount==6)
+ {
+ Filter8(curLine8,prvLine8,x,y,6,filter);
+ rgba[index ]=curLine8[inLineCount ];
+ rgba[index+1]=curLine8[inLineCount+2];
+ rgba[index+2]=curLine8[inLineCount+4];
+
+ r=curLine8[inLineCount ]*256+curLine8[inLineCount+1];
+ g=curLine8[inLineCount+2]*256+curLine8[inLineCount+3];
+ b=curLine8[inLineCount+4]*256+curLine8[inLineCount+5];
+ if(r==trns.col[0] && g==trns.col[1] && b==trns.col[2])
+ {
+ rgba[index+3]=0;
+ }
+ else
+ {
+ rgba[index+3]=255;
+ }
+ x++;
+ index+=4;
+ inLineCount+=6;
+ inPixelCount=0;
+ }
+ break;
+ }
+ break;
+
+
+
+ // Indexed color
+ case 3:
+ switch(hdr.bitDepth)
+ {
+ case 4:
+ curLine8[x/2]=dat;
+ Filter8(curLine8,prvLine8,x/2,y,1,filter);
+
+ for(i=0; i<2 && x<wid; i++)
+ {
+ colIdx=(curLine8[x/2]>>((1-i)*4))&0x0f;
+
+ if(colIdx<plt.nEntry)
+ {
+ rgba[index ]=plt.entry[colIdx*3 ];
+ rgba[index+1]=plt.entry[colIdx*3+1];
+ rgba[index+2]=plt.entry[colIdx*3+2];
+ if(colIdx==trns.col[0] || colIdx==trns.col[1] || colIdx==trns.col[2])
+ {
+ rgba[index+3]=0;
+ }
+ else
+ {
+ rgba[index+3]=255;
+ }
+ }
+ x++;
+ index+=4;
+ }
+ break;
+
+ case 8:
+ curLine8[x]=dat;
+ Filter8(curLine8,prvLine8,x,y,1,filter);
+ colIdx=curLine8[x];
+
+ if(colIdx<plt.nEntry)
+ {
+ rgba[index ]=plt.entry[colIdx*3 ];
+ rgba[index+1]=plt.entry[colIdx*3+1];
+ rgba[index+2]=plt.entry[colIdx*3+2];
+ if(colIdx==trns.col[0] || colIdx==trns.col[1] || colIdx==trns.col[2])
+ {
+ rgba[index+3]=0;
+ }
+ else
+ {
+ rgba[index+3]=255;
+ }
+ }
+ x++;
+ index+=4;
+ break;
+ }
+ break;
+
+
+
+ // Greyscale with alpha
+ case 4:
+ switch(hdr.bitDepth)
+ {
+ case 8:
+ curLine8[inLineCount+inPixelCount]=dat;
+ inPixelCount++;
+ if(inPixelCount==2)
+ {
+ Filter8(curLine8,prvLine8,x,y,2,filter);
+ rgba[index ]=curLine8[inLineCount ];
+ rgba[index+1]=curLine8[inLineCount ];
+ rgba[index+2]=curLine8[inLineCount ];
+ rgba[index+3]=curLine8[inLineCount+1];
+ index+=4;
+ x++;
+ inLineCount+=2;
+ inPixelCount=0;
+ }
+ break;
+ }
+ break;
+
+
+
+ // Truecolor with alpha
+ case 6:
+ switch(hdr.bitDepth)
+ {
+ case 8:
+ curLine8[inLineCount+inPixelCount]=dat;
+ inPixelCount++;
+ if(inPixelCount==4)
+ {
+ Filter8(curLine8,prvLine8,x,y,4,filter);
+ rgba[index ]=curLine8[inLineCount ];
+ rgba[index+1]=curLine8[inLineCount+1];
+ rgba[index+2]=curLine8[inLineCount+2];
+ rgba[index+3]=curLine8[inLineCount+3];
+ index+=4;
+ x++;
+ inLineCount+=4;
+ inPixelCount=0;
+ }
+ break;
+ }
+ break;
+ } // switch(hdr.colorType)
+
+ if(x>=wid)
+ {
+ y++;
+ x=-1;
+ ShiftTwoLineBuf();
+ }
+
+ return YSOK;
+
+
+ // Interlace
+ case 1:
+ // 1 6 4 6 2 6 4 6
+ // 7 7 7 7 7 7 7 7
+ // 5 6 5 6 5 6 5 6
+ // 7 7 7 7 7 7 7 7
+ // 3 6 4 6 3 6 4 6
+ // 7 7 7 7 7 7 7 7
+ // 5 6 5 6 5 6 5 6
+ // 7 7 7 7 7 7 7 7
+ switch(interlacePass)
+ {
+ case 1:
+ interlaceWid=(wid+7)/8;
+ interlaceHei=(hei+7)/8;
+ interlaceX=x*8;
+ interlaceY=y*8;
+ break;
+ case 2:
+ interlaceWid=(wid+3)/8;
+ interlaceHei=(hei+7)/8;
+ interlaceX=4+x*8;
+ interlaceY=y*8;
+ break;
+ case 3:
+ interlaceWid=(wid+3)/4;
+ interlaceHei=(hei+3)/8;
+ interlaceX=x*4;
+ interlaceY=4+y*8;
+ break;
+ case 4:
+ interlaceWid=(wid+1)/4;
+ interlaceHei=(hei+3)/4;
+ interlaceX=2+x*4;
+ interlaceY=y*4;
+ break;
+ case 5:
+ interlaceWid=(wid+1)/2;
+ interlaceHei=(hei+1)/4;
+ interlaceX=x*2;
+ interlaceY=2+y*4;
+ break;
+ case 6:
+ interlaceWid=(wid )/2;
+ interlaceHei=(hei+1)/2;
+ interlaceX=1+x*2;
+ interlaceY=y*2;
+ break;
+ case 7:
+ interlaceWid=wid;
+ interlaceHei=hei/2;
+ interlaceX=x;
+ interlaceY=1+y*2;
+ break;
+ default:
+ return YSERR;
+ } // switch(interlacePass)
+
+ switch(hdr.colorType) // See PNG Specification 6.1 Colour types and values
+ {
+ // Grayscale
+ case 0:
+ switch(hdr.bitDepth)
+ {
+ case 8:
+ curLine8[inLineCount]=dat;
+ Filter8(curLine8,prvLine8,x,y,1,filter);
+
+ index=interlaceX*4+interlaceY*wid*4;
+ rgba[index ]=curLine8[inLineCount];
+ rgba[index+1]=curLine8[inLineCount];
+ rgba[index+2]=curLine8[inLineCount];
+
+ if(curLine8[inLineCount]==trns.col[0] ||
+ curLine8[inLineCount]==trns.col[1] ||
+ curLine8[inLineCount]==trns.col[2])
+ {
+ rgba[index+3]=0;
+ }
+ else
+ {
+ rgba[index+3]=255;
+ }
+
+ x++;
+ inLineCount++;
+ break;
+ }
+ break;
+
+
+ // True color
+ case 2:
+ switch(hdr.bitDepth)
+ {
+ case 8:
+ curLine8[inLineCount+inPixelCount]=dat;
+ inPixelCount++;
+ if(inPixelCount==3)
+ {
+ Filter8(curLine8,prvLine8,x,y,3,filter);
+
+ index=interlaceX*4+interlaceY*wid*4;
+ rgba[index ]=curLine8[inLineCount ];
+ rgba[index+1]=curLine8[inLineCount+1];
+ rgba[index+2]=curLine8[inLineCount+2];
+
+ if(curLine8[inLineCount ]==trns.col[0] &&
+ curLine8[inLineCount+1]==trns.col[1] &&
+ curLine8[inLineCount+2]==trns.col[2])
+ {
+ rgba[index+3]=0;
+ }
+ else
+ {
+ rgba[index+3]=255;
+ }
+
+ x++;
+ inLineCount+=3;
+ inPixelCount=0;
+ }
+ break;
+
+ case 16:
+ curLine8[inLineCount+inPixelCount]=dat;
+ inPixelCount++;
+ if(inPixelCount==6)
+ {
+ Filter8(curLine8,prvLine8,x,y,6,filter);
+ index=interlaceX*4+interlaceY*wid*4;
+ rgba[index ]=curLine8[inLineCount ];
+ rgba[index+1]=curLine8[inLineCount+2];
+ rgba[index+2]=curLine8[inLineCount+4];
+
+ r=curLine8[inLineCount ]*256+curLine8[inLineCount+1];
+ g=curLine8[inLineCount+2]*256+curLine8[inLineCount+3];
+ b=curLine8[inLineCount+4]*256+curLine8[inLineCount+5];
+
+ if(r==trns.col[0] && g==trns.col[1] && b==trns.col[2])
+ // Fixed based on a bug report from a viewer. Thanks for the good catch!
+ // Report received 09/10/2010
+ // Fixed 09/18/2010
+ {
+ rgba[index+3]=0;
+ }
+ else
+ {
+ rgba[index+3]=255;
+ }
+
+ x++;
+ inLineCount+=6;
+ inPixelCount=0;
+ }
+ break;
+ }
+ break;
+
+
+
+ // Indexed color
+ case 3:
+ switch(hdr.bitDepth)
+ {
+ case 8:
+ curLine8[inLineCount]=dat;
+ Filter8(curLine8,prvLine8,x,y,1,filter);
+
+ index=interlaceX*4+interlaceY*wid*4;
+ colIdx=curLine8[inLineCount ];
+ if(colIdx<plt.nEntry)
+ {
+ rgba[index ]=plt.entry[colIdx*3 ];
+ rgba[index+1]=plt.entry[colIdx*3+1];
+ rgba[index+2]=plt.entry[colIdx*3+2];
+ if(colIdx==trns.col[0] || colIdx==trns.col[1] || colIdx==trns.col[2])
+ {
+ rgba[index+3]=0;
+ }
+ else
+ {
+ rgba[index+3]=255;
+ }
+ }
+
+ x++;
+ inLineCount++;
+ break;
+ }
+ break;
+
+
+
+ // Greyscale with alpha
+ case 4:
+ switch(hdr.bitDepth)
+ {
+ case 8:
+ curLine8[inLineCount+inPixelCount]=dat;
+ inPixelCount++;
+ if(inPixelCount==2)
+ {
+ Filter8(curLine8,prvLine8,x,y,2,filter);
+
+ index=interlaceX*4+interlaceY*wid*4;
+ rgba[index ]=curLine8[inLineCount ];
+ rgba[index+1]=curLine8[inLineCount ];
+ rgba[index+2]=curLine8[inLineCount ];
+ rgba[index+3]=curLine8[inLineCount+1];
+
+ x++;
+ inLineCount+=2;
+ inPixelCount=0;
+ }
+ break;
+ }
+ break;
+
+
+
+ // Truecolor with alpha
+ case 6:
+ switch(hdr.bitDepth)
+ {
+ case 8:
+ curLine8[inLineCount+inPixelCount]=dat;
+ inPixelCount++;
+ if(inPixelCount==4)
+ {
+ Filter8(curLine8,prvLine8,x,y,4,filter);
+
+ index=interlaceX*4+interlaceY*wid*4;
+ rgba[index ]=curLine8[inLineCount ];
+ rgba[index+1]=curLine8[inLineCount+1];
+ rgba[index+2]=curLine8[inLineCount+2];
+ rgba[index+3]=curLine8[inLineCount+3];
+
+ x++;
+ inLineCount+=4;
+ inPixelCount=0;
+ }
+ break;
+ }
+ break;
+ } // switch(hdr.colorType)
+
+ if(x>=interlaceWid)
+ {
+ y++;
+ x=-1;
+ ShiftTwoLineBuf();
+ if(y>=interlaceHei)
+ {
+ y=0;
+ interlacePass++;
+
+ INFO("Interlace Pass %d",interlacePass);
+ }
+ }
+
+ return YSOK;
+ default:
+ ERR("Unsupported interlace method.");
+ return YSERR;
+ }
+ }
+ // return YSERR; // unreachable
+}
+
+int YsRawPngDecoder::EndOutput(void)
+{
+ INFO("Final Position (%d,%d)",x,y);
+ return YSOK;
+}
+
+void YsRawPngDecoder::Flip(void) // For drawing in OpenGL
+{
+ int x,y,bytePerLine;
+ unsigned int swp;
+ bytePerLine=wid*4;
+ for(y=0; y<hei/2; y++)
+ {
+ for(x=0; x<bytePerLine; x++)
+ {
+ swp=rgba[y*bytePerLine+x];
+ rgba[y*bytePerLine+x]=rgba[(hei-1-y)*bytePerLine+x];
+ rgba[(hei-1-y)*bytePerLine+x]=swp;
+ }
+ }
+}
