123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428 |
- #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;
- }
|