Skip to main content
1 of 3

C# BMP reader the begging

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 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'm interested "did I start to develop in correct way?"

Please, review my code: http://ideone.com/4ZxyAJ

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