Click here to Skip to main content
15,867,756 members
Articles / Multimedia / Image Processing
Tip/Trick

Work with Bitmaps Faster in C#

Rate me:
Please Sign up or sign in to vote.
4.94/5 (54 votes)
15 Aug 2011CPOL 336.6K   77   45
The alternative solution, how to work with images faster.

Note: If you have any suggestions on how to improve this code, you can contribute on the github repository.

When you are working with bitmaps in C#, you can use the GetPixel(x, y) and SetPixel(x, y, color) functions to get/set the pixel value. But they are very slow.

Here is the alternative way to work with bitmaps faster.

LockBitmap

With the LockBitmap class, we can lock/unlock bitmap data.

C#
public class LockBitmap
{
    Bitmap source = null;
    IntPtr Iptr = IntPtr.Zero;
    BitmapData bitmapData = null;
 
    public byte[] Pixels { get; set; }
    public int Depth { get; private set; }
    public int Width { get; private set; }
    public int Height { get; private set; }
 
    public LockBitmap(Bitmap source)
    {
        this.source = source;
    }
 
    /// <summary>
    /// Lock bitmap data
    /// </summary>
    public void LockBits()
    {
        try
        {
            // Get width and height of bitmap
            Width = source.Width;
            Height = source.Height;
 
            // get total locked pixels count
            int PixelCount = Width * Height;
 
            // Create rectangle to lock
            Rectangle rect = new Rectangle(0, 0, Width, Height);
 
            // get source bitmap pixel format size
            Depth = System.Drawing.Bitmap.GetPixelFormatSize(source.PixelFormat);
 
            // Check if bpp (Bits Per Pixel) is 8, 24, or 32
            if (Depth != 8 && Depth != 24 && Depth != 32)
            {
                throw new ArgumentException("Only 8, 24 and 32 bpp images are supported.");
            }
 
            // Lock bitmap and return bitmap data
            bitmapData = source.LockBits(rect, ImageLockMode.ReadWrite, 
                                         source.PixelFormat);
 
            // create byte array to copy pixel values
            int step = Depth / 8;
            Pixels = new byte[PixelCount * step];
            Iptr = bitmapData.Scan0;
 
            // Copy data from pointer to array
            Marshal.Copy(Iptr, Pixels, 0, Pixels.Length);
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }
 
    /// <summary>
    /// Unlock bitmap data
    /// </summary>
    public void UnlockBits()
    {
        try
        {
            // Copy data from byte array to pointer
            Marshal.Copy(Pixels, 0, Iptr, Pixels.Length);
 
            // Unlock bitmap data
            source.UnlockBits(bitmapData);
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }
 
    /// <summary>
    /// Get the color of the specified pixel
    /// </summary>
    /// <param name="x"></param>
    /// <param name="y"></param>
    /// <returns></returns>
    public Color GetPixel(int x, int y)
    {
        Color clr = Color.Empty;
 
        // Get color components count
        int cCount = Depth / 8;
 
        // Get start index of the specified pixel
        int i = ((y * Width) + x) * cCount;
 
        if (i > Pixels.Length - cCount)
            throw new IndexOutOfRangeException();
 
        if (Depth == 32) // For 32 bpp get Red, Green, Blue and Alpha
        {
            byte b = Pixels[i];
            byte g = Pixels[i + 1];
            byte r = Pixels[i + 2];
            byte a = Pixels[i + 3]; // a
            clr = Color.FromArgb(a, r, g, b);
        }
        if (Depth == 24) // For 24 bpp get Red, Green and Blue
        {
            byte b = Pixels[i];
            byte g = Pixels[i + 1];
            byte r = Pixels[i + 2];
            clr = Color.FromArgb(r, g, b);
        }
        if (Depth == 8)
        // For 8 bpp get color value (Red, Green and Blue values are the same)
        {
            byte c = Pixels[i];
            clr = Color.FromArgb(c, c, c);
        }
        return clr;
    }
 
    /// <summary>
    /// Set the color of the specified pixel
    /// </summary>
    /// <param name="x"></param>
    /// <param name="y"></param>
    /// <param name="color"></param>
    public void SetPixel(int x, int y, Color color)
    {
        // Get color components count
        int cCount = Depth / 8;
 
        // Get start index of the specified pixel
        int i = ((y * Width) + x) * cCount;
 
        if (Depth == 32) // For 32 bpp set Red, Green, Blue and Alpha
        {
            Pixels[i] = color.B;
            Pixels[i + 1] = color.G;
            Pixels[i + 2] = color.R;
            Pixels[i + 3] = color.A;
        }
        if (Depth == 24) // For 24 bpp set Red, Green and Blue
        {
            Pixels[i] = color.B;
            Pixels[i + 1] = color.G;
            Pixels[i + 2] = color.R;
        }
        if (Depth == 8)
        // For 8 bpp set color value (Red, Green and Blue values are the same)
        {
            Pixels[i] = color.B;
        }
    }
}

Benchmark

To test LockBitmap's performance, we can use the Benchmark class.

C#
public class Benchmark
{
    private static DateTime startDate = DateTime.MinValue;
    private static DateTime endDate = DateTime.MinValue;
 
    public static TimeSpan Span { get { return endDate.Subtract(startDate); } }
 
    public static void Start() { startDate = DateTime.Now; }
 
    public static void End() { endDate = DateTime.Now; }
 
    public static double GetSeconds()
    {
        if (endDate == DateTime.MinValue) return 0.0;
        else return Span.TotalSeconds;
    }
}

Usage

Now, we can use the LockBitmap class to work with images very fast.

C#
public void ChangeColor()
{
    Bitmap bmp = (Bitmap)Image.FromFile("d:\\source.png");
    Benchmark.Start();
    LockBitmap lockBitmap = new LockBitmap(bmp);
    lockBitmap.LockBits();
 
    Color compareClr = Color.FromArgb(255, 255, 255, 255);
    for (int y = 0; y < lockBitmap.Height; y++)
    {
        for (int x = 0; x < lockBitmap.Width; x++)
        {
            if (lockBitmap.GetPixel(x, y) == compareClr)
            {
                lockBitmap.SetPixel(x, y, Color.Red);
            }
        }
    }
    lockBitmap.UnlockBits();
    Benchmark.End();
    double seconds = Benchmark.GetSeconds();
    bmp.Save("d:\\result.png");
}

License

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


Written By
Architect
Georgia Georgia
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralRe: I found a bug Pin
94HellGate26-Sep-13 8:00
94HellGate26-Sep-13 8:00 
QuestionNot work for my picture Pin
froxplus24-Jun-13 23:34
froxplus24-Jun-13 23:34 
QuestionLag : 0 inserted at each end of ligne Pin
Member 97338579-Jun-13 1:58
Member 97338579-Jun-13 1:58 
AnswerRe: Lag : 0 inserted at each end of ligne Pin
Vano Maisuradze9-Jun-13 18:04
Vano Maisuradze9-Jun-13 18:04 
QuestionGet XY from 8bpp and then draw it in same bmp but in 24bpp format Pin
Mikgau16-Apr-13 0:09
Mikgau16-Apr-13 0:09 
AnswerRe: Get XY from 8bpp and then draw it in same bmp but in 24bpp format Pin
Mikgau16-Apr-13 3:18
Mikgau16-Apr-13 3:18 
GeneralRe: Get XY from 8bpp and then draw it in same bmp but in 24bpp format Pin
socalshyguy16-Oct-15 17:53
socalshyguy16-Oct-15 17:53 
QuestionLockBitmap --> Bitmap ? Pin
ssseeegggeee19-Jan-13 0:36
ssseeegggeee19-Jan-13 0:36 
How to convert from a LockBitmap to a Bitmap ?
CType and DirectCast not working, as well as retrieving source, nothing works.
I am looking to create a new bitmap, and write pixels of my choice into it. So I made a blank bitmap and made a lockbitmap out of it, appended the pixels to the LockBitmap and retrieve a System.Drawing.Bitmap. How can I do it ?

Please reply.
AnswerRe: LockBitmap --> Bitmap ? Pin
Vano Maisuradze21-Feb-13 5:44
Vano Maisuradze21-Feb-13 5:44 
GeneralMy vote of 5 Pin
Akaki Kapanadze17-Nov-12 2:16
Akaki Kapanadze17-Nov-12 2:16 
GeneralMy vote of 5 Pin
Andre Belloti6-Nov-12 6:54
Andre Belloti6-Nov-12 6:54 
GeneralMy vote of 5 Pin
PGT29-Oct-12 4:59
PGT29-Oct-12 4:59 
Questioni get some errors what references did you use ? Pin
PGT26-Oct-12 9:20
PGT26-Oct-12 9:20 
AnswerRe: i get some errors what references did you use ? Pin
Vano Maisuradze27-Oct-12 10:57
Vano Maisuradze27-Oct-12 10:57 
QuestionActual timings, and another code performance enhancement Pin
Rainer Gustin17-Aug-12 9:42
Rainer Gustin17-Aug-12 9:42 
AnswerRe: Actual timings, and another code performance enhancement Pin
PGT1-Oct-15 5:58
PGT1-Oct-15 5:58 
GeneralReason for my vote of 5 nice one. Pin
Nikhil_S27-Feb-12 2:59
professionalNikhil_S27-Feb-12 2:59 
GeneralFor a good explanation of what is happening... http://bobpo... Pin
Steve Wellens17-Nov-11 7:56
Steve Wellens17-Nov-11 7:56 
GeneralReason for my vote of 5 There are things to improve... but t... Pin
Paulo Zemek17-Nov-11 2:09
mvaPaulo Zemek17-Nov-11 2:09 
GeneralRe: Thanks Pin
Vano Maisuradze17-Nov-11 3:36
Vano Maisuradze17-Nov-11 3:36 
GeneralReason for my vote of 5 Very useful. Solves a couple of pro... Pin
Greg Otto22-Aug-11 14:33
Greg Otto22-Aug-11 14:33 
GeneralRe: Thank you Pin
Vano Maisuradze22-Aug-11 21:19
Vano Maisuradze22-Aug-11 21:19 
GeneralReason for my vote of 5 Nice example. Very straightforward. Pin
Tom Welch15-Aug-11 5:36
Tom Welch15-Aug-11 5:36 
GeneralRe: Thank you. Pin
Vano Maisuradze17-Nov-11 3:36
Vano Maisuradze17-Nov-11 3:36 
GeneralReason for my vote of 5 Oh nice it helpful Pin
Pritesh Aryan15-Aug-11 2:27
Pritesh Aryan15-Aug-11 2:27 

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.