I've started with developing BMP format reader in C#. This tool might read all data from binary BMP file and represents all data from it (from the header, the pixel data etc).
I have started and have done only first 14 bytes reading (header) and getting the pixel data from 24 bit BMP file. Of course there would be a lot of work, but I'd like to know if I'm developing this correctly.
Please, review my code:
using System;
using System.IO;
using System.Text;
class BMPDataInfo
{
enum BMPHeaderTypes
{
BM, // Windows family
BA, // OS/2 struct bitmap array
CI, // OS/2 struct color icon
CP, // OS/2 const color pointer
IC, // OS/2 struct icon
PT, // OS/2 pointer
Invalid, // if two bytes from loaded file don't equal to any values of all BMP possible formats
};
byte[] fileData;
Encoding fileEncoding;
BMPFileInfo fileInfo;
class BMPFileInfo
{
internal Encoding currentEncoding;
internal BMPHeaderTypes currentBMPType;
internal uint currentFileSize;
internal int reservedFirst;
internal int reservedSecond;
internal int tablePixelStartAddress;
internal int[] tablePixel;
}
public BMPDataInfo()
{
fileInfo = new BMPFileInfo();
}
internal byte[] ReadFile(string fileName)
{
FileStream fs = new FileStream(fileName, FileMode.Open);
fileData = new byte[fs.Length];
fs.Read(fileData, 0, fileData.Length);
fs.Close();
using (var fileStreamReader = new StreamReader(fileName, true))
{
fileEncoding = fileStreamReader.CurrentEncoding;
}
switch (fileEncoding.BodyName)
{
case "utf-8":
fileInfo.currentEncoding = Encoding.UTF8;
break;
case "us-ascii":
fileInfo.currentEncoding = Encoding.ASCII;
break;
}
return fileData;
}
internal void BMPGetHeader()
{
#region Initializing the array size of 14 bytes for the BMP header
byte[] headerBMP = new byte[14];
for (int i = 0; i < headerBMP.Length; i++)
{
headerBMP[i] = fileData[i];
}
#endregion
#region Getting first TWO bytes to check the type of BMP file format
fileInfo.currentBMPType = BMPCheckHeaderType(ref headerBMP[0], ref headerBMP[1]);
#endregion
#region Getting file size from BMP header, NOT from the `Length` property of stream
byte[] fileSizeHeaderInfo = new byte[4];
// needed fix for the correct byte shift (data[i] = i << shiftValue)
for (int i = 2, j = 0; j < fileSizeHeaderInfo.Length; i++, j++)
{
fileSizeHeaderInfo[j] = fileData[i];
}
fileInfo.currentFileSize = BMPGetFileSize(ref fileSizeHeaderInfo);
#endregion
#region Getting reserved fields from BMP header
byte[] fileReservedInfo = new byte[4];
for (int i = 6, j = 0; j < fileReservedInfo.Length; i++, j++)
{
fileReservedInfo[j] = fileData[i];
}
int[] reservedResult = BMPGetReservedFromHeader(ref fileReservedInfo);
fileInfo.reservedFirst = reservedResult[0];
fileInfo.reservedSecond = reservedResult[1];
#endregion
#region Getting the starting address, of the byte where the bitmap image data (pixel array) can be found
byte[] filePixelArrayAddress = new byte[4];
for (int i = 10, j = 0; j < filePixelArrayAddress.Length; i++, j++)
{
filePixelArrayAddress[j] = fileData[i];
}
fileInfo.tablePixelStartAddress = BMPGetStartAddress(ref filePixelArrayAddress);
#endregion
#region Reading the pixel table of the current BMP
// needed to be refactored, because the test BMP file has 24 bit depth color, so: 1 pixel/3 bytes
fileInfo.tablePixel = new int[fileData.Length - fileInfo.tablePixelStartAddress];
int[] bufferTable = new int[3];
for (int i = fileInfo.tablePixelStartAddress, j = 0, k = 0; i < fileInfo.tablePixel.Length; i++, k++)
{
if (k > 2)
{
int tmpValue = 0;
for (int z = 0; z < k; z++)
{
tmpValue += bufferTable[z];
}
fileInfo.tablePixel[j] = tmpValue;
k = 0;
j++;
i++;
}
bufferTable[k] = fileData[i];
}
#endregion
}
BMPHeaderTypes BMPCheckHeaderType(ref byte firstValue, ref byte secondValue)
{
if (firstValue == 0x42 && secondValue == 0x4d)
{
return BMPHeaderTypes.BM;
}
return BMPHeaderTypes.Invalid;
}
uint BMPGetFileSize(ref byte[] headerPart)
{
uint fileSize = (uint)fileData[5] << 24
| (uint)fileData[4] << 16
| (uint)fileData[3] << 8
| (uint)fileData[2];
return fileSize;
}
int[] BMPGetReservedFromHeader(ref byte[] headerPart)
{
int reservedFirst = headerPart[0] + headerPart[1];
int reservedSecond = headerPart[2] + headerPart[3];
int[] resultReserved = new int[2];
resultReserved[0] = reservedFirst;
resultReserved[1] = reservedSecond;
return resultReserved;
}
int BMPGetStartAddress(ref byte[] headerPart)
{
int resultStartAddress = 0;
for (int i = 0; i < headerPart.Length; i++)
{
resultStartAddress += headerPart[i];
}
return resultStartAddress;
}
}
class App
{
const string fileName = @"\1.bmp";
static void Main()
{
try
{
BMPDataInfo objDataInfo = new BMPDataInfo();
objDataInfo.ReadFile(fileName);
objDataInfo.BMPGetHeader();
}
catch (Exception exc)
{
Console.WriteLine(exc);
}
}
}