VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > Python基础教程 >
  • C#教程之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 没有用

 


相关教程