private void SpreadColors(int total)
        {
            ColorBox *  pBox  = _boxes;
            ColorEntry *entry = pBox->_rootEntry->_next;

            int index, count = (int)pBox->_colors;

            //Set initial box
            pBox->_color = entry->_color;
            entry        = entry->_next;
            pBox++;

            //Set remaining boxes
            for (index = 1; index < count; index++, pBox++, entry = entry->_next)
            {
                entry->_box      = pBox;
                pBox->_color     = entry->_color;
                pBox->_rootEntry = null;
            }

            //Not needed because the remaining palette colors will be empty anyways.
            //Set total boxes
            //for (; index < total; index++, pBox++)
            //{
            //    pBox->_color = new ARGBPixel(255, 0, 0, 0);
            //    pBox->_rootEntry = null;
            //}

            //_boxCount = total;
            _boxCount = count;
        }
        private bool SelectColors(int targetColors)
        {
            int          splitAxis;
            ColorBox *   splitBox, boxPtr = _boxes;
            ARGBPixel *  sPtr = _srcPixels;
            ColorEntry **gPtr = _groupTable;
            ColorEntry * entry;
            ushort       id;

            //Create initial box
            boxPtr->Initialize();
            _boxCount = 1;

            //Iterate through colors using ID generator
            for (int i = 0; i < _size; i++)
            {
                _idFunc(*sPtr++, &id);
                gPtr = _groupTable + id;
                if ((entry = *gPtr) == null)
                {
                    *gPtr = entry = ColorEntry.Create();
                    _idConv(&id, out entry->_color);
                    entry->_weight = 1;
                    boxPtr->_rootEntry->InsertPrev(entry);
                }
                else
                {
                    entry->_weight++;
                }
            }

            //If no quantization is necessary, then leave.
            if (boxPtr->_colors <= targetColors)
            {
                return(false);
            }

            //Update initial box
            boxPtr->Update(targetColors - 1);

            //Split until we reach desired colors
            while (_boxCount < targetColors)
            {
                //Find split candidate
                splitBox = ColorBox.FindSplit(_boxes, _boxCount, targetColors, out splitAxis);

                //Create new box
                (++boxPtr)->Initialize();

                //Move colors from one box to another using split axis
                splitBox->Split(boxPtr, splitAxis);

                //Update boxes
                _boxCount++;
                splitBox->Update(targetColors - _boxCount);
                boxPtr->Update(targetColors - _boxCount);
            }
            return(true);
        }
        private void WritePalette(ColorPalette pal)
        {
            ColorBox *pBox = _boxes;

            for (int i = 0; i < _boxCount; i++, pBox++)
            {
                pal.Entries[pBox->_index] = (Color)pBox->_color;
            }
        }
        private void ClearBoxes()
        {
            //Clean up
            ColorBox *boxPtr = _boxes;

            for (int i = 0; i < _boxCount; i++, boxPtr++)
            {
                boxPtr->Destroy();
            }
        }
Exemplo n.º 5
0
        private MedianCut(Bitmap bmp, WiiPixelFormat texFormat, WiiPaletteFormat palFormat)
        {
            //Set output format
            if (texFormat == WiiPixelFormat.CI4)
            {
                _outFormat = PixelFormat.Format4bppIndexed;
            }
            else if (texFormat == WiiPixelFormat.CI8)
            {
                _outFormat = PixelFormat.Format8bppIndexed;
            }
            else
            {
                throw new ArgumentException("Invalid pixel format.");
            }

            //Set conversion functions
            if (palFormat == WiiPaletteFormat.IA8)
            {
                _idFunc = IA8Handler;
                _idConv = IA8Converter;
            }
            else if (palFormat == WiiPaletteFormat.RGB565)
            {
                _idFunc = RGB565Handler;
                _idConv = RGB565Converter;
            }
            else
            {
                _idFunc = RGB5A3Handler;
                _idConv = RGB5A3Converter;
            }

            //Lock/set source data
            _srcBmp  = bmp;
            _width   = bmp.Width;
            _height  = bmp.Height;
            _size    = _width * _height;
            _srcData = bmp.LockBits(new Rectangle(0, 0, _width, _height), ImageLockMode.ReadOnly,
                                    PixelFormat.Format32bppArgb);
            _srcPixels = (ARGBPixel *)_srcData.Scan0;

            //Create buffers
            _boxes      = (ColorBox *)Marshal.AllocHGlobal(256 * sizeof(ColorBox));
            _groupTable = (ColorEntry **)Marshal.AllocHGlobal(65536 * sizeof(void *));
        }
            public void Split(ColorBox *newBox, int axis)
            {
                ColorBox *  box = _rootEntry->_box;
                ColorEntry *current, next;
                //Get limit from halfError
                int limit = ((byte *)&box->_halfError)[axis];

                for (current = _rootEntry->_next; current != _rootEntry; current = next)
                {
                    next = current->_next;
                    if (((byte *)&current->_color)[axis] > limit)
                    {
                        //Remove from current box
                        current->Remove();
                        //Add to end of new box
                        newBox->_rootEntry->InsertPrev(current);
                    }
                }
            }
 public void Dispose()
 {
     if (_boxes != null)
     {
         Marshal.FreeHGlobal((IntPtr)_boxes);
         _boxes = null;
     }
     if (_groupTable != null)
     {
         Marshal.FreeHGlobal((IntPtr)_groupTable);
         _groupTable = null;
     }
     if (_srcBmp != null)
     {
         _srcBmp.UnlockBits(_srcData);
         _srcBmp    = null;
         _srcData   = null;
         _srcPixels = null;
     }
     GC.SuppressFinalize(this);
 }
Exemplo n.º 8
0
        private MedianCut(Bitmap bmp, WiiPixelFormat texFormat, WiiPaletteFormat palFormat)
        {
            //Set output format
            if (texFormat == WiiPixelFormat.CI4)
                _outFormat = PixelFormat.Format4bppIndexed;
            else if (texFormat == WiiPixelFormat.CI8)
                _outFormat = PixelFormat.Format8bppIndexed;
            else
                throw new ArgumentException("Invalid pixel format.");

            //Set conversion functions
            if (palFormat == WiiPaletteFormat.IA8)
            {
                _idFunc = IA8Handler;
                _idConv = IA8Converter;
            }
            else if (palFormat == WiiPaletteFormat.RGB565)
            {
                _idFunc = RGB565Handler;
                _idConv = RGB565Converter;
            }
            else
            {
                _idFunc = RGB5A3Handler;
                _idConv = RGB5A3Converter;
            }

            //Lock/set source data
            _srcBmp = bmp;
            _width = bmp.Width;
            _height = bmp.Height;
            _size = _width * _height;
            _srcData = bmp.LockBits(new Rectangle(0, 0, _width, _height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
            _srcPixels = (ARGBPixel*)_srcData.Scan0;

            //Create buffers
            _boxes = (ColorBox*)Marshal.AllocHGlobal(256 * sizeof(ColorBox));
            _groupTable = (ColorEntry**)Marshal.AllocHGlobal(65536 * 4);
        }
        private void SortBoxes()
        {
            //Sort boxes by luminance
            void **    tableData  = stackalloc void *[_boxCount];
            ColorBox **colorTable = (ColorBox **)tableData;
            ColorBox * boxPtr     = _boxes;
            int        index;
            ushort     id;
            float      luminance;

            for (int count = 0; count < _boxCount; count++)
            {
                luminance = boxPtr->_luminance = boxPtr->_color.Luminance();

                for (index = 0; (index < count) && (luminance > colorTable[index]->_luminance); index++)
                {
                    ;
                }

                //Slide entries right
                for (int y = count; y > index;)
                {
                    colorTable[y--] = colorTable[y];
                }

                colorTable[index] = boxPtr++;
            }

            //Set indices and clamp colors
            for (int i = 0; i < _boxCount; i++)
            {
                colorTable[i]->_index = i;
                _idFunc(colorTable[i]->_color, &id);
                _idConv(&id, out colorTable[i]->_color);
            }
        }
Exemplo n.º 10
0
            public static ColorBox *FindSplit(ColorBox *boxes, int boxCount, int maxColors, out int axis)
            {
                ColorBox *outBox = null;
                double    lBias = 1.0, maxC = 0.0;
                //double val;
                double rpe, gpe, bpe, ape;
                //int index = -1;

                byte * pMin, pMax;
                ulong *pErr;

                axis = -1;

                if ((maxColors <= 16) && (boxCount <= 2))
                {
                    lBias = (3.0 - boxCount) / (2.0 / 2.66);
                }

                for (int i = 0; i < boxCount; i++, boxes++)
                {
                    if (boxes->_volume <= 1)
                    {
                        continue;
                    }

                    pMin = (byte *)&boxes->_min;
                    pMax = (byte *)&boxes->_max;
                    pErr = &boxes->bError;

                    rpe = boxes->rError * R_SCALE * R_SCALE;
                    gpe = boxes->gError * G_SCALE * G_SCALE;
                    bpe = boxes->bError * B_SCALE * B_SCALE;
                    ape = boxes->aError * A_SCALE * A_SCALE;

                    //for (int x = 0; x < 4; x++)
                    //{
                    //    if (((val = pErr[i]) > maxC) && (pMin[x] < pMax[x]))
                    //    {
                    //        //index = i;
                    //        outBox = boxes;
                    //        maxC = val;
                    //        axis = x;
                    //    }
                    //}

                    if (((lBias * rpe) > maxC) && (pMin[2] < pMax[2]))
                    {
                        outBox = boxes;
                        maxC   = lBias * rpe;
                        axis   = 2;
                    }

                    if ((gpe > maxC) && (pMin[1] < pMax[1]))
                    {
                        outBox = boxes;
                        maxC   = gpe;
                        axis   = 1;
                    }

                    if ((bpe > maxC) && (pMin[0] < pMax[0]))
                    {
                        outBox = boxes;
                        maxC   = bpe;
                        axis   = 0;
                    }
                    if ((ape > maxC) && (pMin[3] < pMax[3]))
                    {
                        outBox = boxes;
                        maxC   = ape;
                        axis   = 3;
                    }
                }
                return(outBox);
            }
Exemplo n.º 11
0
            public void Update(int remaining)
            {
                ColorBox *  box = _rootEntry->_box;
                ColorEntry *current;
                byte *      tPtr, sColor;
                ulong *     colBuffer = &box->bError;
                byte *      pMin      = (byte *)&box->_min;
                byte *      pMax      = (byte *)&box->_max;
                uint        weight;
                int         diff;
                byte        val;
                int *       size = stackalloc int[4];

                //Reset bounds and weight
                _min    = 0xFFFFFFFF;
                _max    = 0;
                _weight = 0;

                //Zero errors (for use as color accumulator)
                aError = rError = gError = bError = 0;
                //Memory.Fill(&box->error, 32, 0);

                //Get min/max bounds for all contained color entries and calculate color
                for (current = _rootEntry->_next; current != _rootEntry; current = current->_next)
                {
                    _weight += weight = current->_weight;
                    tPtr     = (byte *)&current->_color;

                    //Update bounds for and accumulate each element
                    for (int i = 0; i < 4; i++)
                    {
                        val           = *tPtr++;
                        pMin[i]       = Math.Min(val, pMin[i]);
                        pMax[i]       = Math.Max(val, pMax[i]);
                        colBuffer[i] += val * weight;
                    }
                }

                //Set calculated color
                sColor = (byte *)&box->_color;
                for (int i = 0; i < 4; i++)
                {
                    sColor[i] = (byte)(colBuffer[i] / (uint)_weight);
                }

                //Calculate volume
                _volume = 1;
                for (int i = 0; i < 4; i++)
                {
                    diff     = pMax[i] - pMin[i] + 1;
                    _volume *= (uint)diff;
                    size[i]  = (byte)diff;
                }
                if (_volume == 0)
                {
                    _volume = 0xFFFFFFFF;
                }

                //Calculate error
                aError = rError = gError = bError = 0;
                //Memory.Fill(&box->error, 32, 0);
                for (current = _rootEntry->_next; current != _rootEntry; current = current->_next)
                {
                    weight = current->_weight;
                    tPtr   = (byte *)&current->_color;
                    for (int i = 0; i < 4; i++)
                    {
                        diff          = tPtr[i] - sColor[i];
                        colBuffer[i] += weight * (uint)(diff * diff);
                    }
                }

                //Get half-error
                tPtr = (byte *)&box->_halfError;
                for (int i = 0; i < 4; i++)
                {
                    tPtr[i] = (byte)(pMin[i] + (size[i] / 2));
                }


                if (_volume > 1)
                {
                    int axis1 = -1, axis2 = -1;
                    int len1 = 0, len2 = 0;
                    int ratio;

                    for (int i = 0; i < 4; i++)
                    {
                        if (size[i] > len1)
                        {
                            len2  = len1;
                            axis2 = axis1;
                            len1  = size[i];
                            axis1 = i;
                        }
                        else if (size[i] > len2)
                        {
                            len2  = size[i];
                            axis2 = i;
                        }
                    }

                    if (len2 == 0)
                    {
                        len2 = 1;
                    }

                    ratio = (len1 + (len2 / 2)) / len2;

                    if (ratio > remaining + 1)
                    {
                        ratio = remaining + 1;
                    }

                    if ((ratio > 2) && (axis1 >= 0))
                    {
                        diff = pMin[axis1] + (pMax[axis1] - pMin[axis1] + (ratio / 2));
                        if (diff < pMax[axis1])
                        {
                            tPtr[axis1] = (byte)diff;
                        }
                    }
                }

                //If half-error touches ceiling, set to floor
                for (int i = 0; i < 4; i++)
                {
                    if (tPtr[i] == pMax[i])
                    {
                        tPtr[i] = pMin[i];
                    }
                }
            }
Exemplo n.º 12
0
 public void Dispose()
 {
     if (_boxes != null)
     {
         Marshal.FreeHGlobal((IntPtr)_boxes);
         _boxes = null;
     }
     if (_groupTable != null)
     {
         Marshal.FreeHGlobal((IntPtr)_groupTable);
         _groupTable = null;
     }
     if (_srcBmp != null)
     {
         _srcBmp.UnlockBits(_srcData);
         _srcBmp = null;
         _srcData = null;
         _srcPixels = null;
     }
     GC.SuppressFinalize(this);
 }