CqOctree.cpp
上传用户:hstieta88
上传日期:2007-01-14
资源大小:106k
文件大小:14k
源码类别:

图形图像处理

开发平台:

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