CqOctree.cpp
上传用户:elida16851
上传日期:2022-08-05
资源大小:2048k
文件大小:12k
源码类别:

图形图象

开发平台:

Visual C++

  1. /******************************************************************
  2. CqOctree.CPP
  3.   Performing Color Quantization using Octree algorithm
  4.   The 2 functions for global use is
  5.   HPALETTE CreateOctreePalette (HBITMAP hImage, UINT nMaxColors, UINT nColorBits)
  6.   HPALETTE CreateOctreePalette (LPSTR lpDIB, UINT nMaxColors, UINT nColorBits)
  7.   For using convenience, define it in DIBAPI.H
  8. ******************************************************************/
  9. #include "stdafx.h"
  10. #include "dibapi.h"
  11. // Structure use internally
  12. typedef struct _NODE 
  13. {
  14.     BOOL bIsLeaf;               // TRUE if node has no children
  15.     UINT nPixelCount;           // Number of pixels represented by this leaf
  16.     UINT nRedSum;               // Sum of red components
  17.     UINT nGreenSum;             // Sum of green components
  18.     UINT nBlueSum;              // Sum of blue components
  19.     struct _NODE* pChild[8];    // Pointers to child nodes
  20.     struct _NODE* pNext;        // Pointer to next reducible node
  21. } NODE;
  22. // Function prototypes
  23. //Global use, define it in dibapi.h
  24. //HPALETTE CreateOctreePalette (HDIB hDIB, UINT nMaxColors, UINT nColorBits)
  25. //HPALETTE CreateOctreePalette (LPSTR lpDIB, UINT nMaxColors, UINT nColorBits)
  26. //Local use only
  27. HPALETTE BuildOctreePalette(HANDLE hImage, UINT nMaxColors, UINT nColorBits);
  28. void AddColor (NODE**, BYTE, BYTE, BYTE, UINT, UINT, UINT*, NODE**);
  29. NODE* CreateNode (UINT, UINT, UINT*, NODE**);
  30. void ReduceTree (UINT, UINT*, NODE**);
  31. void DeleteTree (NODE**);
  32. void GetPaletteColors (NODE*, PALETTEENTRY*, UINT*);
  33. int GetRightShiftCount (DWORD);
  34. int GetLeftShiftCount (DWORD);
  35. // Function body
  36. HPALETTE CreateOctreePalette(HDIB hDIB, UINT nMaxColors, UINT nColorBits)
  37. {
  38. HANDLE hImage;
  39. hImage = DIBToDIBSection(hDIB);
  40. if (! hImage)
  41. return NULL;
  42. return BuildOctreePalette(hImage, nMaxColors, nColorBits);
  43. }
  44. HPALETTE CreateOctreePalette(LPBYTE lpDIB, UINT nMaxColors, UINT nColorBits)
  45. {
  46. HANDLE hImage;
  47. hImage = DIBToDIBSection(lpDIB);
  48. if (! hImage)
  49. return NULL;
  50. return BuildOctreePalette(hImage, nMaxColors, nColorBits);
  51. }
  52. HPALETTE BuildOctreePalette(HANDLE hImage, UINT nMaxColors, UINT nColorBits)
  53. {
  54.     DIBSECTION ds;
  55.     int i, j, nPad;
  56.     BYTE* pbBits;
  57.     WORD* pwBits;
  58.     DWORD* pdwBits;
  59.     DWORD rmask, gmask, bmask;
  60.     int rright, gright, bright;
  61.     int rleft, gleft, bleft;
  62.     BYTE r, g, b;
  63.     WORD wColor;
  64.     DWORD dwColor, dwSize;
  65.     LOGPALETTE* plp;
  66.     HPALETTE hPalette;
  67.     NODE* pTree;
  68.     UINT nLeafCount, nIndex;
  69.     NODE* pReducibleNodes[9];
  70.     HDC hdc;    
  71. BYTE* pBuffer;    
  72. BITMAPINFO bmi;
  73.     // Initialize octree variables
  74.     pTree = NULL;
  75.     nLeafCount = 0;
  76.     if (nColorBits > 8) // Just in case
  77.         return NULL;
  78.     for (i=0; i<=(int) nColorBits; i++)
  79.         pReducibleNodes[i] = NULL;
  80.     // Scan the DIB and build the octree
  81.     GetObject (hImage, sizeof (ds), &ds);
  82.     nPad = ds.dsBm.bmWidthBytes - (((ds.dsBmih.biWidth *
  83.         ds.dsBmih.biBitCount) + 7) / 8);
  84.     switch (ds.dsBmih.biBitCount) {
  85.     case 1: // 1-bit DIB    
  86. case 4: // 4-bit DIB    
  87. case 8: // 8-bit DIB
  88.         //        
  89. // The strategy here is to use ::GetDIBits to convert the
  90.         // image into a 24-bit DIB one scan line at a time. A pleasant
  91.         // side effect of using ::GetDIBits in this manner is that RLE-
  92.         // encoded 4-bit and 8-bit DIBs will be uncompressed.        //
  93.         hdc = GetDC (NULL);        
  94. pBuffer = new BYTE[ds.dsBmih.biWidth * 3 + 64];
  95.         ZeroMemory (&bmi, sizeof (bmi));
  96.         bmi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
  97.         bmi.bmiHeader.biWidth = ds.dsBmih.biWidth;
  98.         bmi.bmiHeader.biHeight = ds.dsBmih.biHeight;
  99.         bmi.bmiHeader.biPlanes = 1;        
  100. bmi.bmiHeader.biBitCount = 24;
  101.         bmi.bmiHeader.biCompression = BI_RGB;
  102.         for (i=0; i<ds.dsBmih.biHeight; i++) 
  103. {
  104.             GetDIBits (hdc, (HBITMAP) hImage, i, 1, pBuffer, &bmi,
  105.                 DIB_RGB_COLORS);            
  106. pbBits = pBuffer;
  107.             for (j=0; j<ds.dsBmih.biWidth; j++) 
  108. {                
  109. b = *pbBits++;
  110.                 g = *pbBits++;                
  111. r = *pbBits++;
  112.                 AddColor (&pTree, r, g, b, nColorBits, 0, &nLeafCount,
  113.                           pReducibleNodes);
  114.                 while (nLeafCount > nMaxColors)
  115.                     ReduceTree (nColorBits, &nLeafCount, pReducibleNodes);            
  116. }        
  117. }
  118.         delete pBuffer;        
  119. ReleaseDC (NULL, hdc);        
  120. break;    
  121. case 16: // One case for 16-bit DIBs
  122.         if (ds.dsBmih.biCompression == BI_BITFIELDS) {
  123.             rmask = ds.dsBitfields[0];
  124.             gmask = ds.dsBitfields[1];
  125.             bmask = ds.dsBitfields[2];
  126.         }
  127.         else {
  128.             rmask = 0x7C00;
  129.             gmask = 0x03E0;
  130.             bmask = 0x001F;
  131.         }
  132.         rright = GetRightShiftCount (rmask);
  133.         gright = GetRightShiftCount (gmask);
  134.         bright = GetRightShiftCount (bmask);
  135.         rleft = GetLeftShiftCount (rmask);
  136.         gleft = GetLeftShiftCount (gmask);
  137.         bleft = GetLeftShiftCount (bmask);
  138.         pwBits = (WORD*) ds.dsBm.bmBits;
  139.         for (i=0; i<ds.dsBmih.biHeight; i++) {
  140.             for (j=0; j<ds.dsBmih.biWidth; j++) {
  141.                 wColor = *pwBits++;
  142.                 b = (BYTE) (((wColor & (WORD) bmask) >> bright) << bleft);
  143.                 g = (BYTE) (((wColor & (WORD) gmask) >> gright) << gleft);
  144.                 r = (BYTE) (((wColor & (WORD) rmask) >> rright) << rleft);
  145.                 AddColor (&pTree, r, g, b, nColorBits, 0, &nLeafCount,
  146.                           pReducibleNodes);
  147.                 while (nLeafCount > nMaxColors)
  148.                     ReduceTree (nColorBits, &nLeafCount, pReducibleNodes);
  149.             }
  150.             pwBits = (WORD*) (((BYTE*) pwBits) + nPad);
  151.         }
  152.         break;
  153.     case 24: // Another for 24-bit DIBs
  154.         pbBits = (BYTE*) ds.dsBm.bmBits;
  155.         for (i=0; i<ds.dsBmih.biHeight; i++) {
  156.             for (j=0; j<ds.dsBmih.biWidth; j++) {
  157.                 b = *pbBits++;
  158.                 g = *pbBits++;
  159.                 r = *pbBits++;
  160.                 AddColor (&pTree, r, g, b, nColorBits, 0, &nLeafCount,
  161.                           pReducibleNodes);
  162.                 while (nLeafCount > nMaxColors)
  163.                     ReduceTree (nColorBits, &nLeafCount, pReducibleNodes);
  164.             }
  165.             pbBits += nPad;
  166.         }
  167.         break;
  168.     case 32: // And another for 32-bit DIBs
  169.         if (ds.dsBmih.biCompression == BI_BITFIELDS) {
  170.             rmask = ds.dsBitfields[0];
  171.             gmask = ds.dsBitfields[1];
  172.             bmask = ds.dsBitfields[2];
  173.         }
  174.         else {
  175.             rmask = 0x00FF0000;
  176.             gmask = 0x0000FF00;
  177.             bmask = 0x000000FF;
  178.         }
  179.         rright = GetRightShiftCount (rmask);
  180.         gright = GetRightShiftCount (gmask);
  181.         bright = GetRightShiftCount (bmask);
  182.         pdwBits = (DWORD*) ds.dsBm.bmBits;
  183.         for (i=0; i<ds.dsBmih.biHeight; i++) {
  184.             for (j=0; j<ds.dsBmih.biWidth; j++) {
  185.                 dwColor = *pdwBits++;
  186.                 b = (BYTE) ((dwColor & bmask) >> bright);
  187.                 g = (BYTE) ((dwColor & gmask) >> gright);
  188.                 r = (BYTE) ((dwColor & rmask) >> rright);
  189.                 AddColor (&pTree, r, g, b, nColorBits, 0, &nLeafCount,
  190.                           pReducibleNodes);
  191.                 while (nLeafCount > nMaxColors)
  192.                     ReduceTree (nColorBits, &nLeafCount, pReducibleNodes);
  193.             }
  194.             pdwBits = (DWORD*) (((BYTE*) pdwBits) + nPad);
  195.         }
  196.         break;
  197.     default: // DIB must be 16, 24, or 32-bit!
  198.         return NULL;
  199.     }
  200.     if (nLeafCount > nMaxColors) { // Sanity check
  201.         DeleteTree (&pTree);
  202.         return NULL;
  203.     }
  204.     // Create a logical palette from the colors in the octree
  205.     dwSize = sizeof (LOGPALETTE) + ((nLeafCount - 1) * sizeof (PALETTEENTRY));
  206.     if ((plp = (LOGPALETTE*) HeapAlloc (GetProcessHeap (), 0,
  207.         dwSize)) == NULL) {
  208.         DeleteTree (&pTree);
  209.         return NULL;
  210.     }
  211.     plp->palVersion = 0x300;
  212.     plp->palNumEntries = (WORD) nLeafCount;
  213.     nIndex = 0;
  214.     GetPaletteColors (pTree, plp->palPalEntry, &nIndex);
  215.     hPalette = CreatePalette (plp);
  216.     HeapFree (GetProcessHeap (), 0, plp);
  217.     DeleteTree (&pTree);
  218.     return hPalette;
  219. }
  220. void AddColor (NODE** ppNode, BYTE r, BYTE g, BYTE b, UINT nColorBits,
  221.     UINT nLevel, UINT* pLeafCount, NODE** pReducibleNodes)
  222. {
  223.     int nIndex, shift;
  224.     static BYTE mask[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
  225.     // If the node doesn't exist, create it
  226.     if (*ppNode == NULL)
  227.         *ppNode = CreateNode (nLevel, nColorBits, pLeafCount,
  228.                               pReducibleNodes);
  229.     // Update color information if it's a leaf node
  230.     if ((*ppNode)->bIsLeaf) {
  231.         (*ppNode)->nPixelCount++;
  232.         (*ppNode)->nRedSum += r;
  233.         (*ppNode)->nGreenSum += g;
  234.         (*ppNode)->nBlueSum += b;
  235.     }
  236.     // Recurse a level deeper if the node is not a leaf
  237.     else {
  238.         shift = 7 - nLevel;
  239.         nIndex = (((r & mask[nLevel]) >> shift) << 2) |
  240.             (((g & mask[nLevel]) >> shift) << 1) |
  241.             ((b & mask[nLevel]) >> shift);
  242.         AddColor (&((*ppNode)->pChild[nIndex]), r, g, b, nColorBits,
  243.                   nLevel + 1, pLeafCount, pReducibleNodes);
  244.     }
  245. }
  246. NODE* CreateNode (UINT nLevel, UINT nColorBits, UINT* pLeafCount,
  247.                   NODE** pReducibleNodes)
  248. {
  249.     NODE* pNode;
  250.     if ((pNode = (NODE*) HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY,
  251.         sizeof (NODE))) == NULL)
  252.         return NULL;
  253.     pNode->bIsLeaf = (nLevel == nColorBits) ? TRUE : FALSE;
  254.     if (pNode->bIsLeaf)
  255.         (*pLeafCount)++;
  256.     else { // Add the node to the reducible list for this level
  257.         pNode->pNext = pReducibleNodes[nLevel];
  258.         pReducibleNodes[nLevel] = pNode;
  259.     }
  260.     return pNode;
  261. }
  262. void ReduceTree (UINT nColorBits, UINT* pLeafCount, NODE** pReducibleNodes)
  263. {
  264.     int i;
  265.     NODE* pNode;
  266.     UINT nRedSum, nGreenSum, nBlueSum, nChildren;
  267.     // Find the deepest level containing at least one reducible node
  268.     for (i=nColorBits - 1; (i>0) && (pReducibleNodes[i] == NULL); i--);
  269.     // Reduce the node most recently added to the list at level i
  270.     pNode = pReducibleNodes[i];
  271.     pReducibleNodes[i] = pNode->pNext;
  272.     nRedSum = nGreenSum = nBlueSum = nChildren = 0;
  273.     for (i=0; i<8; i++) {
  274.         if (pNode->pChild[i] != NULL) {
  275.             nRedSum += pNode->pChild[i]->nRedSum;
  276.             nGreenSum += pNode->pChild[i]->nGreenSum;
  277.             nBlueSum += pNode->pChild[i]->nBlueSum;
  278.             pNode->nPixelCount += pNode->pChild[i]->nPixelCount;
  279.             HeapFree (GetProcessHeap (), 0, pNode->pChild[i]);
  280.             pNode->pChild[i] = NULL;
  281.             nChildren++;
  282.         }
  283.     }
  284.     pNode->bIsLeaf = TRUE;
  285.     pNode->nRedSum = nRedSum;
  286.     pNode->nGreenSum = nGreenSum;
  287.     pNode->nBlueSum = nBlueSum;
  288.     *pLeafCount -= (nChildren - 1);
  289. }
  290. void DeleteTree (NODE** ppNode)
  291. {
  292.     int i;
  293.     for (i=0; i<8; i++) {
  294.         if ((*ppNode)->pChild[i] != NULL)
  295.             DeleteTree (&((*ppNode)->pChild[i]));
  296.     }
  297.     HeapFree (GetProcessHeap (), 0, *ppNode);
  298.     *ppNode = NULL;
  299. }
  300. void GetPaletteColors (NODE* pTree, PALETTEENTRY* pPalEntries, UINT* pIndex)
  301. {
  302.     int i;
  303.     if (pTree->bIsLeaf) {
  304.         pPalEntries[*pIndex].peRed =
  305.             (BYTE) ((pTree->nRedSum) / (pTree->nPixelCount));
  306.         pPalEntries[*pIndex].peGreen =
  307.             (BYTE) ((pTree->nGreenSum) / (pTree->nPixelCount));
  308.         pPalEntries[*pIndex].peBlue =
  309.             (BYTE) ((pTree->nBlueSum) / (pTree->nPixelCount));
  310.         (*pIndex)++;
  311.     }
  312.     else {
  313.         for (i=0; i<8; i++) {
  314.             if (pTree->pChild[i] != NULL)
  315.                 GetPaletteColors (pTree->pChild[i], pPalEntries, pIndex);
  316.         }
  317.     }
  318. }
  319. int GetRightShiftCount (DWORD dwVal)
  320. {
  321.     int i;
  322.     for (i=0; i<sizeof (DWORD) * 8; i++) {
  323.         if (dwVal & 1)
  324.             return i;
  325.         dwVal >>= 1;
  326.     }
  327.     return -1;
  328. }
  329. int GetLeftShiftCount (DWORD dwVal)
  330. {
  331.     int nCount, i;
  332.     nCount = 0;
  333.     for (i=0; i<sizeof (DWORD) * 8; i++) {
  334.         if (dwVal & 1)
  335.             nCount++;
  336.         dwVal >>= 1;
  337.     }
  338.     return (8 - nCount);
  339. }