C++ How to create a bitmap file

user2557642 picture user2557642 · Sep 17, 2013 · Viewed 27.3k times · Source

I am trying to figure out how to create a bitmap file in C++ VS. Currently I have taken in the file name and adding the ".bmp" extension to create the file. I want to know how I could change the pixels of the file by making it into different colors or patterns (ie. like a checkerboard) This is my function that I have and I believe that I have to send 3 different Bytes at a time in order to establish the color of the pixel.

void makeCheckerboardBMP(string fileName, int squaresize, int n) {
    ofstream ofs;
    ofs.open(fileName + ".bmp");
    writeHeader(ofs, n, n);

    for(int row = 0; row < n; row++) {
        for(int col = 0; col < n; col++) {

            if(col % 2 == 0) {
                ofs << 0;
                ofs << 0;
                ofs << 0;
            } else {
                ofs << 255;
                ofs << 255;
                ofs << 255;
            }
        }
    }
}

void writeHeader(ostream& out, int width, int height){
    if (width % 4 != 0) {
        cerr << "ERROR: There is a windows-imposed requirement on BMP that the width be a          
multiple of 4.\n";
        cerr << "Your width does not meet this requirement, hence this will fail.  You can fix     
this\n";
        cerr << "by increasing the width to a multiple of 4." << endl;
        exit(1);
    }

    BITMAPFILEHEADER tWBFH;
    tWBFH.bfType = 0x4d42;
    tWBFH.bfSize = 14 + 40 + (width*height*3);
    tWBFH.bfReserved1 = 0;
    tWBFH.bfReserved2 = 0;
    tWBFH.bfOffBits = 14 + 40;

    BITMAPINFOHEADER tW2BH;
    memset(&tW2BH,0,40);
    tW2BH.biSize = 40;
    tW2BH.biWidth = width;
    tW2BH.biHeight = height;
    tW2BH.biPlanes = 1;
    tW2BH.biBitCount = 24;
    tW2BH.biCompression = 0;

    out.write((char*)(&tWBFH),14);
    out.write((char*)(&tW2BH),40);
}

Answer

SinisterMJ picture SinisterMJ · Sep 17, 2013

These are the two functions I am using for my code (one greyscale, one RGB saving).

Might give you a hint whats going wrong. Note: they are done to work, not to be efficient.

void SaveBitmapToFile( BYTE* pBitmapBits, LONG lWidth, LONG lHeight,WORD wBitsPerPixel, LPCTSTR lpszFileName )
{
    RGBQUAD palette[256];
    for(int i = 0; i < 256; ++i)
    {
        palette[i].rgbBlue = (byte)i;
        palette[i].rgbGreen = (byte)i;
        palette[i].rgbRed = (byte)i;
    }

    BITMAPINFOHEADER bmpInfoHeader = {0};
    // Set the size
    bmpInfoHeader.biSize = sizeof(BITMAPINFOHEADER);
    // Bit count
    bmpInfoHeader.biBitCount = wBitsPerPixel;
    // Use all colors
    bmpInfoHeader.biClrImportant = 0;
    // Use as many colors according to bits per pixel
    bmpInfoHeader.biClrUsed = 0;
    // Store as un Compressed
    bmpInfoHeader.biCompression = BI_RGB;
    // Set the height in pixels
    bmpInfoHeader.biHeight = lHeight;
    // Width of the Image in pixels
    bmpInfoHeader.biWidth = lWidth;
    // Default number of planes
    bmpInfoHeader.biPlanes = 1;
    // Calculate the image size in bytes
    bmpInfoHeader.biSizeImage = lWidth* lHeight * (wBitsPerPixel/8);

    BITMAPFILEHEADER bfh = {0};
    // This value should be values of BM letters i.e 0x4D42
    // 0x4D = M 0×42 = B storing in reverse order to match with endian

    bfh.bfType = 'B'+('M' << 8);
    // <<8 used to shift ‘M’ to end

    // Offset to the RGBQUAD
    bfh.bfOffBits = sizeof(BITMAPINFOHEADER) + sizeof(BITMAPFILEHEADER) + sizeof(RGBQUAD) * 256;
    // Total size of image including size of headers
    bfh.bfSize = bfh.bfOffBits + bmpInfoHeader.biSizeImage;
    // Create the file in disk to write
    HANDLE hFile = CreateFile( lpszFileName,GENERIC_WRITE, 0,NULL,
        CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,NULL);

    if( !hFile ) // return if error opening file
    {
        return;
    }

    DWORD dwWritten = 0;
    // Write the File header
    WriteFile( hFile, &bfh, sizeof(bfh), &dwWritten , NULL );
    // Write the bitmap info header
    WriteFile( hFile, &bmpInfoHeader, sizeof(bmpInfoHeader), &dwWritten, NULL );
    // Write the palette
    WriteFile( hFile, &palette[0], sizeof(RGBQUAD) * 256, &dwWritten, NULL );
    // Write the RGB Data
    if(lWidth%4 == 0)
    {
        WriteFile( hFile, pBitmapBits, bmpInfoHeader.biSizeImage, &dwWritten, NULL );
    }
    else
    {
        char* empty = new char[ 4 - lWidth % 4];
        for(int i = 0; i < lHeight; ++i)
        {
            WriteFile( hFile, &pBitmapBits[i * lWidth], lWidth, &dwWritten, NULL );
            WriteFile( hFile, empty,  4 - lWidth % 4, &dwWritten, NULL );
        }
    }
    // Close the file handle
    CloseHandle( hFile );
}

void SaveBitmapToFileColor( BYTE* pBitmapBits, LONG lWidth, LONG lHeight,WORD wBitsPerPixel, LPCTSTR lpszFileName )
{

    BITMAPINFOHEADER bmpInfoHeader = {0};
    // Set the size
    bmpInfoHeader.biSize = sizeof(BITMAPINFOHEADER);
    // Bit count
    bmpInfoHeader.biBitCount = wBitsPerPixel;
    // Use all colors
    bmpInfoHeader.biClrImportant = 0;
    // Use as many colors according to bits per pixel
    bmpInfoHeader.biClrUsed = 0;
    // Store as un Compressed
    bmpInfoHeader.biCompression = BI_RGB;
    // Set the height in pixels
    bmpInfoHeader.biHeight = lHeight;
    // Width of the Image in pixels
    bmpInfoHeader.biWidth = lWidth;
    // Default number of planes
    bmpInfoHeader.biPlanes = 1;
    // Calculate the image size in bytes
    bmpInfoHeader.biSizeImage = lWidth* lHeight * (wBitsPerPixel/8);

    BITMAPFILEHEADER bfh = {0};
    // This value should be values of BM letters i.e 0x4D42
    // 0x4D = M 0×42 = B storing in reverse order to match with endian

    bfh.bfType = 'B'+('M' << 8);
    // <<8 used to shift ‘M’ to end

    // Offset to the RGBQUAD
    bfh.bfOffBits = sizeof(BITMAPINFOHEADER) + sizeof(BITMAPFILEHEADER);
    // Total size of image including size of headers
    bfh.bfSize = bfh.bfOffBits + bmpInfoHeader.biSizeImage;
    // Create the file in disk to write
    HANDLE hFile = CreateFile( lpszFileName,GENERIC_WRITE, 0,NULL,
        CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,NULL);

    if( !hFile ) // return if error opening file
    {
        return;
    }

    DWORD dwWritten = 0;
    // Write the File header
    WriteFile( hFile, &bfh, sizeof(bfh), &dwWritten , NULL );
    // Write the bitmap info header
    WriteFile( hFile, &bmpInfoHeader, sizeof(bmpInfoHeader), &dwWritten, NULL );
    // Write the palette
    //WriteFile( hFile, &palette[0], sizeof(RGBQUAD) * 256, &dwWritten, NULL );
    // Write the RGB Data
    if(lWidth%4 == 0)
    {
        WriteFile( hFile, pBitmapBits, bmpInfoHeader.biSizeImage, &dwWritten, NULL );
    }
    else
    {
        char* empty = new char[ 4 - lWidth % 4];
        for(int i = 0; i < lHeight; ++i)
        {
            WriteFile( hFile, &pBitmapBits[i * lWidth], lWidth, &dwWritten, NULL );
            WriteFile( hFile, empty,  4 - lWidth % 4, &dwWritten, NULL );
        }
    }
    // Close the file handle
    CloseHandle( hFile );
}