How to convert the method to use lockbits instead getpixel and setpixel ?

Chocolade 536 Reputation points
2023-01-31T19:36:11.3866667+00:00

The method. when i'm using multiple files it's slowly and make the whole application working slowly.

public void ReadSetPixels(Bitmap image1, Bitmap image2)
        {
            image1.SetResolution(96, 96);
            image2.SetResolution(96, 96);

            int tolerance = 64;
            for (int x = 0; x < image1.Width; x++)
            {
                for (int y = 0; y < image1.Height; y++)
                {
                    Color pixelColor = image1.GetPixel(x, y);
                    // just average R, G, and B values to get gray. Then invert by 255.
                    int invertedGrayValue = 255 - (int)((pixelColor.R + pixelColor.G + pixelColor.B) / 3);
                    if (invertedGrayValue > tolerance) { invertedGrayValue = 255; }
                    // this keeps the original pixel color but sets the alpha value
                    image1.SetPixel(x, y, Color.FromArgb(invertedGrayValue, pixelColor));
                }
            }
            // composite image1 on top of image2
            using (Graphics g = Graphics.FromImage(image2))
            {
                g.CompositingMode = CompositingMode.SourceOver;
                g.CompositingQuality = CompositingQuality.HighQuality;
                g.DrawImage(image1, new Point(0, 0));
            }

            image2.Save(@"d:\mynewbmp.bmp");
            image1.Dispose();
            image2.Dispose();
        }
Developer technologies Windows Forms
Developer technologies C#
0 comments No comments
{count} votes

Accepted answer
  1. Reza Aghaei 4,986 Reputation points MVP Volunteer Moderator
    2023-01-31T22:18:28.8166667+00:00

    I've answered a similar question here. The code is originally written by Vano Maisuradze with some small modifications. The class is using LockBits method and provides fast version of GetPixel and SetPixel methods.

    Here is the class:

    using System.Drawing.Imaging;
    using System.Runtime.InteropServices;
    
    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()
        {
            // 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);
        }
    
        /// <summary>
        /// Unlock bitmap data
        /// </summary>
        public void UnlockBits()
        {
            // Copy data from byte array to pointer
            Marshal.Copy(Pixels, 0, Iptr, Pixels.Length);
    
            // Unlock bitmap data
            source.UnlockBits(bitmapData);
        }
    
        /// <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;
            }
        }
    }
    

    You can simply modify your code to use the class like this:

    var img1 = new LockBitmap(image1);
    img1.LockBits();
    // img1.GetPixel ...
    // img1.SetPixel ...
    img1.UnlockBits();
    // now changes have been applied on image1 
    

1 additional answer

Sort by: Most helpful
  1. Castorix31 90,521 Reputation points
    2023-01-31T21:40:18.03+00:00

    You can convert the VB code I had posted in this thread to convert pixels into gray :

    Pixel manipulation written in csharp needs more than an automatic conversion...

    (https://icsharpcode.github.io/CodeConverter/)


Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.