123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636 |
- //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);
- }
|