123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424 |
- #include "stdafx.h"
- #include "Quantizer.h"
- #include <MATH.H>
- /////////////////////////////////////////////////////////////////////////////
- CQuantizer::CQuantizer (UINT nMaxColors, UINT nColorBits)
- {
- m_nColorBits = nColorBits < 8 ? nColorBits : 8;
- m_pTree = NULL;
- m_nLeafCount = 0;
- for (int i=0; i<=(int) m_nColorBits; i++)
- m_pReducibleNodes[i] = NULL;
- m_nMaxColors = nMaxColors;
- }
- /////////////////////////////////////////////////////////////////////////////
- CQuantizer::~CQuantizer ()
- {
- if (m_pTree != NULL)
- DeleteTree (&m_pTree);
- }
- /////////////////////////////////////////////////////////////////////////////
- BOOL CQuantizer::ProcessImage (HANDLE hImage)
- {
- BYTE r, g, b;
- int i, j;
- BITMAPINFOHEADER ds;
- memcpy(&ds,hImage, sizeof(ds));
- int effwdt = ((((ds.biBitCount * ds.biWidth ) + 31) / 32) * 4);
- int nPad = effwdt - (((ds.biWidth * ds.biBitCount) + 7) / 8);
- BYTE* pbBits = (BYTE*)hImage + *(LPDWORD)hImage;
- switch (ds.biBitCount) {
- case 1: // 1-bit DIB
- case 4: // 4-bit DIB
- case 8: // 8-bit DIB
- for (i=0; i<ds.biHeight; i++) {
- for (j=0; j<ds.biWidth; j++) {
- BYTE idx=GetPixelIndex(j,i,ds.biBitCount,effwdt,pbBits);
- BYTE* pal = (BYTE*)(hImage) + sizeof(BITMAPINFOHEADER);
- long ldx = idx*sizeof(RGBQUAD);
- b = pal[ldx++];
- g = pal[ldx++];
- r = pal[ldx];
- AddColor (&m_pTree, r, g, b, m_nColorBits, 0, &m_nLeafCount,
- m_pReducibleNodes);
- while (m_nLeafCount > m_nMaxColors)
- ReduceTree (m_nColorBits, &m_nLeafCount,
- m_pReducibleNodes);
- }
- }
- break;
- case 15:
- case 16://16bit
- for (i=0; i<ds.biHeight; i++)
- {
- for (j=0; j<ds.biWidth; j++)
- {
- b = (*pbBits)&0x1F;
- g = (*pbBits++)>>5;
- g |= ((*pbBits)&0x03)<<3;
- r = ((*pbBits++)>>2)&0x1F;
- r *= 8;
- b *= 8;
- g *= 8;
-
- AddColor (&m_pTree, r, g, b, m_nColorBits, 0, &m_nLeafCount,
- m_pReducibleNodes);
- while (m_nLeafCount > m_nMaxColors)
- ReduceTree (m_nColorBits, &m_nLeafCount, m_pReducibleNodes);
- }
- pbBits += nPad;
- }
- break;
- case 24: // 24-bit DIB
- for (i=0; i<ds.biHeight; i++) {
- for (j=0; j<ds.biWidth; j++) {
- b = *pbBits++;
- g = *pbBits++;
- r = *pbBits++;
- AddColor (&m_pTree, r, g, b, m_nColorBits, 0, &m_nLeafCount,
- m_pReducibleNodes);
- while (m_nLeafCount > m_nMaxColors)
- ReduceTree (m_nColorBits, &m_nLeafCount, m_pReducibleNodes);
- }
- pbBits += nPad;
- }
- break;
- case 32: // 32-bit DIB
- for (i=0; i<ds.biHeight; i++) {
- for (j=0; j<ds.biWidth; j++) {
- b = *pbBits++;
- g = *pbBits++;
- r = *pbBits++;
- pbBits++;
- AddColor (&m_pTree, r, g, b, m_nColorBits, 0, &m_nLeafCount,
- m_pReducibleNodes);
- while (m_nLeafCount > m_nMaxColors)
- ReduceTree (m_nColorBits, &m_nLeafCount, m_pReducibleNodes);
- }
- pbBits += nPad;
- }
- break;
- default: // Unrecognized color format
- return FALSE;
- }
- return TRUE;
- }
- /////////////////////////////////////////////////////////////////////////////
- void CQuantizer::AddColor (NODE** ppNode, BYTE r, BYTE g, BYTE b,
- UINT nColorBits, UINT nLevel, UINT* pLeafCount, NODE** pReducibleNodes)
- {
- static BYTE mask[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
- // If the node doesn't exist, create it.
- if (*ppNode == NULL)
- *ppNode = (NODE*)CreateNode (nLevel, nColorBits, pLeafCount, pReducibleNodes);
- // Update color information if it's a leaf node.
- if ((*ppNode)->bIsLeaf)
- {
- (*ppNode)->nPixelCount++;
- (*ppNode)->nRedSum += r;
- (*ppNode)->nGreenSum += g;
- (*ppNode)->nBlueSum += b;
- } else
- { // Recurse a level deeper if the node is not a leaf.
- int shift = 7 - nLevel;
- int nIndex =(((r & mask[nLevel]) >> shift) << 2) |
- (((g & mask[nLevel]) >> shift) << 1) |
- (( b & mask[nLevel]) >> shift);
- AddColor(&((*ppNode)->pChild[nIndex]), r, g, b, nColorBits,
- nLevel + 1, pLeafCount, pReducibleNodes);
- }
- }
- /////////////////////////////////////////////////////////////////////////////
- void* CQuantizer::CreateNode (UINT nLevel, UINT nColorBits, UINT* pLeafCount,
- NODE** pReducibleNodes)
- {
- NODE* pNode = (NODE*)calloc(1,sizeof(NODE));
- if (pNode== NULL) return NULL;
- pNode->bIsLeaf = (nLevel == nColorBits) ? TRUE : FALSE;
- if (pNode->bIsLeaf) (*pLeafCount)++;
- else {
- pNode->pNext = pReducibleNodes[nLevel];
- pReducibleNodes[nLevel] = pNode;
- }
- return pNode;
- }
- /////////////////////////////////////////////////////////////////////////////
- void CQuantizer::ReduceTree (UINT nColorBits, UINT* pLeafCount,
- NODE** pReducibleNodes)
- {
- int i;
- // Find the deepest level containing at least one reducible node.
- for (i=nColorBits - 1; (i>0) && (pReducibleNodes[i] == NULL); i--);
- // Reduce the node most recently added to the list at level i.
- NODE* pNode = pReducibleNodes[i];
- pReducibleNodes[i] = pNode->pNext;
- NODE* pNodeTmp = pNode;
- NODE* pNeedReduceNode = NULL,*pPreNode = NULL,*pPreNodeTmp = NULL;
- long nMinPixelCount = 0;
- while(pNodeTmp)
- {
- long nPixelCount = 0;
- for (int m=0; m<8; m++)
- {
- if (pNodeTmp->pChild[m] != NULL)
- {
- nPixelCount += pNodeTmp->pChild[m]->nPixelCount;
- }
- }
- if(nMinPixelCount == 0)
- {
- nMinPixelCount = nPixelCount;
- pNeedReduceNode = pNodeTmp;
- }
- else if(nPixelCount < nMinPixelCount)
- {
- nMinPixelCount = nPixelCount;
- pNeedReduceNode = pNodeTmp;
- pPreNode = pPreNodeTmp;
- }
- pPreNodeTmp = pNodeTmp;
- pNodeTmp = pNodeTmp->pNext;
- }
- if(pPreNode)
- {
- pPreNode->pNext = pNeedReduceNode->pNext;
- pReducibleNodes[i] = pNode;
- }
- pNode = pNeedReduceNode;
- UINT nRedSum = 0;
- UINT nGreenSum = 0;
- UINT nBlueSum = 0;
- UINT nChildren = 0;
- for (i=0; i<8; i++)
- {
- if (pNode->pChild[i] != NULL)
- {
- nRedSum += pNode->pChild[i]->nRedSum;
- nGreenSum += pNode->pChild[i]->nGreenSum;
- nBlueSum += pNode->pChild[i]->nBlueSum;
- pNode->nPixelCount += pNode->pChild[i]->nPixelCount;
- free(pNode->pChild[i]);
- pNode->pChild[i] = NULL;
- nChildren++;
- }
- }
- pNode->bIsLeaf = TRUE;
- pNode->nRedSum = nRedSum;
- pNode->nGreenSum = nGreenSum;
- pNode->nBlueSum = nBlueSum;
- *pLeafCount -= (nChildren - 1);
- }
- /////////////////////////////////////////////////////////////////////////////
- void CQuantizer::DeleteTree (NODE** ppNode)
- {
- for (int i=0; i<8; i++) {
- if ((*ppNode)->pChild[i] != NULL) DeleteTree (&((*ppNode)->pChild[i]));
- }
- free(*ppNode);
- *ppNode = NULL;
- }
- BOOL CQuantizer::FindColorIndex(NODE *pNode,BYTE r,BYTE g,BYTE b,int nLevel,UINT *pColorIndex)
- {
- static BYTE mask[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
- // If the node doesn't exist, create it.
- if (pNode == NULL)
- {
- return FALSE;
- }
- // Update color information if it's a leaf node.
- if (pNode->bIsLeaf)
- {
- *pColorIndex = pNode->nColorIndex;
- return TRUE;
- }
-
- // Recurse a level deeper if the node is not a leaf.
- int shift = 7 - nLevel;
- int nIndex =(((r & mask[nLevel]) >> shift) << 2) |
- (((g & mask[nLevel]) >> shift) << 1) |
- (( b & mask[nLevel]) >> shift);
- return FindColorIndex(pNode->pChild[nIndex], r, g, b, nLevel+1, pColorIndex);
- }
- BOOL CQuantizer::GetColorIndex(BYTE r,BYTE g,BYTE b,UINT *pColorIndex)
- {
- return FindColorIndex(m_pTree,r,g,b,0,pColorIndex);
- }
- /////////////////////////////////////////////////////////////////////////////
- void CQuantizer::GetPaletteColors (NODE* pTree, RGBQUAD* prgb, UINT* pIndex)
- {
- if (pTree){
- if (pTree->bIsLeaf) {
- prgb[*pIndex].rgbRed = (BYTE)((pTree->nRedSum)/(pTree->nPixelCount));
- prgb[*pIndex].rgbGreen = (BYTE)((pTree->nGreenSum)/(pTree->nPixelCount));
- prgb[*pIndex].rgbBlue = (BYTE)((pTree->nBlueSum)/(pTree->nPixelCount));
- prgb[*pIndex].rgbReserved = 0;
- pTree->nColorIndex = *pIndex;
- (*pIndex)++;
- } else {
- for (int i=0; i<8; i++) {
- if (pTree->pChild[i] != NULL)
- GetPaletteColors (pTree->pChild[i], prgb, pIndex);
- }
- }
- }
- }
- /////////////////////////////////////////////////////////////////////////////
- UINT CQuantizer::GetColorCount ()
- {
- return m_nLeafCount;
- }
- /////////////////////////////////////////////////////////////////////////////
- void CQuantizer::SetColorTable (RGBQUAD* prgb)
- {
- UINT nIndex = 0;
- GetPaletteColors (m_pTree, prgb, &nIndex);
- }
- /////////////////////////////////////////////////////////////////////////////
- BYTE CQuantizer::GetPixelIndex(long x, long y, int nbit, long effwdt, BYTE *pimage)
- {
- if (nbit==8)
- {
- return pimage[y*effwdt + x];
- } else
- {
- BYTE pos;
- BYTE iDst= pimage[y*effwdt + (x*nbit >> 3)];
- if (nbit==4)
- {
- pos = 4*(1-x%2);
- iDst &= (0x0F<<pos);
- return iDst >> pos;
- } else if (nbit==1)
- {
- pos = 7-x%8;
- iDst &= (0x01<<pos);
- return iDst >> pos;
- }
- }
- return 0;
- }
- CRGBQuantizer::CRGBQuantizer(UINT nMaxColors, UINT nColorBits)
- :CQuantizer(nMaxColors,nColorBits)
- {
- }
- BOOL CRGBQuantizer::ProcessImageRGB(BYTE *pRGBData,UINT nWidth,UINT nHeight)
- {
- BYTE r,g,b;
- for (int i=0; i<nHeight; i++)
- {
- for (int j=0; j<nWidth; j++)
- {
- r = *pRGBData++;
- g = *pRGBData++;
- b = *pRGBData++;
- AddColor (&m_pTree, r, g, b, m_nColorBits, 0, &m_nLeafCount,
- m_pReducibleNodes);
- while (m_nLeafCount > m_nMaxColors)
- ReduceTree (m_nColorBits, &m_nLeafCount, m_pReducibleNodes);
- }
- }
- return TRUE;
- }
- CBitmapQuantizer::CBitmapQuantizer(UINT nMaxColors, UINT nColorBits)
- :CQuantizer(nMaxColors,nColorBits)
- {
- }
- BOOL CBitmapQuantizer::ProcessImageBitmap (HBITMAP hBmp)
- {
- 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+7)/8*bm.bmHeight*bm.bmBitsPixel);
- 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;
- bmpInf->bmiHeader.biXPelsPerMeter = 0;
- bmpInf->bmiHeader.biYPelsPerMeter = 0;
- bmpInf->bmiHeader.biClrUsed = 0;
- bmpInf->bmiHeader.biClrImportant = 0;
- //-----------------------------------------------
- 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);
- bmpInf->bmiHeader.biSize = sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)*nPaletteSize;
- BOOL bRet = ProcessImage(bmpInf);
- LocalFree(bmpInf);
- return bRet;
- }
|