Click here to Skip to main content
15,892,746 members
Articles / Programming Languages / C#
Tip/Trick

Very simple conversion of bitmap to indexed bitmap

Rate me:
Please Sign up or sign in to vote.
2.47/5 (7 votes)
9 Apr 2023CPOL 7.7K   2   22
Very simple conversion of bitmap to indexed bitmap
C#
private static unsafe Bitmap ToIndexed(Bitmap source, PixelFormat format)
        {
            Rectangle rectangle = new Rectangle(0, 0, source.Width, source.Height);
            Bitmap result = new Bitmap(source.Width, source.Height, format);

            BitmapData sourceData = source.LockBits(rectangle, 
                ImageLockMode.ReadOnly, source.PixelFormat),
                resultData = result.LockBits(rectangle, 
                ImageLockMode.WriteOnly, format);

            int sourceFlags = sourceData.Stride * sourceData.Height,
                resultFlags = resultData.Stride * resultData.Height;

            byte* sourceBuffer = (byte*)sourceData.Scan0.ToPointer(), 
                resultBuffer = (byte*)resultData.Scan0.ToPointer();

            int offset = sourceFlags / resultFlags;
            for (int i = 0; i < sourceFlags; i++)
            {
                resultBuffer[i / offset] = sourceBuffer[i];
            }

            result.UnlockBits(resultData);
            source.UnlockBits(sourceData);
            return result;
        }

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
I do not claim to be wrong! I just rarely ever write.

Comments and Discussions

 
GeneralMy vote of 1 Pin
Stacy Dudovitz11-Apr-23 18:37
professionalStacy Dudovitz11-Apr-23 18:37 
GeneralRe: My vote of 1 Pin
Lucky Vdb11-Apr-23 20:40
professionalLucky Vdb11-Apr-23 20:40 
GeneralRe: My vote of 1 Pin
charles henington12-Apr-23 10:15
charles henington12-Apr-23 10:15 
GeneralRe: My vote of 1 Pin
charles henington12-Apr-23 16:22
charles henington12-Apr-23 16:22 
GeneralRe: My vote of 1 Pin
Stacy Dudovitz12-Apr-23 20:30
professionalStacy Dudovitz12-Apr-23 20:30 
Oh, where to begin...

A tip is only useful if it's intended target audience is specified. No where in this tip is the target specified as Windows Forms, and worse, no where have you specified that its Windows Forms under .NET Framework as opposed to .NET Core. This all needs to be inferred, and for those of us with mileage under our belts, we would never present code in this fashion. That's just for openers.

The code does not compile as is. No where are the proper using statements specified:
C#
using System.Drawing;
using System.Drawing.Imaging;

In addition, those who have not used unsafe code will not know how/where to set the proper flags to compile the code under Project->Properties->Build.

The comes the code itself, which is a ticking timebomb due to improper handling of resources and error handling. There are two major violations of best practices here:
  1. Never return an object that implements an IDisposable pattern i.e. requires garbage collection
  2. Never implement a method with objects that contain lifetime resources without exception handling
I have taken the liberty of rewriting your "tip" to conform to address the two violations as follows:
C#
private static void ToIndexed(Bitmap source, PixelFormat format, out Bitmap result)
   {
       result = null;
       try
       {
           unsafe
           {
               Rectangle rectangle = new Rectangle(0, 0, source.Width, source.Height);
               result = new Bitmap(source.Width, source.Height, format);

               BitmapData sourceData = source.LockBits(rectangle,
                       ImageLockMode.ReadOnly, source.PixelFormat),
                   resultData = result.LockBits(rectangle,
                       ImageLockMode.WriteOnly, format);

               int sourceFlags = sourceData.Stride * sourceData.Height,
                   resultFlags = resultData.Stride * resultData.Height;

               byte* sourceBuffer = (byte*)sourceData.Scan0.ToPointer(),
                   resultBuffer = (byte*)resultData.Scan0.ToPointer();

               int offset = sourceFlags / resultFlags;
               for (int i = 0; i < sourceFlags; i++)
               {
                   resultBuffer[i / offset] = sourceBuffer[i];
               }

               result.UnlockBits(resultData);
               source.UnlockBits(sourceData);
           }

       }
       catch (Exception e)
       {
           result?.Dispose();
           throw;
       }
   }

I wrote a quick console application that shows how one might call your method:
C#
static void Main(string[] args)
{
    try
    {
        using (Bitmap bm = new Bitmap(10, 10))
        {
            Bitmap res;
            ToIndexed(bm, PixelFormat.Alpha, res);

                . . . .

        }
    }
    catch (Exception e)
    {
        Console.WriteLine(e);
        throw;
    }
}

One more point... this code is brittle, in that bitmap integer size will vary from machine to machine, and from processor to processor. In fact, given the prevalence or Mono, and the continued portability or .NET on platforms such as Xamarin, where this can run on Processors where 'endian'ness cannot be assured, this code is quite brittle indeed.

None of this is pointed out in either code comments or in accompanying text. The reason for my vote of '1' is not for the type of submission, but rather for what seems to be a 'phoning it in' type of effort. Even tips require some modicum of time and preparation. I almost feel like I spent more time and effort answering you, than you did posting your tip in the first place.
GeneralRe: My vote of 1 Pin
charles henington13-Apr-23 9:55
charles henington13-Apr-23 9:55 
GeneralRe: My vote of 1 Pin
charles henington13-Apr-23 11:20
charles henington13-Apr-23 11:20 
GeneralRe: My vote of 1 Pin
Stacy Dudovitz14-Apr-23 7:38
professionalStacy Dudovitz14-Apr-23 7:38 
GeneralMy vote of 2 Pin
dmjm-h11-Apr-23 12:01
dmjm-h11-Apr-23 12:01 
GeneralRe: My vote of 2 Pin
charles henington11-Apr-23 16:36
charles henington11-Apr-23 16:36 
GeneralRe: My vote of 2 Pin
charles henington11-Apr-23 16:55
charles henington11-Apr-23 16:55 
GeneralMy vote of 5 Pin
Lucky Vdb11-Apr-23 1:35
professionalLucky Vdb11-Apr-23 1:35 
GeneralRe: My vote of 5 Pin
charles henington11-Apr-23 11:17
charles henington11-Apr-23 11:17 
GeneralMy vote of 2 Pin
YDaoust10-Apr-23 23:20
YDaoust10-Apr-23 23:20 
GeneralRe: My vote of 2 Pin
charles henington11-Apr-23 11:14
charles henington11-Apr-23 11:14 
GeneralRe: My vote of 2 Pin
YDaoust11-Apr-23 20:17
YDaoust11-Apr-23 20:17 
GeneralRe: My vote of 2 Pin
charles henington12-Apr-23 3:36
charles henington12-Apr-23 3:36 
GeneralRe: My vote of 2 Pin
YDaoust12-Apr-23 4:36
YDaoust12-Apr-23 4:36 
GeneralRe: My vote of 2 Pin
charles henington12-Apr-23 9:55
charles henington12-Apr-23 9:55 
GeneralRe: My vote of 2 Pin
YDaoust12-Apr-23 10:27
YDaoust12-Apr-23 10:27 
GeneralRe: My vote of 2 Pin
charles henington12-Apr-23 10:37
charles henington12-Apr-23 10:37 
GeneralRe: My vote of 2 Pin
charles henington12-Apr-23 15:07
charles henington12-Apr-23 15:07 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.