As the GetPixel and SetPixel functions provided by the .NET framework are (so) slow, I had to write my own implementation of it. This Bitmap class allows you to access image pixels directly from the memory (via unsafe code.) Trust me, this is way faster!
To-do list:
Features:
- Way faster than the core framework's implementation. (~ 10 times faster!)
- Supports Format32bppArgb, Format24bppRgb.
- Support for more image formats.
- Suggestions?
Here it is, QBitmap.cs:
// http://codecav.blogspot.in/ public unsafe class QBitmap : IDisposable { private Bitmap _bitmap; private BitmapData _bitmapData; public int Width { get; private set; } public int Height { get; private set; } public PixelFormat PixelFormat { get; private set; } public QBitmap(Bitmap bitmap) { _bitmap = bitmap; Initialize(); } private void Initialize() { if (_bitmap == null) throw new ArgumentNullException(); Width = _bitmap.Width; Height = _bitmap.Height; PixelFormat = _bitmap.PixelFormat; } public void LockBits() { try { _bitmapData = _bitmap.LockBits(new Rectangle(0, 0, Width, Height), ImageLockMode.ReadWrite, PixelFormat); } catch (Exception e) { throw new Exception(e.Message); } } public void UnlockBits() { try { _bitmap.UnlockBits(_bitmapData); } catch (Exception e) { throw new Exception(e.Message); } } public Color GetPixel(int x, int y) { byte a = 0, r, g, b; var pData = (byte*) _bitmapData.Scan0.ToPointer(); switch (PixelFormat) { case PixelFormat.Format32bppArgb: b = *(pData + (y * _bitmapData.Stride) + (x * 4)); g = *(pData + (y * _bitmapData.Stride) + (x * 4) + 1); r = *(pData + (y * _bitmapData.Stride) + (x * 4) + 2); a = *(pData + (y * _bitmapData.Stride) + (x * 4) + 3); break; case PixelFormat.Format24bppRgb: b = *(pData + (y * _bitmapData.Stride) + (x * 3)); g = *(pData + (y * _bitmapData.Stride) + (x * 3) + 1); r = *(pData + (y * _bitmapData.Stride) + (x * 3) + 2); break; // Support for more formats. case PixelFormat.Format8bppIndexed: case PixelFormat.Format4bppIndexed: case PixelFormat.Format1bppIndexed: default: throw new NotSupportedException("The specified pixel format is not supported."); } return Color.FromArgb(a, r, g, b); } public void SetPixel(int x, int y, Color color) { var pData = (byte*) _bitmapData.Scan0.ToPointer(); switch (PixelFormat) { case PixelFormat.Format32bppArgb: *(pData + (y*_bitmapData.Stride) + (x*4)) = color.B; *(pData + (y*_bitmapData.Stride) + (x*4) + 1) = color.G; *(pData + (y*_bitmapData.Stride) + (x*4) + 2) = color.R; *(pData + (y*_bitmapData.Stride) + (x*4) + 3) = color.A; break; case PixelFormat.Format24bppRgb: *(pData + (y*_bitmapData.Stride) + (x*3)) = color.B; *(pData + (y*_bitmapData.Stride) + (x*3) + 1) = color.G; *(pData + (y*_bitmapData.Stride) + (x*3) + 2) = color.R; break; // Support for more formats. case PixelFormat.Format8bppIndexed: case PixelFormat.Format4bppIndexed: case PixelFormat.Format1bppIndexed: default: throw new NotSupportedException("The specified pixel format is not supported."); } } private bool _disposed; public void Dispose() { if (_disposed) return; _bitmap.Dispose(); _bitmap = null; _disposed = true; } }
Usage:
// QBitmap usage (http://codecav.blogspot.in/) var image = (Bitmap) Image.FromFile("Path\To\Image.png"); using (var qBitmap = new QBitmap(image)) { qBitmap.LockBits(); // Perform operations on the image. qBitmap.UnlockBits(); }
Feel free to ask/suggest anything. Have fun with it!