using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace HS_Core.ImageFormat2D
{
///
/// The Bitmap File Header
///
struct BitmapFileHeader
{
public UInt16 bfType;
public UInt32 bfSize;
public UInt16 bfReserved1;
public UInt16 bfReserved2;
public UInt32 bfOffBits;
}
///
/// The Bitmap Info Header
///
struct BitmapHeader
{
public UInt32 biSize;
public UInt32 BiWidth;
public UInt32 BiHeight;
public UInt16 biPlanes;
public UInt16 biBitCount;
public UInt32 biCompression;
public UInt32 biSizeImage;
public UInt32 biXPelsPerMeter;
public UInt32 biYPelsPerMeter;
public UInt32 biClrUsed;
public UInt32 biClrImportant;
}
///
/// a 24bit pixel (no alpha channel)
///
struct BitmapPixel
{
public byte r;
public byte g;
public byte b;
}
///
/// Main Bitmap Class
///
class HS_Bitmap
{
private BitmapPixel[,] Pixels; //pixel data for the image
public int Width { get; private set; } //image width
public int Height { get; private set; } //image height
///
/// Constructor - Create a new Bitmap
///
/// New Image Width
/// New Image Height
public HS_Bitmap(int Width, int Height)
{
this.Width = Width;
this.Height = Height;
Pixels = new BitmapPixel[Width, Height];
}
///
/// Get pixel data of the bitmap surface
///
/// 2D array of BitmapPixel
public BitmapPixel[,] GetPixels()
{
return Pixels;
}
///
/// Set data for a single pixel
///
/// X location on bitmap
/// Y Location on bitmap
/// Pixel data
public void SetPixel(int x, int y, BitmapPixel pix)
{
if (x >= 0 && x < Width)
{
if (y >= 0 && y < Height)
{
Pixels[x, y] = pix;
}
}
}
///
/// Clear entire bitmap to a single colour
///
/// Red Value
/// Green Value
/// Blue Value
public void Clear(byte r, byte g, byte b)
{
for (int x = 0; x < Width; x++)
{
for (int y = 0; y < Height; y++)
{
Pixels[x, y].r = r;
Pixels[x, y].g = g;
Pixels[x, y].b = b;
}
}
}
///
/// Set data for a single pixel
///
/// X location on bitmap
/// Y Location on bitmap
/// Red Value
/// Green Value
/// Blue Value
public void SetPixel(int x, int y, byte r, byte g, byte b)
{
if (x >= 0 && x < Width)
{
if (y >= 0 && y < Height)
{
Pixels[x, y].r = r;
Pixels[x, y].g = g;
Pixels[x, y].b = b;
}
}
}
///
/// Set multiple pixels at once
///
/// X location in destination bitmap
/// Y location in destination bitmap
/// 2D Array of BitmapPixel to copy to destination bitmap
public void SetPixels(int x, int y, BitmapPixel[,] pixels)
{
int p_width = pixels.GetLength(0);
int p_height = pixels.GetLength(1);
for (int x2 = 0; x2 < p_width; x2++)
{
for (int y2 = 0; y2 < p_height; y2++)
{
if (x + x2 >= 0 && x + x2 < Width)
{
if (y + y2 >= 0 && y + y2 < Height)
{
Pixels[x + x2, y + y2] = pixels[x2, y2];
}
}
}
}
}
///
/// Copy another bitmap into this bitmap
///
/// X location in destination bitmap
/// Y location in destination bitmap
/// Source bitmap to copy from
public void SetPixels(int x, int y, HS_Bitmap bmp)
{
BitmapPixel[,] pixels = bmp.GetPixels();
SetPixels(x, y, pixels);
}
///
/// Provides bitmap image data in the correct format for storing in a file (.bmp)
///
/// BMP formatted pixel data
private byte[] GetBMPRawData()
{
//calculate padding and size of buffer
int ScanlineSize = Width * 3;
int BufferPadding = 0;
while ((ScanlineSize + BufferPadding) % 4 != 0)
BufferPadding++;
int Combined = BufferPadding + ScanlineSize;
byte[] Buffer = new byte[Height * Combined];
//now flip the orientation and reverse the rgb, because bitmaps.
int BufferPos = 0;
for (int y = 0; y < Height; y++)
{
for (int x = 0; x < Width; x++)
{
BufferPos = (Height - y - 1) * Combined + (x * 3);
Buffer[BufferPos] = Pixels[x, y].b;
Buffer[BufferPos + 1] = Pixels[x, y].g;
Buffer[BufferPos + 2] = Pixels[x, y].r;
}
}
return Buffer;
}
///
/// Save the current state of the bitmap to a file.
///
/// Destination file to create (include path and .bmp extension)
public void SaveBmp(string fn)
{
//this will only write 24bit bitmaps.
BitmapFileHeader BmpFileHeader = new BitmapFileHeader();
BitmapHeader BmpHeader = new BitmapHeader();
byte[] BmpData = GetBMPRawData();
UInt32 BmpFileHeaderSize = (UInt32)System.Runtime.InteropServices.Marshal.SizeOf(BmpFileHeader);
UInt32 BmpInfoHeaderSize = (UInt32)System.Runtime.InteropServices.Marshal.SizeOf(BmpHeader);
BmpFileHeader.bfSize = (UInt32)(BmpFileHeaderSize + BmpInfoHeaderSize + BmpData.Length);
BmpFileHeader.bfType = 0x4D42;
BmpFileHeader.bfReserved1 = 0;
BmpFileHeader.bfReserved2 = 0;
BmpFileHeader.bfOffBits = 54;
BmpHeader.biSize = BmpInfoHeaderSize;
BmpHeader.BiWidth = (UInt32)Width;
BmpHeader.BiHeight = (UInt32)Height;
BmpHeader.biPlanes = 1;
BmpHeader.biBitCount = 24;
BmpHeader.biCompression = 0;
BmpHeader.biSizeImage = 0;
BmpHeader.biXPelsPerMeter = 3800;
BmpHeader.biYPelsPerMeter = 3800;
BmpHeader.biClrUsed = 0;
BmpHeader.biClrImportant = 0;
StreamWriter swriter = new StreamWriter(fn);
BinaryWriter ImgStream = new BinaryWriter(swriter.BaseStream); //remember to write the file in binary you dofus :/
ImgStream.Write(BmpFileHeader.bfType);
ImgStream.Write(BmpFileHeader.bfSize);
ImgStream.Write(BmpFileHeader.bfReserved1);
ImgStream.Write(BmpFileHeader.bfReserved2);
ImgStream.Write(BmpFileHeader.bfOffBits);
ImgStream.Write(BmpHeader.biSize);
ImgStream.Write(BmpHeader.BiWidth);
ImgStream.Write(BmpHeader.BiHeight);
ImgStream.Write(BmpHeader.biPlanes);
ImgStream.Write(BmpHeader.biBitCount);
ImgStream.Write(BmpHeader.biCompression);
ImgStream.Write(BmpHeader.biSizeImage);
ImgStream.Write(BmpHeader.biXPelsPerMeter);
ImgStream.Write(BmpHeader.biYPelsPerMeter);
ImgStream.Write(BmpHeader.biClrUsed);
ImgStream.Write(BmpHeader.biClrImportant);
for (int n = 0; n < BmpData.Length; n++)
{
ImgStream.Write(BmpData[n]);
}
swriter.Dispose();
ImgStream.Dispose();
}
}
}