//GIF编码 //编写者:高书克 //日 期:2004-12-6 #include #include #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< 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 8) { addToBuf(file,pByts,nUsedBits,(nClearCode&0xFF00)>>8,nCurCodeBits-8); } int nHeardCode = nClearCode+1; for(int i=0; i= 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< 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; ibmiHeader.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> 3)]; if (bm.bmBitsPixel==4) { pos = 4*(1-j%2); iDst &= (0x0F<> pos; }else if (bm.bmBitsPixel==1) { pos = 7-j%8; iDst &= (0x01<> pos; } } } } } break; case 15: case 16: for(i=bm.bmHeight-1; i>=0; i--) { nOffset = i*nLnBytes; for(int j=0; j>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=0; i--) { nOffset = i*nLnBytes; for(int j=0; j= nDataSize) { pHeard[nIndex] = wHeard; nIndex++; bEndIsValide = FALSE; break; } wEnd = pData[nDataIndex+1]; nDataIndex++; for(int i=0; i= 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); }