Click here to Skip to main content
Click here to Skip to main content

Work with bitmaps faster in C#

By , 15 Aug 2011
Rate this:
Please Sign up or sign in to vote.

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.

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.

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.

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)

About the Author

Vano Maisuradze
Software Developer (Senior)
Georgia Georgia
No Biography provided

Comments and Discussions

 
BugI found a bug Pinmember94HellGate26-Sep-13 7:56 
GeneralRe: I found a bug Pinmember94HellGate26-Sep-13 8:00 
QuestionNot work for my picture Pinmemberfroxplus24-Jun-13 23:34 
QuestionLag : 0 inserted at each end of ligne PinmemberMember 97338579-Jun-13 1:58 
AnswerRe: Lag : 0 inserted at each end of ligne PinmemberVano Maisuradze9-Jun-13 18:04 
QuestionGet XY from 8bpp and then draw it in same bmp but in 24bpp format PinmemberMikgau16-Apr-13 0:09 
AnswerRe: Get XY from 8bpp and then draw it in same bmp but in 24bpp format PinmemberMikgau16-Apr-13 3:18 
QuestionLockBitmap --> Bitmap ? Pinmemberssseeegggeee19-Jan-13 0:36 
AnswerRe: LockBitmap --> Bitmap ? PinmemberVano Maisuradze21-Feb-13 5:44 
GeneralMy vote of 5 Pinmemberakaki kapanadze17-Nov-12 2:16 
Good Job! Thumbs Up | :thumbsup:
GeneralMy vote of 5 PinmemberAndre Belloti6-Nov-12 6:54 
GeneralMy vote of 5 PinmemberPGT29-Oct-12 4:59 
Questioni get some errors what references did you use ? PinmemberPGT26-Oct-12 9:20 
AnswerRe: i get some errors what references did you use ? PinmemberVano Maisuradze27-Oct-12 10:57 
QuestionActual timings, and another code performance enhancement [modified] PinmemberRainer Gustin17-Aug-12 9:42 
GeneralReason for my vote of 5 nice one. Pinmembernikhi _singh27-Feb-12 2:59 
GeneralFor a good explanation of what is happening... http://bobpo... PinmemberSteve Wellens17-Nov-11 7:56 
GeneralReason for my vote of 5 There are things to improve... but t... PinmvpPaulo Zemek17-Nov-11 2:09 
GeneralRe: Thanks PinmemberVano Maisuradze17-Nov-11 3:36 
GeneralReason for my vote of 5 Very useful. Solves a couple of pro... PinmemberGreg Otto22-Aug-11 14:33 
GeneralRe: Thank you PinmemberVano Maisuradze22-Aug-11 21:19 
GeneralReason for my vote of 5 Nice example. Very straightforward. PinmemberTom Welch15-Aug-11 5:36 
GeneralRe: Thank you. PinmemberVano Maisuradze17-Nov-11 3:36 
GeneralReason for my vote of 5 Oh nice it helpful PinmemberPritesh Aryan15-Aug-11 2:27 
GeneralRe: Thank you. PinmemberVano Maisuradze17-Nov-11 3:36 

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

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

| Advertise | Privacy | Mobile
Web03 | 2.8.140415.2 | Last Updated 15 Aug 2011
Article Copyright 2011 by Vano Maisuradze
Everything else Copyright © CodeProject, 1999-2014
Terms of Use
Layout: fixed | fluid