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;
}
}
}