mirror of
https://github.com/danbulant/Cosmos
synced 2026-05-19 12:30:32 +00:00
172 lines
7 KiB
C#
172 lines
7 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Text;
|
|
|
|
namespace Cosmos.System.Graphics
|
|
{
|
|
public class Bitmap : Image
|
|
{
|
|
public Bitmap(uint Width, uint Height, ColorDepth colorDepth) : base(Width, Height, colorDepth)
|
|
{
|
|
rawData = new int[Width * Height];
|
|
}
|
|
|
|
public void Save(string path)
|
|
{
|
|
using (FileStream fs = File.Open(path, FileMode.Create))
|
|
{
|
|
Save(fs, ImageFormat.bmp);
|
|
}
|
|
}
|
|
|
|
public void Save(Stream stream, ImageFormat imageFormat)
|
|
{
|
|
Byte[] file = new Byte[54 /*header*/ + width * height * (uint)depth / 8 /*assume that it is full bytes */];
|
|
|
|
//Set signature
|
|
byte[] data = BitConverter.GetBytes(0x4D42);
|
|
stream.Write(data, 0, 2);
|
|
//Write apporiximate file size
|
|
data = BitConverter.GetBytes(54 /*header*/ + width * height * (uint)depth / 8 /*assume that it is full bytes */);
|
|
stream.Write(data, 0, data.Length);
|
|
//Leave bytes 6 -> 10 empty
|
|
data = new Byte[] { 0, 0, 0, 0 };
|
|
stream.Write(data, 0, 4);
|
|
//Offset to start of iamge data
|
|
uint offset = 54;
|
|
data = BitConverter.GetBytes(offset);
|
|
stream.Write(data, 0, 4);
|
|
//Write size of bitmapinfoheader
|
|
data = BitConverter.GetBytes(40);
|
|
stream.Write(data, 0, 4);
|
|
//Width in pixels
|
|
data = BitConverter.GetBytes(width);
|
|
stream.Write(data, 0, 4);
|
|
//Height in pixels
|
|
data = BitConverter.GetBytes(height);
|
|
stream.Write(data, 0, 4);
|
|
//Number of palnes(1)
|
|
data = BitConverter.GetBytes(1);
|
|
stream.Write(data, 0, 2);
|
|
//Bits per pixel
|
|
data = BitConverter.GetBytes((int)depth);
|
|
stream.Write(data, 0, 2);
|
|
//Compression type
|
|
data = BitConverter.GetBytes(0);
|
|
stream.Write(data, 0, 4);
|
|
//Size of image data in bytes
|
|
data = BitConverter.GetBytes(width * height * (uint)depth / 8);
|
|
stream.Write(data, 0, 4);
|
|
//Horizontal resolution in meters (is not accurate)
|
|
data = BitConverter.GetBytes(width / 40);
|
|
stream.Write(data, 0, 4);
|
|
//Vertical resolution in meters (is not accurate)
|
|
data = BitConverter.GetBytes(height / 40);
|
|
stream.Write(data, 0, 4);
|
|
//Number of colors in image /zero
|
|
data = BitConverter.GetBytes(0);
|
|
stream.Write(data, 0, 4);
|
|
//number of important colors in iamge / zero
|
|
data = BitConverter.GetBytes(0);
|
|
stream.Write(data, 0, 4);
|
|
//Finished header
|
|
|
|
//Copy image data
|
|
stream.Position = offset;
|
|
Byte[] imageData = new Byte[width * height * (int)depth / 8];
|
|
int imageDataPoint = 0;
|
|
for (int y = 0; y < width; y++)
|
|
{
|
|
for (int x = 0; x < height; x++)
|
|
{
|
|
data = BitConverter.GetBytes(rawData[x + (height - (1 + y)) * width]);
|
|
for (int i = 0; i < data.Length; i++)
|
|
{
|
|
imageData[i + imageDataPoint] = data[i];
|
|
}
|
|
imageDataPoint += data.Length;
|
|
}
|
|
}
|
|
stream.Write(imageData, 0, imageData.Length);
|
|
|
|
stream.Flush();
|
|
}
|
|
|
|
public static Bitmap CreateBitmap(string path)
|
|
{
|
|
#region BMP Header
|
|
|
|
Byte[] text = File.ReadAllBytes(path);
|
|
//Assume that we are using the BMP (Windows) header format
|
|
//I am using http://www.fastgraph.com/help/bmp_header_format.html
|
|
//and https://upload.wikimedia.org/wikipedia/commons/c/c4/BMPfileFormat.png?1519566101894as as reference
|
|
//read header - bytes 10 -> 14 is the offset of the bitmap image data
|
|
uint pixelTableOffset = (uint)BitConverter.ToInt32(text, 10);
|
|
//now reading size of BITMAPINFOHEADER should be 40 - bytes 14 -> 18
|
|
uint infoHeaderSize = (uint)BitConverter.ToInt32(text, 14);
|
|
if (infoHeaderSize != 40) throw new Exception("Info header size has the wrong value!");
|
|
|
|
//now reading width of image in pixels - bytes 18 -> 22
|
|
uint imageWidth = (uint)BitConverter.ToInt32(text, 18);
|
|
|
|
//now reading height of image in pixels - byte 22 -> 26
|
|
uint imageHeight = (uint)BitConverter.ToInt32(text, 22);
|
|
|
|
//now reading number of planes should be 1 - byte 26 -> 28
|
|
ushort planes = (ushort)BitConverter.ToInt16(text, 26);
|
|
if (planes != 1)
|
|
throw new Exception("Number of planes is not 1! Can not read file!");
|
|
|
|
//now reading size of bits per pixel (1, 4, 8, 24, 32) - bytes 28 - 30
|
|
ushort pixelSize = (ushort)BitConverter.ToInt16(text, 28);
|
|
//TODO: Be able to handle other pixel sizes
|
|
if (pixelSize != 32)
|
|
throw new NotImplementedException("Can only handle 32bit pictures!");
|
|
|
|
//now reading compression type - bytes 30 -> 34
|
|
uint compression = (uint)BitConverter.ToInt32(text, 30);
|
|
//TODO: Be able to handle compressed files
|
|
if (compression != 0)
|
|
throw new NotImplementedException("Can only handle uncompressed files!");
|
|
|
|
//now reading total image data size(including padding) - bytes 34 -> 38
|
|
uint totalImageSize = (uint)BitConverter.ToInt32(text, 34);
|
|
//Somehow this is 0 for my test bmp
|
|
|
|
#endregion BMP Header
|
|
|
|
Bitmap bitmap = new Bitmap(imageWidth, imageHeight, (ColorDepth)pixelSize);
|
|
|
|
#region Pixel Table
|
|
|
|
//Calculate padding
|
|
int paddingPerRow = 0;
|
|
if (totalImageSize != 0) //I think this happens when there is not padding
|
|
{
|
|
int pureImageSize = (int)(imageWidth * imageHeight * pixelSize / 8);
|
|
int remainder = (int)totalImageSize - pureImageSize;
|
|
if (remainder < 0) throw new Exception("Total Image Size is smaller than pure image size");
|
|
paddingPerRow = remainder / (int)imageHeight;
|
|
}
|
|
//Read data
|
|
int position = (int)pixelTableOffset;
|
|
Byte[] _pixel = new byte[pixelSize / 8]; //Pixel size is in byte
|
|
|
|
for (int x = 0; x < imageWidth; x++)
|
|
{
|
|
for (int y = 0; y < imageHeight; y++)
|
|
{
|
|
bitmap.rawData[x + (imageHeight - (y + 1)) * imageWidth] = BitConverter.ToInt32(text, position);
|
|
position += (int)imageWidth * pixelSize / 8 + paddingPerRow;
|
|
}
|
|
position += pixelSize / 8;
|
|
position -= pixelSize / 8 * ((int)imageWidth + paddingPerRow) * (int)imageHeight;
|
|
}
|
|
|
|
#endregion Pixel Table
|
|
|
|
return bitmap;
|
|
}
|
|
}
|
|
}
|