/// <summary> /// Add a color into the tree /// </summary> /// <param name="pixel">The color</param> /// <param name="colorBits">The number of significant color bits</param> /// <param name="level">The level in the tree</param> /// <param name="octree">The tree to which this node belongs</param> public void AddColor ( Color32* pixel , int colorBits , int level , Octree octree ) { // Update the color information if this is a leaf if ( _leaf ) { Increment ( pixel ) ; // Setup the previous node octree.TrackPrevious ( this ) ; } else { // Go to the next level down in the tree int shift = 7 - level ; int index = ( ( pixel->Red & mask[level] ) >> ( shift - 2 ) ) | ( ( pixel->Green & mask[level] ) >> ( shift - 1 ) ) | ( ( pixel->Blue & mask[level] ) >> ( shift ) ) ; OctreeNode child = _children[index] ; if ( null == child ) { // Create a new child node & store in the array child = new OctreeNode ( level + 1 , colorBits , octree ) ; _children[index] = child ; } // Add the color to the child node child.AddColor ( pixel , colorBits , level + 1 , octree ) ; } }
// Aqui comienza el algoritmo propiamente dicho public void EvaluateSteps( BitmapData sourceData, Bitmap output, int width , int height , Rectangle bounds ) { Octree octree = new Octree(MaxColorBits); FirstPass( sourceData , width , height, octree ) ; output.Palette = this.GetPalette ( output.Palette, octree ) ; SecondPass( sourceData , output , width , height , bounds, octree ) ; }
/// <summary> /// Construct the node /// </summary> /// <param name="level">The level in the tree = 0 - 7</param> /// <param name="colorBits">The number of significant color bits in the image</param> /// <param name="octree">The tree to which this node belongs</param> public OctreeNode ( int level , int colorBits , Octree octree ) { // Construct the new node _leaf = ( level == colorBits ) ; _red = _green = _blue = 0 ; _pixelCount = 0 ; // If a leaf, increment the leaf count if ( _leaf ) { octree.Leaves++ ; _nextReducible = null ; _children = null ; } else { // Otherwise add this to the reducible nodes _nextReducible = octree.ReducibleNodes[level] ; octree.ReducibleNodes[level] = this ; _children = new OctreeNode[8] ; } }
private void SecondPass ( BitmapData sourceData , Bitmap output , int width , int height , Rectangle bounds, Octree octree ) { BitmapData outputData = null ; try { // Lock the output bitmap into memory outputData = output.LockBits ( bounds , ImageLockMode.WriteOnly , PixelFormat.Format8bppIndexed ) ; // Define the source data pointers. The source row is a byte to // keep addition of the stride value easier (as this is in bytes) byte* pSourceRow = (byte*)sourceData.Scan0.ToPointer ( ) ; Int32* pSourcePixel = (Int32*)pSourceRow ; Int32* pPreviousPixel = pSourcePixel ; // Now define the destination data pointers byte* pDestinationRow = (byte*) outputData.Scan0.ToPointer(); byte* pDestinationPixel = pDestinationRow ; // And convert the first pixel, so that I have values going into the loop byte pixelValue = QuantizePixel ( (Color32*)pSourcePixel, octree ) ; // Assign the value of the first pixel *pDestinationPixel = pixelValue ; // Loop through each row for ( int row = 0 ; row < height ; row++ ) { // Set the source pixel to the first pixel in this row pSourcePixel = (Int32*) pSourceRow ; // And set the destination pixel pointer to the first pixel in the row pDestinationPixel = pDestinationRow ; // Loop through each pixel on this scan line for ( int col = 0 ; col < width ; col++ , pSourcePixel++ , pDestinationPixel++ ) { // Check if this is the same as the last pixel. If so use that value // rather than calculating it again. This is an inexpensive optimisation. if ( *pPreviousPixel != *pSourcePixel ) { // Quantize the pixel pixelValue = QuantizePixel ( (Color32*)pSourcePixel, octree ) ; // And setup the previous pointer pPreviousPixel = pSourcePixel ; } // And set the pixel in the output *pDestinationPixel = pixelValue ; } // Add the stride to the source row pSourceRow += sourceData.Stride ; // And to the destination row pDestinationRow += outputData.Stride ; } } finally { // Ensure that I unlock the output bits output.UnlockBits ( outputData ) ; } }
private void FirstPass ( BitmapData sourceData , int width , int height, Octree octree ) { // Define the source data pointers. The source row is a byte to // keep addition of the stride value easier (as this is in bytes) byte* pSourceRow = (byte*)sourceData.Scan0.ToPointer ( ) ; Int32* pSourcePixel ; // Loop through each row for ( int row = 0 ; row < height ; row++ ) { // Set the source pixel to the first pixel in this row pSourcePixel = (Int32*) pSourceRow ; // And loop through each column for ( int col = 0 ; col < width ; col++ , pSourcePixel++ ) // Now I have the pixel, call the FirstPassQuantize function... octree.AddColor ( (Color32*)pSourcePixel ) ; // Add the stride to the source row pSourceRow += sourceData.Stride ; } }
private byte QuantizePixel ( Color32* pixel, Octree octree ) { byte paletteIndex = (byte)MaxColors ; // The color at [_maxColors] is set to transparent // Get the palette index if this non-transparent if ( pixel->Alpha > 0 ) paletteIndex = (byte)octree.GetPaletteIndex ( pixel ) ; return paletteIndex ; }
private ColorPalette GetPalette ( ColorPalette original, Octree octree ) { // First off convert the octree to _maxColors colors ArrayList palette = octree.Palletize ( MaxColors - 1 ) ; // Then convert the palette based on those colors for ( int index = 0 ; index < palette.Count ; index++ ) original.Entries[index] = (Color)palette[index] ; // Add the transparent color original.Entries[MaxColors] = Color.FromArgb ( 0 , 0 , 0 , 0 ) ; return original ; }