• LockBitmap 修正版


    目前在做图片主题色提取相关的事情,所以搜索到的了 LockBitmap 这个类,但是发现其中取出的颜色有些问题,明明没有的颜色,却出现在主题色里面,经过多方面排除,之后确定是 LockBitmap 的问题,这个类相关的文章已经被转发了很多次,基本上到处都是,但是只有少数人提出问题(如 https://www.cnblogs.com/xiashengwang/p/4225848.html 的评论里面),也没给出相关的解决方案,所以只能自己改了

    修正版如下:(修改了 50/95/137 行)

      1 public class LockBitmap : IDisposable
      2     {
      3         Bitmap source = null;
      4         IntPtr Iptr = IntPtr.Zero;
      5         BitmapData bitmapData = null;
      6 
      7         public byte[] Pixels { get; set; }
      8         public int Depth { get; private set; }
      9         public int Width { get; private set; }
     10         public int Height { get; private set; }
     11 
     12         public LockBitmap(Bitmap source)
     13         {
     14             this.source = source;
     15             LockBits();
     16         }
     17 
     18         /// <summary>
     19         /// Lock bitmap data
     20         /// </summary>
     21         public void LockBits()
     22         {
     23             try
     24             {
     25                 // Get width and height of bitmap
     26                 Width = source.Width;
     27                 Height = source.Height;
     28 
     29                 // get total locked pixels count
     30                 //int PixelCount = Width * Height;
     31 
     32                 // Create rectangle to lock
     33                 System.Drawing.Rectangle rect = new System.Drawing.Rectangle(0, 0, Width, Height);
     34 
     35                 // get source bitmap pixel format size
     36                 Depth = System.Drawing.Bitmap.GetPixelFormatSize(source.PixelFormat);
     37 
     38                 // Check if bpp (Bits Per Pixel) is 8, 24, or 32
     39                 if (Depth != 8 && Depth != 24 && Depth != 32)
     40                 {
     41                     throw new ArgumentException("Only 8, 24 and 32 bpp images are supported.");
     42                 }
     43 
     44                 // Lock bitmap and return bitmap data
     45                 bitmapData = source.LockBits(rect, ImageLockMode.ReadWrite,
     46                                              source.PixelFormat);
     47 
     48                 // create byte array to copy pixel values
     49                 int step = Depth / 8;
     50                 Pixels = new byte[bitmapData.Stride * Height];
     51                 Iptr = bitmapData.Scan0;
     52 
     53                 // Copy data from pointer to array
     54                 Marshal.Copy(Iptr, Pixels, 0, Pixels.Length);
     55             }
     56             catch (Exception ex)
     57             {
     58                 throw ex;
     59             }
     60         }
     61 
     62         /// <summary>
     63         /// Unlock bitmap data
     64         /// </summary>
     65         public void UnlockBits()
     66         {
     67             try
     68             {
     69                 // Copy data from byte array to pointer
     70                 Marshal.Copy(Pixels, 0, Iptr, Pixels.Length);
     71 
     72                 // Unlock bitmap data
     73                 source.UnlockBits(bitmapData);
     74             }
     75             catch (Exception ex)
     76             {
     77                 throw ex;
     78             }
     79         }
     80 
     81         /// <summary>
     82         /// Get the color of the specified pixel
     83         /// </summary>
     84         /// <param name="x"></param>
     85         /// <param name="y"></param>
     86         /// <returns></returns>
     87         public Color GetPixel(int x, int y)
     88         {
     89             Color clr = Color.Empty;
     90 
     91             // Get color components count
     92             int cCount = Depth / 8;
     93 
     94             // Get start index of the specified pixel
     95             //int i = ((y * Width) + x) * cCount;
     96             int i = y * bitmapData.Stride + x * cCount;
     97 
     98             if (i > Pixels.Length - cCount)
     99                 throw new IndexOutOfRangeException();
    100 
    101             if (Depth == 32) // For 32 bpp get Red, Green, Blue and Alpha
    102             {
    103                 byte b = Pixels[i];
    104                 byte g = Pixels[i + 1];
    105                 byte r = Pixels[i + 2];
    106                 byte a = Pixels[i + 3]; // a
    107                 clr = Color.FromArgb(a, r, g, b);
    108             }
    109             if (Depth == 24) // For 24 bpp get Red, Green and Blue
    110             {
    111                 byte b = Pixels[i];
    112                 byte g = Pixels[i + 1];
    113                 byte r = Pixels[i + 2];
    114                 clr = Color.FromArgb(r, g, b);
    115             }
    116             if (Depth == 8)
    117             // For 8 bpp get color value (Red, Green and Blue values are the same)
    118             {
    119                 byte c = Pixels[i];
    120                 clr = Color.FromArgb(c, c, c);
    121             }
    122             return clr;
    123         }
    124 
    125         /// <summary>
    126         /// Set the color of the specified pixel
    127         /// </summary>
    128         /// <param name="x"></param>
    129         /// <param name="y"></param>
    130         /// <param name="color"></param>
    131         public void SetPixel(int x, int y, Color color)
    132         {
    133             // Get color components count
    134             int cCount = Depth / 8;
    135 
    136             // Get start index of the specified pixel
    137             //int i = ((y * Width) + x) * cCount;
    138             int i = y * bitmapData.Stride + x * cCount;
    139 
    140             if (Depth == 32) // For 32 bpp set Red, Green, Blue and Alpha
    141             {
    142                 Pixels[i] = color.B;
    143                 Pixels[i + 1] = color.G;
    144                 Pixels[i + 2] = color.R;
    145                 Pixels[i + 3] = color.A;
    146             }
    147             if (Depth == 24) // For 24 bpp set Red, Green and Blue
    148             {
    149                 Pixels[i] = color.B;
    150                 Pixels[i + 1] = color.G;
    151                 Pixels[i + 2] = color.R;
    152             }
    153             if (Depth == 8)
    154             // For 8 bpp set color value (Red, Green and Blue values are the same)
    155             {
    156                 Pixels[i] = color.B;
    157             }
    158         }
    159 
    160         public bool IsValidCoordinate(int x, int y)
    161         {
    162             return x >= 0 && x < this.Width && y > 0 && y < this.Height;
    163         }
    164 
    165         #region IDisposable Support
    166         private bool disposedValue = false; // 要检测冗余调用
    167 
    168         protected virtual void Dispose(bool disposing)
    169         {
    170             if (!disposedValue)
    171             {
    172                 if (disposing)
    173                 {
    174                     // TODO: 释放托管状态(托管对象)。
    175                 }
    176 
    177                 // TODO: 释放未托管的资源(未托管的对象)并在以下内容中替代终结器。
    178                 // TODO: 将大型字段设置为 null。
    179                 UnlockBits();
    180                 disposedValue = true;
    181             }
    182         }
    183 
    184         // TODO: 仅当以上 Dispose(bool disposing) 拥有用于释放未托管资源的代码时才替代终结器。
    185         // ~LockBitmap() {
    186         //   // 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。
    187         //   Dispose(false);
    188         // }
    189 
    190         // 添加此代码以正确实现可处置模式。
    191         void IDisposable.Dispose()
    192         {
    193             // 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。
    194             Dispose(true);
    195             // TODO: 如果在以上内容中替代了终结器,则取消注释以下行。
    196             // GC.SuppressFinalize(this);
    197         }
    198         #endregion
    199     }

    使用方式:

        using (var bitmap = new LockBitmap(img))
        {
            for (int i = 0; i < img.Width; i++)
            {
                for (int j = 0; j < img.Height; j++)
                {
                    tempColor = bitmap.GetPixel(i, j);
                }
            }
        }

    Stride 和 Width 的区别参考:http://blog.csdn.net/ustcxiangchun/article/details/25893883 

    这里有个问题:我用了 https://www.cnblogs.com/bomo/archive/2013/02/26/2934055.html 里面的指针法,然后 MVC 的属性【允许不安全的代码】也勾选了,但是发布 Release 版本无论怎样都发布不成功,只能发布 Debug 版本,如果有知道的怎么发布的 Release 版本的,希望评论告知一下,感谢。编译环境:VS2015 、ASP.NET MVC 5 、.NET Framework 4.5.2。尝试过的方式:web.config 配置 "/unsafe+"=true 没有用

  • 相关阅读:
    Python--魔法方法
    Flask之request实现思想
    关于python一切皆对象的理解
    python快速生成依赖包
    redis的安装和使用
    linux-环境变量的配置
    python-虚拟环境的配置
    11-Linux-系统服务
    10-Linux-进程管理
    [SCOI2014]方伯伯的玉米田
  • 原文地址:https://www.cnblogs.com/elen/p/8340574.html
Copyright © 2020-2023  润新知