123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635 |
- //GIF编码
- //编写者:高书克
- //日 期:2004-12-6
- #include <StdAfx.h>
- #include <MATH.H>
- #include "quantizer.h"
- #include "GSKCreateGIF.h"
- //13 byte
- typedef struct _GIFHEADER
- {
- BYTE Signature[6];
- WORD ScreenWidth;
- WORD ScreenHeight;
- BYTE GlobalFlagByte;
- BYTE BackGroundColor;
- BYTE AspectRatio;
- }GIFHEARD;
- #define HASPalette 0x80
- //10 byte
- typedef struct _GIFDATAHEARD
- {
- BYTE imageLabel;
- WORD imageLeft;
- WORD imageTop;
- WORD imageWidth;
- WORD imageHeight;
- BYTE localFlagByte;
- }GIFDATAHEARD;
- void addToBuf(HANDLE file,BYTE *buf,long &nUsedBits,BYTE data,int nBit)
- {
- int nIndex,nCurByteUsedBits;
-
- nIndex = nUsedBits/8;
- nCurByteUsedBits = nUsedBits%8;
- if(nIndex >= 255)
- {//已经产生255个字节的数据
- BYTE bytes = 0xFF;
- DWORD DwWitten=0;
- ::WriteFile(file,&bytes,1,&DwWitten,NULL);
- ::WriteFile(file,buf,bytes,&DwWitten,NULL);
- //file.Write(&bytes,1);
- //file.Write(buf,bytes);
- buf[0] = buf[255];
- nIndex = 0;
- nUsedBits -= 255*8;
- }
-
- if(nCurByteUsedBits == 0)
- {
- buf[nIndex] = data;
- }
- else
- {
- buf[nIndex] |= data<<nCurByteUsedBits;
-
- if(nBit > 8-nCurByteUsedBits)
- {
- nIndex++;
- buf[nIndex] = data>>(8-nCurByteUsedBits);
- }
- }
-
- nUsedBits += nBit;
- }
- void WriteData(HANDLE file,WORD *pHeard,int nDataCount,BYTE bitsPixel,BOOL bEnd)
- {
- BYTE initBits = bitsPixel+1;
- BYTE pByts[256];
- BYTE *pTmp = (BYTE*)pHeard;
- int nCurCodeBits=initBits;
- WORD nMaxCode=1;
- WORD nClearCode=1;
- WORD nEndCode;
- /*CStdioFile strFile;
-
- if(strFile.Open("d:\\writedata.txt",CFile::modeWrite|CFile::modeCreate|CFile::typeText))
- {
- CString sTmp;
- for(int i=0; i<nDataCount; i++)
- {
- sTmp.Format("%X ",pHeard[i]);
- strFile.WriteString(sTmp);
- }
- }
- */
- nClearCode <<= nCurCodeBits-1;
- nMaxCode <<= nCurCodeBits;
- nEndCode = nClearCode+1;
- memset(pByts,0,256);
-
- long nUsedBits = 0;
- addToBuf(file,pByts,nUsedBits,nClearCode&0xFF,min(8,nCurCodeBits));
- if(nCurCodeBits > 8)
- {
- addToBuf(file,pByts,nUsedBits,(nClearCode&0xFF00)>>8,nCurCodeBits-8);
- }
-
- int nHeardCode = nClearCode+1;
- for(int i=0; i<nDataCount; i++)
- {
- if(nHeardCode++ >= nMaxCode)
- {
- nCurCodeBits++;
- if(nCurCodeBits == 13)
- {
- //CString sMsg;
- //sMsg.Format("[%X,%X]",pHeard[i-1],pHeard[i]);
- //AfxMessageBox(sMsg);
- addToBuf(file,pByts,nUsedBits,nClearCode&0xFF,8);
- addToBuf(file,pByts,nUsedBits,(nClearCode&0xFF00)>>8,4);
- nCurCodeBits = initBits;
- nHeardCode = nClearCode+2;
- }
-
- nMaxCode = (WORD)1<<nCurCodeBits;
- }
-
- addToBuf(file,pByts,nUsedBits,pHeard[i]&0xFF,min(8,nCurCodeBits));
-
- if(nCurCodeBits > 8)
- {
- addToBuf(file,pByts,nUsedBits,(pHeard[i]&0xFF00)>>8,nCurCodeBits-8);
- }
- }
- if(bEnd)
- {
- addToBuf(file,pByts,nUsedBits,nEndCode&0xFF,min(8,nCurCodeBits));
- if(nCurCodeBits > 8)
- {
- addToBuf(file,pByts,nUsedBits,(nEndCode&0xFF00)>>8,nCurCodeBits-8);
- }
- }
- long nByteCount = nUsedBits/8;
-
- if(nUsedBits%8 != 0)
- {
- nByteCount++;
- }
-
- BYTE bytes;
- int nIndex = 0;
- DWORD DwWitten=0;
- while(nByteCount>0)
- {
- bytes = min(0xFF,(BYTE)nByteCount);
- nByteCount -= bytes;
-
-
- ::WriteFile(file,&bytes,1,&DwWitten,NULL);
- ::WriteFile(file,pByts+nIndex,bytes,&DwWitten,NULL);
- //file.Write(&bytes,1);
- //file.Write(pByts+nIndex,bytes);
-
- nIndex += bytes;
- }
- bytes = 0x0;
- //file.Write(&bytes,1);
- ::WriteFile(file,&bytes,1,&DwWitten,NULL);
- }
- BYTE GetColorIndex(RGBQUAD *pQuad, UINT nSize,BYTE r,BYTE g,BYTE b)
- {
- BYTE nIndex;
- long nDist,nRDist,nGDist,nBDist,nMinDist = 999999999;
-
- for(UINT i=0; i<nSize; i++)
- {
- nRDist = pQuad[i].rgbRed - r;
- nGDist = pQuad[i].rgbGreen - g;
- nBDist = pQuad[i].rgbBlue - b;
- nDist = nRDist*nRDist + nGDist*nGDist + nBDist*nBDist;
- //nDist = 0.3*abs(nRDist) + 0.59*abs(nGDist) + 0.11*abs(nBDist);
- if(nDist < nMinDist)
- {
- nIndex = (BYTE)i;
- nMinDist = nDist;
- if(nDist == 0)
- {
- break;
- }
- }
- }
-
- return nIndex;
- }
- BOOL GetData(HBITMAP hBmp,BYTE **ppPalette,BYTE **ppData,BYTE *pBitsPixel,int *pWidth,int *pHeight)
- {
- BITMAP bm;
- PBITMAPINFO bmpInf;
-
- if(GetObject(hBmp,sizeof(bm),&bm)==0)
- return FALSE;
-
- int nPaletteSize=0;
-
- if(bm.bmBitsPixel<16)
- nPaletteSize=(int)pow(2.0,bm.bmBitsPixel);
-
- bmpInf=(PBITMAPINFO)LocalAlloc(LPTR,sizeof(BITMAPINFOHEADER)+
- sizeof(RGBQUAD)*nPaletteSize+((bm.bmWidth*bm.bmBitsPixel+31)/32)*4*bm.bmHeight);
-
- BYTE* buf=((BYTE*)bmpInf) +
- sizeof(BITMAPINFOHEADER)+
- sizeof(RGBQUAD)*nPaletteSize;
-
- //-----------------------------------------------
- bmpInf->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
- bmpInf->bmiHeader.biWidth = bm.bmWidth;
- bmpInf->bmiHeader.biHeight = bm.bmHeight;
- bmpInf->bmiHeader.biPlanes = bm.bmPlanes;
- bmpInf->bmiHeader.biBitCount = bm.bmBitsPixel;
- bmpInf->bmiHeader.biCompression = BI_RGB;
- bmpInf->bmiHeader.biSizeImage = (bm.bmWidth+7)/8*bm.bmHeight*bm.bmBitsPixel;
- //-----------------------------------------------
-
- HDC hDC = ::GetWindowDC(NULL);
-
- if(!::GetDIBits(hDC,hBmp,0,(UINT)bm.bmHeight,buf,bmpInf,DIB_RGB_COLORS))
- {
- ::ReleaseDC(NULL,hDC);
- LocalFree(bmpInf);
- return FALSE;
- }
-
- ::ReleaseDC(NULL,hDC);
- *pWidth = bm.bmWidth;
- *pHeight = bm.bmHeight;
- *ppData = new BYTE[bm.bmWidth*bm.bmHeight];
- CQuantizer quan(256,8);
-
- bmpInf->bmiHeader.biSize = sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)*nPaletteSize;
- quan.ProcessImage(bmpInf);
- int nColorCount = quan.GetColorCount();
- RGBQUAD *pQuad = new RGBQUAD[nColorCount];
-
- quan.SetColorTable(pQuad);
-
- int nLnBytes;
-
- //每行数据是4字节的整数倍
- nLnBytes = ((bm.bmWidth*bm.bmBitsPixel+31)/32)*4;
- int nOffset,i,nIndex=0;
- BYTE r,g,b;
- UINT nColorIndex;
-
- switch(bm.bmBitsPixel)
- {
- case 1:
- case 4:
- case 8:
- {
- delete []pQuad;
- nColorCount = (int)pow(2.0,bm.bmBitsPixel);
- pQuad = new RGBQUAD[nColorCount];
- memcpy(pQuad,(BYTE*)bmpInf+sizeof(BITMAPINFOHEADER),sizeof(RGBQUAD)*nColorCount);
- for(i=bm.bmHeight-1; i>=0; i--)
- {
- nOffset = i*nLnBytes;
-
- for(int j=0; j<bm.bmWidth; j++)
- {
- if(bm.bmBitsPixel==8)
- {
- (*ppData)[nIndex++] = buf[nOffset+j];
- }
- else
- {
- BYTE pos;
- BYTE iDst= buf[nOffset + (j*bm.bmBitsPixel >> 3)];
- if (bm.bmBitsPixel==4)
- {
- pos = 4*(1-j%2);
- iDst &= (0x0F<<pos);
- (*ppData)[nIndex++] = iDst >> pos;
- }else if (bm.bmBitsPixel==1)
- {
- pos = 7-j%8;
- iDst &= (0x01<<pos);
- (*ppData)[nIndex++] = iDst >> pos;
- }
- }
- }
- }
- }
- break;
- case 15:
- case 16:
- for(i=bm.bmHeight-1; i>=0; i--)
- {
- nOffset = i*nLnBytes;
-
- for(int j=0; j<bm.bmWidth; j++)
- {
- b = buf[nOffset+j*2]&0x1F;
- g = buf[nOffset+j*2]>>5;
- g |= (buf[nOffset+j*2+1]&0x03)<<3;
- r = (buf[nOffset+j*2+1]>>2)&0x1F;
-
- r *= 8;
- b *= 8;
- g *= 8;
- quan.GetColorIndex(r,g,b,&nColorIndex);
- (*ppData)[nIndex++] = (BYTE)nColorIndex;
- }
- }
- break;
- case 24:
- for(i=bm.bmHeight-1; i>=0; i--)
- {
- nOffset = i*nLnBytes;
-
- for(int j=0; j<bm.bmWidth; j++)
- {
- b = buf[nOffset+j*3];
- g = buf[nOffset+j*3+1];
- r = buf[nOffset+j*3+2];
- quan.GetColorIndex(r,g,b,&nColorIndex);
- (*ppData)[nIndex++] = (BYTE)nColorIndex;
-
- //该算法效果好,但速度慢
- //pData[nIndex++]=GetColorIndex(pQuad,nColorCount,r,g,b);
- }
- }
- break;
- case 32:
- for(i=bm.bmHeight-1; i>=0; i--)
- {
- nOffset = i*nLnBytes;
-
- for(int j=0; j<bm.bmWidth; j++)
- {
- b = buf[nOffset+j*4];
- g = buf[nOffset+j*4+1];
- r = buf[nOffset+j*4+2];
- quan.GetColorIndex(r,g,b,&nColorIndex);
- (*ppData)[nIndex++] = (BYTE)nColorIndex;
- }
- }
- break;
- default:
- delete []pQuad;
- LocalFree(bmpInf);
- return FALSE;
- break;
- }
- *pBitsPixel = 8;
- if(nColorCount <= 8)
- {
- *pBitsPixel = 3;
- }
- else if(nColorCount <= 16)
- {
- *pBitsPixel = 4;
- }
- else if(nColorCount <= 32)
- {
- *pBitsPixel = 5;
- }
- else if(nColorCount <= 64)
- {
- *pBitsPixel = 6;
- }
- else if(nColorCount <= 128)
- {
- *pBitsPixel = 7;
- }
-
- int nGIFPaletteSize = (int)pow(2.0,(int)*pBitsPixel);
- *ppPalette = new BYTE[nGIFPaletteSize*3];
- memset(*ppPalette,0,nGIFPaletteSize*3);
-
- for(i=0; i<(int)nColorCount; i++)
- {
- (*ppPalette)[i*3] = pQuad[i].rgbRed;
- (*ppPalette)[i*3+1] = pQuad[i].rgbGreen;
- (*ppPalette)[i*3+2] = pQuad[i].rgbBlue;
- }
- delete []pQuad;
- LocalFree(bmpInf);
- return TRUE;
- }
- void EnCode(BYTE *pData,long nDataSize,BYTE bitsPixel,WORD **ppEnCodeData,long *pnSize)
- {
- WORD *pHeard = new WORD[4097];
- WORD *pEnd = new WORD[4096];
- int nDataBufIndex=0;
- //每幅图片最大1000000个像素
- *ppEnCodeData = new WORD[1000000];
- int nIndex =0;
- int nDataIndex = 0;
- pHeard[nIndex] = pData[nDataIndex];
- pEnd[nIndex] = pData[nDataIndex+1];
- nIndex++;
- nDataIndex++;
- WORD wHeard,wEnd;
- BOOL bEndIsValide = TRUE;
- WORD wBeginCode = (((WORD)1)<<bitsPixel)+2;
- //编码
- for(; nDataIndex<nDataSize; )
- {
- wHeard = pData[nDataIndex];
- if(nDataIndex+1 >= nDataSize)
- {
- pHeard[nIndex] = wHeard;
- nIndex++;
- bEndIsValide = FALSE;
- break;
- }
- wEnd = pData[nDataIndex+1];
- nDataIndex++;
- for(int i=0; i<nIndex; i++)
- {
- if( (pHeard[i] == wHeard) && (pEnd[i] == wEnd) )
- {
- wHeard = wBeginCode+i;
- if(nDataIndex+1 >= nDataSize)
- {
- pHeard[nIndex] = wHeard;
- nIndex++;
- bEndIsValide = FALSE;
- break;
- }
-
- wEnd = pData[nDataIndex+1];
- nDataIndex++;
- }
- }
-
- pHeard[nIndex] = wHeard;
-
- if(bEndIsValide)
- {
- pEnd[nIndex] = wEnd;
- nIndex++;
- }
- else
- {
- break;
- }
-
- //达到4096(12位)后,重新开始编码
- if(wBeginCode+nIndex-1 == 4096)
- {
- memcpy( ((BYTE*)*ppEnCodeData)+nDataBufIndex,pHeard,nIndex*2);
- nDataBufIndex += nIndex*2;
- nIndex = 0;
-
- pHeard[nIndex] = pData[nDataIndex];
- pEnd[nIndex] = pData[nDataIndex+1];
- nIndex++;
- nDataIndex++;
- }
- }
-
- memcpy( ((BYTE*)*ppEnCodeData)+nDataBufIndex,pHeard,nIndex*2);
- nDataBufIndex += nIndex*2;
- *pnSize = nDataBufIndex/2;
- delete []pHeard;
- delete []pEnd;
- }
- typedef struct _GraphicController
- {
- BYTE extensionIntroducer;
- BYTE graphicControlLabel;
- BYTE blockSize;
- BYTE packedField;
- WORD nDelayTime;
- BYTE transparentColorIndex;
- BYTE blockTerminator;
- }GraphicController;
- typedef struct _ApplicationExtension
- {
- BYTE extensionIntroducer;
- BYTE applicationLabel;
- BYTE blockSize;
- char applicationId[8];
- char appAuthCode[3];
- char cAppData[4];
- BYTE blockTerminator;
- }ApplicationExtension;
- void CreateGIFHeard(HANDLE file,WORD nImageWidth,WORD nImageHeight,BYTE bitsPixel)
- {
- //GIF文件头,89a格式
- GIFHEARD heard;
- memcpy(heard.Signature,"GIF89a",6);
- heard.ScreenWidth = nImageWidth;
- heard.ScreenHeight = nImageHeight;
- //heard.GlobalFlagByte = HASPalette|((bitsPixel-1)<<4)|0|(bitsPixel-1);全局调色板
- heard.GlobalFlagByte = ((bitsPixel-1)<<4);
- heard.BackGroundColor = 0;
- heard.AspectRatio = 0;
- DWORD DwWitten=0;
- ::WriteFile(file,&heard,13,&DwWitten,NULL);
- //file.Write(&heard,13);//不要用sizeof(GIFHEARD),除非把编译器设为1字节对齐
-
- //为了让IE循环播放,必须加入该应用程序块(如果只有一幅图片,可省略该块)
- ApplicationExtension appData;
- appData.extensionIntroducer = 0x21;
- appData.applicationLabel = 0xFF;
- appData.blockSize = 11;
- memcpy(appData.applicationId,"NETSCAPE",8);
- memcpy(appData.appAuthCode,"2.0",3);
- appData.cAppData[0] = 3;
- appData.cAppData[1] = 1;
- appData.cAppData[2] = 0;
- appData.cAppData[3] = 0;
- appData.blockTerminator = 0;
-
-
- ::WriteFile(file,&appData,sizeof(ApplicationExtension),&DwWitten,NULL);
- //file.Write(&appData,sizeof(ApplicationExtension));
- }
- void AddImageToGIF(HANDLE file,BYTE *pData,BYTE *palette,WORD nImageWidth,WORD nImageHeight,BYTE bitsPixel,WORD nDelay,
- short int nTransparentColorIndex)
- {
- //控制块
- GraphicController control;
-
- control.extensionIntroducer = 0x21;
- control.graphicControlLabel = 0xF9;
- control.blockSize = 4;
- control.packedField = (nTransparentColorIndex==-1? 4:5);
- control.nDelayTime = nDelay;//延迟时间
- control.transparentColorIndex = (BYTE)(nTransparentColorIndex==-1? 0:nTransparentColorIndex);
- control.blockTerminator = 0;
-
- //file.Write(&control,sizeof(GraphicController));
- DWORD DwWitten=0;
- ::WriteFile(file,&control,sizeof(GraphicController),&DwWitten,NULL);
- ////file.Write(palette,nGIFPaletteSize*3);全局调色板
- //图片数据头
- GIFDATAHEARD dataHeard;
- dataHeard.imageLabel = 0x2c;
- dataHeard.imageLeft = 0;
- dataHeard.imageTop = 0;
- dataHeard.imageWidth = nImageWidth;
- dataHeard.imageHeight = nImageHeight;
- dataHeard.localFlagByte = HASPalette|(bitsPixel-1);
-
- ::WriteFile(file,&dataHeard.imageLabel,1,&DwWitten,NULL);
- ::WriteFile(file,&dataHeard.imageLeft,2,&DwWitten,NULL);
- ::WriteFile(file,&dataHeard.imageTop,2,&DwWitten,NULL);
- ::WriteFile(file,&dataHeard.imageWidth,2,&DwWitten,NULL);
- ::WriteFile(file,&dataHeard.imageHeight,2,&DwWitten,NULL);
- ::WriteFile(file,&dataHeard.localFlagByte,1,&DwWitten,NULL);
- //file.Write(&dataHeard.imageLabel,1);
- //file.Write(&dataHeard.imageLeft,2);
- //file.Write(&dataHeard.imageTop,2);
- //file.Write(&dataHeard.imageWidth,2);
- //file.Write(&dataHeard.imageHeight,2);
- //file.Write(&dataHeard.localFlagByte,1);
-
- //调色板
- //file.Write(palette,(int)pow(2,bitsPixel)*3);
- ::WriteFile(file,palette,(int)pow(2.0,bitsPixel)*3,&DwWitten,NULL);
- //每像素占用位数
- //file.Write(&bitsPixel,1);
- ::WriteFile(file,&bitsPixel,1,&DwWitten,NULL);
-
- WORD *pEnCodeData = NULL;
- long nSize = 0;
- //编码
- EnCode(pData,nImageWidth*nImageHeight,bitsPixel,&pEnCodeData,&nSize);
-
- //写入数据
- WriteData(file,pEnCodeData,nSize,bitsPixel,TRUE);
-
- delete []pEnCodeData;
- }
- void CloseGIF(HANDLE file)
- {
- //写入结束标志
- BYTE bytes = 0x3B;
- //file.Write(&bytes,1);
- DWORD DwWitten=0;
- ::WriteFile(file,&bytes,1,&DwWitten,NULL);
- }
|