Welcome to Dream.In.Code
Getting C++ Help is Easy!

Join 136,834 C++ Programmers for FREE! Get instant access to thousands of C++ experts, tutorials, code snippets, and more! There are 1,763 people online right now. Registration is fast and FREE... Join Now!




Storing an Array to Bitmap

 
Closed TopicStart new topic

Storing an Array to Bitmap, Converting a 16bpp grayscale array to bmp

rtokars
3 Oct, 2008 - 10:40 AM
Post #1

New D.I.C Head
*

Joined: 18 Jul, 2008
Posts: 18

I have a pointer to an array that stores a GrayScale 16 bits per pixel image and I'm trying to save it as a BMP. I'm able to create the BITMAP, but when I open the BMP file it shows up in color (instead of GrayScale).
My code is:
CODE

void SaveBitmapToFile( uns16* 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 0×4D42
    // 0×4D = M 0×42 = B storing in reverse order to match with endian
    bfh.bfType=0x4D42;
    /* or
    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 RGB Data
    WriteFile( hFile, pBitmapBits, bmpInfoHeader.biSizeImage, &dwWritten, NULL );
    // Close the file handle
    CloseHandle( hFile );
}


pBitmapBits is the 16bpp array
lWidth is 1024 pixels
lHeight is 1024 pixels
wBitsPerPixel is 16
lpszFileName is SavedImage.bmp
User is offlineProfile CardPM
+Quote Post

rtokars
RE: Storing An Array To Bitmap
3 Oct, 2008 - 11:06 AM
Post #2

New D.I.C Head
*

Joined: 18 Jul, 2008
Posts: 18

Because the array is GrayScale, the color bmp comes out all distorted. What should I change so that it is a saved 16bpp GrayScale BMP?
User is offlineProfile CardPM
+Quote Post

rtokars
RE: Storing An Array To Bitmap
6 Oct, 2008 - 09:01 AM
Post #3

New D.I.C Head
*

Joined: 18 Jul, 2008
Posts: 18

I tried a different approach to the BMP code shown below. The results are still pretty much the same, unable to save the file effectively as a Grayscale 16bpp... I also attached the kind of results I'm getting, compressed as a jpg file. The result.jpg shows the result from the code from the first post on the left side of the image. The result from the code from this current post is on the right side of the image. Anyone help? thx

CODE

void SaveBitmapToFile( uns16* lpBits, LONG lWidth, LONG lHeight, WORD wBitsPerPixel, LPCTSTR pszFile, HWND hwnd )
{
    
    PBITMAPINFO pbmi;
    WORD    cClrBits;                         
    int biPlanesSetBU = 1;

    // Convert the color format to a count of bits.
    cClrBits = (WORD)(biPlanesSetBU * wBitsPerPixel);  //cClrBits = 16 in our case

    // Allocate memory for the BITMAPINFO structure. (This structure
    // contains a BITMAPINFOHEADER structure and an array of RGBQUAD
    // data structures.)

     if (cClrBits != 24)
         pbmi = (PBITMAPINFO) LocalAlloc(LPTR,
                    sizeof(BITMAPINFOHEADER) +
                    sizeof(RGBQUAD) * (1<< cClrBits));

     // There is no RGBQUAD array for the 24-bit-per-pixel format.

     else
         pbmi = (PBITMAPINFO) LocalAlloc(LPTR,
                    sizeof(BITMAPINFOHEADER));

    // Initialize the fields in the BITMAPINFO structure.

    pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);  // biSize = 40
    pbmi->bmiHeader.biWidth = lWidth;             //lwidth = 1024
    pbmi->bmiHeader.biHeight = -1*lHeight;         // -1024 so that image is displayed rightside up
    pbmi->bmiHeader.biPlanes = biPlanesSetBU;  // biPlaneSetBU = 1
    pbmi->bmiHeader.biBitCount = wBitsPerPixel; // wBitsPerPixel = 16

    if (cClrBits < 24)
        pbmi->bmiHeader.biClrUsed = (1<<cClrBits);

    // If the bitmap is not compressed, set the BI_RGB flag.
    pbmi->bmiHeader.biCompression = BI_RGB;

    // Compute the number of bytes in the array of color
    // indices and store the result in biSizeImage.
    // For Windows NT, the width must be DWORD aligned unless
    // the bitmap is RLE compressed. This example shows this.
    // For Windows 95/98/Me, the width must be WORD aligned unless the
    // bitmap is RLE compressed.
    pbmi->bmiHeader.biSizeImage = ((pbmi->bmiHeader.biWidth * cClrBits +31) & ~31) /8    //biSizeImage = 2097152
                                  * -1 * pbmi->bmiHeader.biHeight;
    // Set biClrImportant to 0, indicating that all of the
    // device colors are important.
    pbmi->bmiHeader.biClrImportant = 0;

    HANDLE hf;                 // file handle
    BITMAPFILEHEADER hdr = {0};       // bitmap file-header
    PBITMAPINFOHEADER pbih;     // bitmap info-header
    //LPBYTE lpBits;              // memory pointer
    DWORD dwTotal;              // total count of bytes
    DWORD cb;                   // incremental count of bytes
    //uns16 *hp;                   // byte pointer
    DWORD dwTmp = 0;
    pbih = &pbmi->bmiHeader;
                            

    // Retrieve the color table (RGBQUAD array) and the bits
    // (array of palette indices) from the DIB.
    /*if (!GetDIBits(hDC, hBMP, 0, (WORD) pbih->biHeight, lpBits, pbi,
        DIB_RGB_COLORS))
    {
        MessageBox(hwnd, "Error Get DI Bits", "Error", MB_OK);
                            
    }*/

    // Create the .BMP file.
    hf = CreateFile(pszFile,
                   GENERIC_READ | GENERIC_WRITE,
                   (DWORD) 0,
                    NULL,
                   CREATE_ALWAYS,
                   FILE_ATTRIBUTE_NORMAL,
                   (HANDLE) NULL);
    if (hf == INVALID_HANDLE_VALUE)
        MessageBox(hwnd, "Error creating file", "Error", MB_OK);
                            
    hdr.bfType = 0x4d42;        // 0x42 = "B" 0x4d = "M"
    // Compute the size of the entire file.
    hdr.bfSize = (DWORD) (sizeof(BITMAPFILEHEADER) +
                 pbih->biSize + pbih->biClrUsed
                 * sizeof(RGBQUAD) + pbih->biSizeImage);
    hdr.bfReserved1 = 0;
    hdr.bfReserved2 = 0;

    // Compute the offset to the array of color indices.
    hdr.bfOffBits = (DWORD) sizeof(BITMAPFILEHEADER) +
                    pbih->biSize + pbih->biClrUsed
                    * sizeof (RGBQUAD);

    // Copy the BITMAPFILEHEADER into the .BMP file.
    if (!WriteFile(hf, (LPVOID) &hdr, sizeof(BITMAPFILEHEADER),
                    (LPDWORD) &dwTmp,  NULL))
       MessageBox(hwnd, "Error writing file1", "Error", MB_OK);                        
    
    // Copy the BITMAPINFOHEADER and RGBQUAD array into the file.
    if (!WriteFile(hf, (LPVOID) pbih, sizeof(BITMAPINFOHEADER)
                  + pbih->biClrUsed * sizeof (RGBQUAD),
                  (LPDWORD) &dwTmp, ( NULL)))
        MessageBox(hwnd, "Error writing file2", "Error", MB_OK);
                            
    // Copy the array of color indices into the .BMP file.
    dwTotal = cb = pbih->biSizeImage; //4292870144
  
    if (!WriteFile(hf, lpBits, (int) cb, (LPDWORD) &dwTmp, NULL))
        MessageBox(hwnd, "Error writing file3", "Error", MB_OK);            

    // Close the .BMP file.
    if (!CloseHandle(hf))
        MessageBox(hwnd, "Error closing file4", "Error", MB_OK);

}




Attached thumbnail(s)
Attached Image
User is offlineProfile CardPM
+Quote Post

rtokars
RE: Storing An Array To Bitmap
7 Oct, 2008 - 01:00 PM
Post #4

New D.I.C Head
*

Joined: 18 Jul, 2008
Posts: 18

Do I need to post any more info? I haven't seen any suggestions.

I'm going to try and compress the array from a 16bpp to a 8bpp and see if I can make a color pallete that will keep the image in GrayScale. Wish me luck.
User is offlineProfile CardPM
+Quote Post

rtokars
RE: Storing An Array To Bitmap
10 Oct, 2008 - 12:33 PM
Post #5

New D.I.C Head
*

Joined: 18 Jul, 2008
Posts: 18

Consider this issue closed. The code below can be directly coppied into Microsoft Visual Studio. It gives a basic idea of how to manipulate a grayscale image image with a Color Table. Hopefully this will shed some light on future programmers trying to manipulate BMPs.
CODE

#include <stdio.h>
#include <windows.h>
#include <shlwapi.h>
#include <stdlib.h>

void SaveBitmapToFile( LONG lWidth, LONG lHeight);

LPCTSTR StrBmpFileNameBMP = "Image.bmp";

int main(void)
{

    int width = 1024;
    int height = 1024;
    SaveBitmapToFile(width, height);
    return 0;
}

void SaveBitmapToFile( LONG lWidth, LONG lHeight)
{
    BITMAPINFOHEADER bmpInfoHeader = {0};
    // Set the size
    bmpInfoHeader.biSize = sizeof(BITMAPINFOHEADER);
    // Bit count
    bmpInfoHeader.biBitCount = 8; //image already processed to be 8bpp
    // 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; //0    //mgiht want to use BI_BITFIELDS and set up the bmiColors like u did below with the color table
    // Set the height in pixels
    bmpInfoHeader.biHeight = -1*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 = 0; //lWidth* lHeight * (wBitsPerPixel/8); // or try sizeof(RGBTRIPLE)*lWidth*lHeight // possible to set to zero (if not compression)

    BYTE count=0;

    BYTE *procframe;
    procframe = (BYTE*)malloc( 1048576 * sizeof(BYTE) ); //1024x1024 = 1048576
    if (procframe == NULL)
    {
        puts("Error");
        return;
    }

    for (int i = 0; i < 1048576; i++, procframe++)
    {

        *procframe = count;
        if (count == 255)
            count=0;
        else
            count++;        
    }

    procframe = procframe - 1048576;  //important  must move the pointer back to the starting position!!!

    RGBQUAD ColorTable[256];    //used for color table purposes
    for (int i = 0; i < 256; i++)
    {
        ColorTable[i].rgbBlue = i;
        ColorTable[i].rgbGreen = i;
        ColorTable[i].rgbRed = i;
        ColorTable[i].rgbReserved = 0;
    }

    BITMAPFILEHEADER bfh = {0};
    // This value should be values of BM letters i.e 0×4D42
    // 0×4D = M 0×42 = B storing in reverse order to match with endian
    bfh.bfType=0x4D42;/* 19778   'BM'    or    bfh.bfType = ‘B’+(’M’ << 8);    // <<8 used to shift ‘M’ to end*/
    // Offset to the RGBQUAD
    bfh.bfOffBits = sizeof(BITMAPINFOHEADER) + sizeof(BITMAPFILEHEADER) + sizeof(ColorTable); //specifies the offset from the beginning of the file to the bitmap data. //prob should add + sizeof(ColorTable)
    // Total size of image including size of headers
    bfh.bfSize = bfh.bfOffBits + 1048576 * sizeof(BYTE); // or try sizeof(BITMAPINFOHEADER)
    // Create the file in disk to write
    
    HANDLE hFile = CreateFile( StrBmpFileNameBMP,GENERIC_WRITE, 0,NULL,

                               CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,NULL);

    if( !hFile ) // return if error opening file
    {
        free(procframe);
        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 RGBQuad Color Table
    WriteFile( hFile, ColorTable, sizeof(ColorTable), &dwWritten, NULL);
    // Write the RGB Data
    WriteFile( hFile, procframe, 1048576 * sizeof(BYTE), &dwWritten, NULL);   //its not passing as an array
    //WriteFile( hFile, pBitmapBits, bmpInfoHeader.biSizeImage, &dwWritten, NULL );
    // Close the file handle

    free(procframe);
    CloseHandle( hFile );
}


User is offlineProfile CardPM
+Quote Post

Closed TopicStart new topic
Time is now: 12/3/08 03:57PM

Live C++ Help!

C++ Tutorials

Reference Sheets

C++ Snippets

DIC Chatroom

Bye Bye Ads

Monthly Drawing

Thumb Drive

Top Contributors

Top 10 Kudos This Month