wwt-website/WWTWebservices/FastBitmap.cs

295 строки
8.0 KiB
C#

using System;
using System.Drawing;
using System.Drawing.Imaging;
namespace WWTWebservices
{
public struct PixelData
{
public byte blue;
public byte green;
public byte red;
public byte alpha;
public PixelData(int r, int g, int b, int a) // values between 0 and 255
{
blue = (byte)(b >= 255 ? 255 : (b < 0 ? 0 : b));
red = (byte)(r >= 255 ? 255 : (r < 0 ? 0 : r));
green = (byte)(g >= 255 ? 255 : (g < 0 ? 0 : g));
alpha = (byte)(a >= 255 ? 255 : (a < 0 ? 0 : a));
}
}
public unsafe class FastBitmapEnumerator : IDisposable
{
int x;
int y;
FastBitmap fastBitmap;
PixelData* pCurrentPixel;
bool locked;
public FastBitmapEnumerator(FastBitmap fastBitmap)
{
fastBitmap.LockBitmap();
locked = true;
this.fastBitmap = fastBitmap;
x = -1;
y = 0;
pCurrentPixel = fastBitmap[x, y];
}
public void Dispose()
{
if (locked)
{
fastBitmap.UnlockBitmap();
}
}
public bool MoveNext()
{
x++;
pCurrentPixel++;
if (x == fastBitmap.Size.X)
{
y++;
if (y == fastBitmap.Size.Y)
{
return false;
}
else
{
x = 0;
pCurrentPixel = fastBitmap[0, y];
//Debug.WriteLine(String.Format("{0}", pCurrentPixel - fastBitmap[0, 0]));
}
}
return true;
}
public PixelData* Current
{
get
{
return pCurrentPixel;
}
}
}
/// <summary>
/// A bitmap class that allows fast x, y access
/// </summary>
public unsafe class FastBitmap
{
Bitmap bitmap;
// three elements used for MakeGreyUnsafe
int width;
BitmapData bitmapData = null;
Byte* pBase = null;
PixelData* pCurrentPixel = null;
int xLocation;
int yLocation;
Point size;
internal bool locked = false;
/// <summary>
/// Create an instance from an existing bitmap
/// </summary>
/// <param name="bitmap">The bitmap</param>
public FastBitmap(Bitmap bitmap)
{
this.bitmap = bitmap;
GraphicsUnit unit = GraphicsUnit.Pixel;
RectangleF bounds = bitmap.GetBounds(ref unit);
size = new Point((int)bounds.Width, (int)bounds.Height);
}
/// <summary>
/// Save the bitmap to a file
/// </summary>
/// <param name="filename">Filename to save the bitmap to</param>
public void Save(string filename)
{
bitmap.Save(filename, ImageFormat.Jpeg);
}
public void Dispose()
{
bitmap.Dispose();
}
/// <summary>
/// Size of the bitmap in pixels
/// </summary>
public Point Size
{
get
{
return size;
}
}
/// <summary>
/// The Bitmap object wrapped by this instance
/// </summary>
public Bitmap Bitmap
{
get
{
return (bitmap);
}
}
/// <summary>
/// Start at the beginning of the bitmap
/// </summary>
public void InitCurrentPixel()
{
LockBitmap();
//if (pBase == null)
//{
// throw new InvalidOperationException("Bitmap must be locked before calling InitCurrentPixel()");
// }
pCurrentPixel = (PixelData*)pBase;
}
/// <summary>
/// Return the next pixel
/// </summary>
/// <returns>The next pixel, or null if done</returns>
public PixelData* GetNextPixel()
{
PixelData* pReturnPixel = pCurrentPixel;
if (xLocation == size.X)
{
xLocation = 0;
yLocation++;
if (yLocation == size.Y)
{
UnlockBitmap();
return null;
}
else
{
pCurrentPixel = this[0, yLocation];
}
}
else
{
xLocation++;
pCurrentPixel++;
}
return pReturnPixel;
}
/// <summary>
/// Get the pixel data at a specific x and y location
/// </summary>
public PixelData* this[int x, int y]
{
get
{
return (PixelData*)(pBase + y * width + x * sizeof(PixelData));
}
}
public FastBitmapEnumerator GetEnumerator()
{
return new FastBitmapEnumerator(this);
}
/// <summary>
/// Lock the bitmap.
/// </summary>
public void LockBitmap()
{
GraphicsUnit unit = GraphicsUnit.Pixel;
RectangleF boundsF = bitmap.GetBounds(ref unit);
Rectangle bounds = new Rectangle((int)boundsF.X,
(int)boundsF.Y,
(int)boundsF.Width,
(int)boundsF.Height);
// Figure out the number of bytes in a row
// This is rounded up to be a multiple of 4
// bytes, since a scan line in an image must always be a multiple of 4 bytes
// in length.
width = (int)boundsF.Width * sizeof(PixelData);
if (width % 4 != 0)
{
width = 4 * (width / 4 + 1);
}
bitmapData =
bitmap.LockBits(bounds, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
pBase = (Byte*)bitmapData.Scan0.ToPointer();
locked = true;
}
/// <summary>
/// Unlock the bitmap
/// </summary>
public void UnlockBitmap()
{
bitmap.UnlockBits(bitmapData);
bitmapData = null;
pBase = null;
locked = false;
}
public PixelData GetFilteredPixel(double xd, double yd)
{
int x = (int)(xd);
double xr = xd - (double)x;
int y = (int)(yd);
double yr = yd - (double)y;
if (x < 0 || x > (bitmap.Width - 1) || y < 0 || y > (bitmap.Height - 1))
{
return new PixelData();
}
int stepX = 1;
int stepY = 1;
if (x == bitmap.Width - 1)
{
stepX = 0;
}
if (y == bitmap.Height - 1)
{
stepY = 0;
}
PixelData* tl = this[x, y];
PixelData* tr = this[x + stepX, y];
PixelData* bl = this[x, y + stepY];
PixelData* br = this[x + stepX, y + stepY];
PixelData result;
result.alpha = (byte)((((((double)tl->alpha * (1.0 - xr)) + ((double)tr->alpha * xr))) * (1.0 - yr)) +
(((((double)bl->alpha * (1.0 - xr)) + ((double)br->alpha * xr))) * yr));
result.red = (byte)((((((double)tl->red * (1.0 - xr)) + ((double)tr->red * xr))) * (1.0 - yr)) +
(((((double)bl->red * (1.0 - xr)) + ((double)br->red * xr))) * yr));
result.green = (byte)((((((double)tl->green * (1.0 - xr)) + ((double)tr->green * xr))) * (1.0 - yr)) +
(((((double)bl->green * (1.0 - xr)) + ((double)br->green * xr))) * yr));
result.blue = (byte)((((((double)tl->blue * (1.0 - xr)) + ((double)tr->blue * xr))) * (1.0 - yr)) +
(((((double)bl->blue * (1.0 - xr)) + ((double)br->blue * xr))) * yr));
return result;
}
}
}