Click here to Skip to main content
15,867,308 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.4K   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

 
QuestionDefinitely the fatest algoritmn Pin
MGODOY-BR17-Jan-19 2:46
MGODOY-BR17-Jan-19 2:46 
GeneralMy vote of 1 Pin
jamesford4214-Nov-18 19:14
jamesford4214-Nov-18 19:14 
QuestionHmm Pin
Member 107771646-Dec-17 8:33
Member 107771646-Dec-17 8:33 
AnswerRe: Hmm Pin
EyalY10-Apr-18 4:11
EyalY10-Apr-18 4:11 
GeneralMy vote of 5 Pin
Arthur V. Ratz28-Aug-17 23:34
professionalArthur V. Ratz28-Aug-17 23:34 
PraiseAWESOME work!!!! Pin
jcxtsoftware16-May-16 3:06
jcxtsoftware16-May-16 3:06 
GeneralRe: AWESOME work!!!! Pin
Vano Maisuradze16-May-16 4:32
Vano Maisuradze16-May-16 4:32 
QuestionUnable to use it in another function > Cannot implicitly convert type void to system.drawing.bitmap Pin
PGT2-Oct-15 5:22
PGT2-Oct-15 5:22 
AnswerRe: Unable to use it in another function > Cannot implicitly convert type void to system.drawing.bitmap Pin
Vano Maisuradze2-Oct-15 6:11
Vano Maisuradze2-Oct-15 6:11 
GeneralRe: Unable to use it in another function > Cannot implicitly convert type void to system.drawing.bitmap Pin
PGT21-Oct-15 0:04
PGT21-Oct-15 0:04 
Questionwrong time measurement Pin
Elmue13-Jul-15 10:34
Elmue13-Jul-15 10:34 
QuestionNeed to correct for stride Pin
Member 1086906713-May-15 6:52
Member 1086906713-May-15 6:52 
AnswerRe: Need to correct for stride Pin
Vano Maisuradze13-May-15 8:18
Vano Maisuradze13-May-15 8:18 
QuestionAn unhandled exception of type 'System.AccessViolationException' occurred in mscorlib.dll Pin
Member 116585561-May-15 22:46
Member 116585561-May-15 22:46 
AnswerRe: An unhandled exception of type 'System.AccessViolationException' occurred in mscorlib.dll Pin
Member 116585562-May-15 1:23
Member 116585562-May-15 1:23 
AnswerRe: An unhandled exception of type 'System.AccessViolationException' occurred in mscorlib.dll Pin
T. Kouba7-Feb-16 10:30
T. Kouba7-Feb-16 10:30 
GeneralMy vote of 5 Pin
Member 1071724430-Sep-14 21:32
Member 1071724430-Sep-14 21:32 
QuestionAnother samples comparatively Pin
Melih_123_melih5-Sep-14 4:28
Melih_123_melih5-Sep-14 4:28 
BugI found a bug Pin
94HellGate26-Sep-13 7:56
94HellGate26-Sep-13 7:56 
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 

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.