C++ School Assignment? Project Due Tomorrow? Chat LIVE With A Programming Expert!

Page 1 of 1

Storing an Array to Bitmap Converting a 16bpp grayscale array to bmp Rate Topic: -----

#1 rtokars  Icon User is offline

  • New D.I.C Head
  • Pip

Reputation: 7
  • View blog
  • Posts: 20
  • Joined: 18-July 08


Dream Kudos: 0

Share |

Storing an Array to Bitmap

Post icon  Posted 03 October 2008 - 10:40 AM

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:
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
Was This Post Helpful? 0
  • +
  • -


#2 rtokars  Icon User is offline

  • New D.I.C Head
  • Pip

Reputation: 7
  • View blog
  • Posts: 20
  • Joined: 18-July 08


Dream Kudos: 0

Re: Storing an Array to Bitmap

Posted 03 October 2008 - 11:06 AM

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?
Was This Post Helpful? 0
  • +
  • -

#3 rtokars  Icon User is offline

  • New D.I.C Head
  • Pip

Reputation: 7
  • View blog
  • Posts: 20
  • Joined: 18-July 08


Dream Kudos: 0

Re: Storing an Array to Bitmap

Posted 06 October 2008 - 09:01 AM

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

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

Was This Post Helpful? 0
  • +
  • -

#4 rtokars  Icon User is offline

  • New D.I.C Head
  • Pip

Reputation: 7
  • View blog
  • Posts: 20
  • Joined: 18-July 08


Dream Kudos: 0

Re: Storing an Array to Bitmap

Posted 07 October 2008 - 01:00 PM

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.
Was This Post Helpful? 0
  • +
  • -

#40 rtokars  Icon User is offline

  • New D.I.C Head
  • Pip

Reputation: 7
  • View blog
  • Posts: 20
  • Joined: 18-July 08


Dream Kudos: 0

Re: Storing an Array to Bitmap

Posted 10 October 2008 - 12:33 PM

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



Was This Post Helpful? 1

Page 1 of 1

1 User(s) are reading this topic
0 members, 1 guests, 0 anonymous users