Click here to Skip to main content
11,413,961 members (75,353 online)
Click here to Skip to main content

Tagged as

Work with bitmaps faster in C#

, 15 Aug 2011 CPOL
Rate this:
Please Sign up or sign in to vote.
The alternative solution, how to work with images faster.

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)

Share

About the Author

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

Comments and Discussions

 
QuestionMessage Removed Pin
Member 11588941, 7-Apr-15 17:25
memberMember 115889417-Apr-15 17:25 
GeneralMy vote of 5 Pin
Member 10717244, 30-Sep-14 22:32
memberMember 1071724430-Sep-14 22:32 
QuestionAnother samples comparatively Pin
Melih_123_melih, 5-Sep-14 5:28
memberMelih_123_melih5-Sep-14 5:28 
BugI found a bug Pin
94HellGate, 26-Sep-13 8:56
member94HellGate26-Sep-13 8:56 
GeneralRe: I found a bug Pin
94HellGate, 26-Sep-13 9:00
member94HellGate26-Sep-13 9:00 
QuestionNot work for my picture Pin
froxplus, 25-Jun-13 0:34
memberfroxplus25-Jun-13 0:34 
QuestionLag : 0 inserted at each end of ligne Pin
Member 9733857, 9-Jun-13 2:58
memberMember 97338579-Jun-13 2:58 
AnswerRe: Lag : 0 inserted at each end of ligne Pin
Vano Maisuradze, 9-Jun-13 19:04
memberVano Maisuradze9-Jun-13 19:04 
QuestionGet XY from 8bpp and then draw it in same bmp but in 24bpp format Pin
Mikgau, 16-Apr-13 1:09
memberMikgau16-Apr-13 1:09 
AnswerRe: Get XY from 8bpp and then draw it in same bmp but in 24bpp format Pin
Mikgau, 16-Apr-13 4:18
memberMikgau16-Apr-13 4:18 
QuestionLockBitmap --> Bitmap ? Pin
ssseeegggeee, 19-Jan-13 1:36
memberssseeegggeee19-Jan-13 1:36 
AnswerRe: LockBitmap --> Bitmap ? Pin
Vano Maisuradze, 21-Feb-13 6:44
memberVano Maisuradze21-Feb-13 6:44 
GeneralMy vote of 5 Pin
akaki kapanadze, 17-Nov-12 3:16
memberakaki kapanadze17-Nov-12 3:16 
GeneralMy vote of 5 Pin
Andre Belloti, 6-Nov-12 7:54
memberAndre Belloti6-Nov-12 7:54 
GeneralMy vote of 5 Pin
PGT, 29-Oct-12 5:59
memberPGT29-Oct-12 5:59 
great code samples
Questioni get some errors what references did you use ? Pin
PGT, 26-Oct-12 10:20
memberPGT26-Oct-12 10:20 
AnswerRe: i get some errors what references did you use ? Pin
Vano Maisuradze, 27-Oct-12 11:57
memberVano Maisuradze27-Oct-12 11:57 
QuestionActual timings, and another code performance enhancement [modified] Pin
Rainer Gustin, 17-Aug-12 10:42
memberRainer Gustin17-Aug-12 10:42 
GeneralReason for my vote of 5 nice one. Pin
nikhi _singh, 27-Feb-12 3:59
membernikhi _singh27-Feb-12 3:59 
GeneralFor a good explanation of what is happening... http://bobpo... Pin
Steve Wellens, 17-Nov-11 8:56
memberSteve Wellens17-Nov-11 8:56 
GeneralReason for my vote of 5 There are things to improve... but t... Pin
Paulo Zemek, 17-Nov-11 3:09
mvpPaulo Zemek17-Nov-11 3:09 
GeneralRe: Thanks Pin
Vano Maisuradze, 17-Nov-11 4:36
memberVano Maisuradze17-Nov-11 4:36 
GeneralReason for my vote of 5 Very useful. Solves a couple of pro... Pin
Greg Otto, 22-Aug-11 15:33
memberGreg Otto22-Aug-11 15:33 
GeneralRe: Thank you Pin
Vano Maisuradze, 22-Aug-11 22:19
memberVano Maisuradze22-Aug-11 22:19 
GeneralReason for my vote of 5 Nice example. Very straightforward. Pin
Tom Welch, 15-Aug-11 6:36
memberTom Welch15-Aug-11 6:36 
GeneralRe: Thank you. Pin
Vano Maisuradze, 17-Nov-11 4:36
memberVano Maisuradze17-Nov-11 4:36 
GeneralReason for my vote of 5 Oh nice it helpful Pin
Pritesh Aryan, 15-Aug-11 3:27
memberPritesh Aryan15-Aug-11 3:27 
GeneralRe: Thank you. Pin
Vano Maisuradze, 17-Nov-11 4:36
memberVano Maisuradze17-Nov-11 4: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 | Terms of Use | Mobile
Web02 | 2.8.150427.2 | Last Updated 15 Aug 2011
Article Copyright 2011 by Vano Maisuradze
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid