using System; using System.Drawing; using System.Drawing.Imaging; namespace ClassicalSharp { /// Represents a wrapper around a bitmap. Provides /// a fast implementation for getting and setting pixels in that bitmap. /// Only supports 32 bit RGBA pixel format. public unsafe class FastBitmap : IDisposable { /// Constructs a new FastBitmap wrapped around the specified Bitmap. /// Bitmap which is wrapped. /// Whether to immediately lock the bits of the bitmap, /// so that get and set pixel operations can be performed immediately after construction. public FastBitmap( Bitmap bmp, bool lockBits ) { Bitmap = bmp; if( lockBits ) { LockBits(); } } public Bitmap Bitmap; BitmapData data; byte* scan0; int stride; public bool IsLocked { get { return data != null; } } /// Gets the address of the first pixel in this bitmap. public IntPtr Scan0 { get { return data.Scan0; } } /// Gets the stride width/scan width of the bitmap. /// (i.e. the actual size of each scanline, including padding) public int Stride { get { return data.Stride; } } /// Gets the width of this bitmap, in pixels. public int Width { get { return data.Width; } } /// Gets the height of this bitmap, in pixels. public int Height { get { return data.Height; } } /// Locks the wrapped bitmap into system memory, /// so that fast get/set pixel operations can be performed. public void LockBits() { if( Bitmap == null ) throw new InvalidOperationException( "Bmp is null." ); if( data != null ) { Bitmap.UnlockBits( data ); } PixelFormat format = Bitmap.PixelFormat; if( !( format == PixelFormat.Format32bppArgb || format == PixelFormat.Format32bppRgb ) ) { throw new NotSupportedException( "Unsupported bitmap pixel format: " + format ); } Rectangle rec = new Rectangle( 0, 0, Bitmap.Width, Bitmap.Height ); data = Bitmap.LockBits( rec, ImageLockMode.ReadWrite, format ); scan0 = (byte*)data.Scan0; stride = data.Stride; } public void Dispose() { UnlockBits(); } public void UnlockBits() { if( data != null ) { Bitmap.UnlockBits( data ); data = null; scan0 = (byte*)IntPtr.Zero; stride = 0; } } public int GetPixel( int x, int y ) { // TODO: Does this work with big-endian systems? int* row = (int*)( scan0 + ( y * stride ) ); return row[x]; // b g r a } public int* GetRowPtr( int y ) { return (int*)( scan0 + ( y * stride ) ); } public void SetPixel( int x, int y, int col ) { int* row = (int*)( scan0 + ( y * stride ) ); row[x] = col; } } }