• 加快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:	est.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

  • 相关阅读:
    本周总结
    团队组队
    ListView之checkbox错位问题解决
    ListView
    ScrollView(滚动条)
    elementui中自定义Select选择器样式自定义
    element-ui中Select 选择器列表内容居中
    element-ui中Select 选择器去除点击时的淡蓝色边框
    vue和uni-app不同的类型绑定不同的类名
    根据年月日获取星期几
  • 原文地址:https://www.cnblogs.com/itelite/p/4605074.html
Copyright © 2020-2023  润新知