#include"octtree.h" #include"image.h" // Build octree BOOL OctQuant::BuildTree() { int row; // Row counter int col; // Column counter BOOL status = TRUE; // Return status ImgRGBColor color; // Pixel color // Allocate octree root node proot=MakeNode(0); // Build the octree for (row = 0; row < height; row++) for (col = 0; col < width; col++) { color.Set(*(RGBPixel *)(olddata+col+row*image->Pitch),image->Mask); InsertNode(proot, color); if (num_leaf > max_color) ReduceTree(); } return status; } // Recursively delete octree nodes void OctQuant::DeleteNode( OctNode *pn ) { int i; // Loop index OctNode *pc; // Child node pointer if (pn==NULL) return; if (pn->IsLeaf() == FALSE) { // Delete child nodes for (i = 0; i < 8; i++) if ((pc = pn->GetChild(i)) != NULL) { DeleteNode(pc); pn->SetChild(i, NULL); pn->DecNumChild(); } } else num_leaf--; delete pn; } // Set color palette entries void OctQuant::FillPalette( OctNode *pn, int *pindex) { int i; // Loop index // Perform recursive depth-first traversal of octree if (pn != NULL) { if ((pn->IsLeaf()==TRUE) || pn->GetLevel()==leaf_level) { // Set color palette entry image->AllocPal(); image->pal[*pindex] = pn->GetColor(); // Set node color palette index pn->SetIndex(*pindex); // Advance to next color palette entry *pindex = *pindex + 1; } else { // Visit child nodes for (i = 0; i < 8; i++) FillPalette(pn->GetChild(i), pindex); } } } // Get next reducible node pointer OctNode *OctQuant::GetReducible() { int new_level; // New reducible node level OctNode *prn; // Reducible node pointer OctNode *plcn = NULL; // Largest pixel count node OctNode *pnext; // Next node OctNode *pprev; // Previous node new_level = leaf_level - 1; // Find lowest reducible node level while (prnl[new_level] == NULL) new_level--; // Find node with largest pixel count prn = prnl[new_level]; while (prn != NULL) { if (plcn == NULL) plcn = prn; else if (prn->GetCount() < plcn->GetCount()) plcn = prn; prn = prn->GetNext(); } // Remove node from reducible list pnext = plcn->GetNext(); pprev = plcn->GetPrev(); if (pprev == NULL) { prnl[new_level] = pnext; if (pnext != NULL) pnext->SetPrev(NULL); } else { pprev->SetNext(pnext); if (pnext != NULL) pnext->SetPrev(pprev); } plcn->SetNext(NULL); plcn->SetPrev(NULL); plcn->SetMark(FALSE); return plcn; } void OctQuant::ReduceTree() // Reduce octree { int i; // Loop index OctNode *pn; // Node pointer OctNode *pc; // Child node pointer pn = GetReducible(); // Get next reducible node // Delete children for (i = 0; i < 8; i++) { if ((pc = pn->GetChild(i)) != NULL) { DeleteNode(pc); pn->SetChild(i, NULL); pn->DecNumChild(); } } pn->SetLeaf(TRUE); // Mark node as leaf num_leaf++; // Increment leaf count // Update reduction and leaf levels if (pn->GetLevel() < (leaf_level - 1)) leaf_level = pn->GetLevel() + 1; } // Insert node into octree BOOL OctQuant::InsertNode( OctNode *pn, ImgRGBColor &c) { int c_index; // Child index int level; // Node level BOOL status = TRUE; // Return status OctNode *pc; // Child node pointer level = pn->GetLevel(); // Get node level pn->AddColor(c); // Add RGB color to node if (pn->IsLeaf() == FALSE && level < leaf_level) { // Find child node c_index = pn->FindChild(c); if ((pc = pn->GetChild(c_index)) == NULL) { // Allocate child node if ((pc = MakeNode(level + 1)) == NULL) return FALSE; // Set child node pointer pn->SetChild(c_index, pc); pn->IncNumChild(); // Increment child count } if ((pn->GetNumChild() > 1) && (pn->IsMark() == FALSE)) { // Mark node as candidate for reduction MakeReducible(pn); } // Insert child node into octree status = InsertNode(pc, c); } return status; } BOOL OctQuant::MapColors() { int row,col; // Row counter ImgRGBColor color; // 24-bit RGB color int psize=(image->Bpp>>3); int x,axl=width*psize; // Quantize the bitmap colors for (row=0; row < height; row++) for (x=0,col=0; xPitch),image->Mask); newdata[col+row*image->xlen]=(BYTE)QuantizeColor(proot, color); } return TRUE; } BOOL OctQuant::Quantize(Image *img) { BOOL status = TRUE; // Return status image=img; newdata=new BYTE[image->xlen*image->ylen]; olddata=image->Lock(); image->AllocPal(); for(int i=0;ipal[i]=0; width=image->xlen; height=image->ylen; int ncol=0; status=BuildTree(); FillPalette(proot,&ncol); status=MapColors(); DeleteTree(); // Delete color quantization octree image->UnLock(); image->Bpp=8; image->itype=ITYPE_INDEXED; image->IAlloc(); image->AllocPal(); image->SetData(newdata); image->RealizePalette(); delete newdata; return status; }