Direct Access Pixel Data, GetPixel, SetPixel
using System; using System.Drawing; using System.Drawing.Imaging; using System.IO; public unsafe class MemoryBitmap : IDisposable { private readonly BitmapData _bmpData; private readonly int _depth; private readonly byte* _pfp; private readonly int _stride; private Bitmap _memoryBitmap; public MemoryBitmap(string path) { if (path.IsNullOrEmpty()) throw new Exception("Path cannot be null or empty."); if (!File.Exists(path)) throw new Exception($"Path {path} does not exist."); var bitmap = new Bitmap(path); _memoryBitmap = bitmap; if (_memoryBitmap.PixelFormat != PixelFormat.Format32bppArgb && _memoryBitmap.PixelFormat != PixelFormat.Format24bppRgb && _memoryBitmap.PixelFormat != PixelFormat.Format8bppIndexed) { var clone = new Bitmap(_memoryBitmap.Width, _memoryBitmap.Height, PixelFormat.Format32bppArgb); using (var gr = Graphics.FromImage(clone)) { gr.DrawImage(_memoryBitmap, new Rectangle(0, 0, clone.Width, clone.Height)); _memoryBitmap = clone; } } Width = _memoryBitmap.Width; Height = _memoryBitmap.Height; var rect = new Rectangle(0, 0, _memoryBitmap.Width, _memoryBitmap.Height); try { _bmpData = _memoryBitmap.LockBits(rect, ImageLockMode.ReadWrite, _memoryBitmap.PixelFormat); } catch (Exception ex) { throw new Exception("Could not lock bitmap", ex.InnerException); } _depth = Image.GetPixelFormatSize(_bmpData.PixelFormat) / 8; _pfp = (byte*) _bmpData.Scan0.ToPointer(); _stride = _bmpData.Stride; } public MemoryBitmap(Bitmap bitmap) { _memoryBitmap = bitmap ?? throw new Exception("Bitmap cannot be null"); if (_memoryBitmap.PixelFormat != PixelFormat.Format32bppArgb && _memoryBitmap.PixelFormat != PixelFormat.Format24bppRgb && _memoryBitmap.PixelFormat != PixelFormat.Format8bppIndexed) { var clone = new Bitmap(_memoryBitmap.Width, _memoryBitmap.Height, PixelFormat.Format32bppArgb); using (var gr = Graphics.FromImage(clone)) { gr.DrawImage(_memoryBitmap, new Rectangle(0, 0, clone.Width, clone.Height)); _memoryBitmap = clone; } } Width = _memoryBitmap.Width; Height = _memoryBitmap.Height; var rect = new Rectangle(0, 0, _memoryBitmap.Width, _memoryBitmap.Height); try { _bmpData = _memoryBitmap.LockBits(rect, ImageLockMode.ReadWrite, _memoryBitmap.PixelFormat); } catch (Exception ex) { throw new Exception("Could not lock bitmap", ex.InnerException); } _depth = Image.GetPixelFormatSize(_bmpData.PixelFormat) / 8; _pfp = (byte*) _bmpData.Scan0.ToPointer(); _stride = _bmpData.Stride; } public int Width { get; } public int Height { get; } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } public void ConvertFormat(PixelFormat newPf) { var clone = new Bitmap(_memoryBitmap.Width, _memoryBitmap.Height, newPf); using (var gr = Graphics.FromImage(clone)) { gr.DrawImage(_memoryBitmap, new Rectangle(0, 0, clone.Width, clone.Height)); _memoryBitmap = clone; } } public void Save(string path) { _memoryBitmap.Save(path); } protected virtual void Dispose(bool disposing) { if (!disposing) return; if (_memoryBitmap != null) _memoryBitmap.UnlockBits(_bmpData); } private byte* PixelPointer(int x, int y) { return _pfp + y * _stride + x * _depth; } public Color GetPixel(int x, int y) { if (x < 0 || y < 0 || x >= Width || y >= Height) throw new Exception("Coordinates out of range"); int a, r, g, b; var p = PixelPointer(x, y); if (_memoryBitmap.PixelFormat == PixelFormat.Format32bppArgb) { b = *p++; g = *p++; r = *p++; a = *p; return Color.FromArgb(a, r, g, b); } if (_memoryBitmap.PixelFormat == PixelFormat.Format24bppRgb) { b = *p++; g = *p++; r = *p; return Color.FromArgb(r, g, b); } if (_memoryBitmap.PixelFormat == PixelFormat.Format8bppIndexed) { a = *p; return Color.FromArgb(a, a, a); } return default; } public void SetPixel(int x, int y, Color col) { if (x < 0 || y < 0 || x >= Width || y >= Height) throw new Exception("Coordinates out of range"); var p = PixelPointer(x, y); if (_memoryBitmap.PixelFormat == PixelFormat.Format32bppArgb) { *p++ = col.B; *p++ = col.G; *p++ = col.R; *p = col.A; return; } if (_memoryBitmap.PixelFormat == PixelFormat.Format24bppRgb) { *p++ = col.B; *p++ = col.G; *p = col.R; return; } if (_memoryBitmap.PixelFormat == PixelFormat.Format8bppIndexed) *p = col.B; } }