加快Bitmap的访问速度

引言

在对Bitmap图片操作的时候,有时需要用到获取或设置像素颜色方法:GetPixel 和 SetPixel,

如果直接对这两个方法进行操作的话速度很慢,这里我们可以通过把数据提取出来操作,然后操作完在复制回去可以加快访问速度

两种方法

其实对Bitmap的访问还有两种方式,一种是内存法,一种是指针法

1、内存法

  这里定义一个类LockBitmap,通过把Bitmap数据拷贝出来,在内存上直接操作,操作完成后在拷贝到Bitmap中

复制代码
        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;

                }

            }

        }
复制代码

  使用:先锁定Bitmap,然后通过Pixels操作颜色对象,最后释放锁,把数据更新到Bitmap中

复制代码
            string file = @"C:\test.jpg";

            Bitmap bmp = new Bitmap(Image.FromFile(file));

            

            LockBitmap lockbmp = new LockBitmap(bmp);

            //锁定Bitmap,通过Pixel访问颜色

            lockbmp.LockBits();



            //获取颜色

            Color color = lockbmp.GetPixel(10, 10);



            //从内存解锁Bitmap

            lockbmp.UnlockBits();
复制代码

 2、指针法

  这种方法访问速度比内存法更快,直接通过指针对内存进行操作,不需要进行拷贝,但是在C#中直接通过指针操作内存是不安全的,所以需要在代码中加入unsafe关键字,在生成选项中把允许不安全代码勾上,才能编译通过

  这里定义成PointerBitmap类

复制代码
            public class PointBitmap

            {

                Bitmap source = null;

                IntPtr Iptr = IntPtr.Zero;

                BitmapData bitmapData = null;



                public int Depth { get; private set; }

                public int Width { get; private set; }

                public int Height { get; private set; }



                public PointBitmap(Bitmap source)

                {

                    this.source = source;

                }



                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);



                        //得到首地址

                        unsafe

                        {

                            Iptr = bitmapData.Scan0;

                            //二维图像循环

                            

                        }

                    }

                    catch (Exception ex)

                    {

                        throw ex;

                    }

                }



                public void UnlockBits()

                {

                    try

                    {

                        source.UnlockBits(bitmapData);

                    }

                    catch (Exception ex)

                    {

                        throw ex;

                    }

                }



                public Color GetPixel(int x, int y)

                {

                    unsafe

                    {

                        byte* ptr = (byte*)Iptr;

                        ptr = ptr + bitmapData.Stride * y;

                        ptr += Depth * x / 8;

                        Color c = Color.Empty;

                        if (Depth == 32)

                        {

                            int a = ptr[3];

                            int r = ptr[2];

                            int g = ptr[1];

                            int b = ptr[0];

                            c = Color.FromArgb(a, r, g, b);

                        }

                        else if (Depth == 24)

                        {

                            int r = ptr[2];

                            int g = ptr[1];

                            int b = ptr[0];

                            c = Color.FromArgb(r, g, b);

                        }

                        else if (Depth == 8)

                        {

                            int r = ptr[0];

                            c = Color.FromArgb(r, r, r);

                        }

                        return c;

                    }

                }



                public void SetPixel(int x, int y, Color c)

                {

                    unsafe

                    {

                        byte* ptr = (byte*)Iptr;

                        ptr = ptr + bitmapData.Stride * y;

                        ptr += Depth * x / 8;

                        if (Depth == 32)

                        {

                            ptr[3] = c.A;

                            ptr[2] = c.R;

                            ptr[1] = c.G;

                            ptr[0] = c.B;

                        }

                        else if (Depth == 24)

                        {

                            ptr[2] = c.R;

                            ptr[1] = c.G;

                            ptr[0] = c.B;

                        }

                        else if (Depth == 8)

                        {

                            ptr[2] = c.R;

                            ptr[1] = c.G;

                            ptr[0] = c.B;

                        }

                    }

                }

            }
复制代码

 使用方法这里就不列出来了,跟上面的LockBitmap类似

 

资料

http://www.codeproject.com/Tips/240428/Work-with-bitmap-faster-with-Csharp

你可能感兴趣的:(bitmap)