【C#】加快Bitmap的访问速度

来源:互联网 发布:淘宝店铺logo设计 编辑:程序博客网 时间:2024/04/25 13:31

 

在对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类似

 

 

以上图片由“图斗罗”提供

阅读全文
0 0