Link to home
Start Free TrialLog in
Avatar of WalterRautenbach
WalterRautenbach

asked on

Create 1 bit bitmap from raw data

Hi there

I am using a 3rd party software sdk to enocde a 2d barcode.  The function returns a pointer to the raw image data.  The image data is 1 bit per pixel data.  Their document also states that the image is 4 byte aligned (what ever that means?)  The function returns with the width and height of the image as well (I am not sure if the width and height is that of the image as a 1 byte per pixel image or 1 bit per pixel image).  I also see that the function returns with a Palette but I am not sure if this is relevant.

My question is, I want to display the 2D barcode and store it as a Bitmap in the DB.  How can I create the  1 bit bitmap?
Avatar of DanRollins
DanRollins
Flag of United States of America image

Do you have a way to save the raw pixel data to a file and attach it to a post here?  If so, I can provide code to create a monochrome BMP from it.

I'd need the width and height.  
The four-byte alignment is standard.  It just means that if the width in bytes is not a multiple of four, there are bytes of binary zero added to the right-hand side of the image data matrix.
Avatar of WalterRautenbach
WalterRautenbach

ASKER

Hi Dan

Thanks for the assistance.  I attached the file.  The widht = 364 and the height = 212.

You will find that I wrote 52264 bytes to the file.  I am not sure if this is correct as the SDK does not say how many bytes is actually returned (I am pretty sure you can calculate it though using width * height / 8 or something??).  The way I got to 52264 is it was the first value that did not give me an access violation reading passed the returned image buffer.

Thanks again
bits.txt
I can't get a reasonable image from that data.  But when I use a width of
    384
it looks like it might be a barcode.  Does the attached look like the image you scannned?
bits1.bmp
Hi Dan

Great work, it looks like it, it just seems swapped.  Please find attached what the image should look like.

Regards.  Why do you think 384 would work?
2dBarcode.zip
The 384 makes sense... I was doing the 32-bit alignment logic wrong.  A 364-pixel wide image must actually be 384 wide so that it is a multiple of 32 (4-byte aligned)

The attached is from an MFC project, but I've avoided use of CBitmap and other MFC objects.  You won't be using the CFile object, since you already have a buffer containing the data.

The for() loop copies the bottom line to the top, and so forth.   Raw bitmap data is expected to have the scanlines in bottom-to-top order.
void CD49Dlg::OnButton2() 
{
	int nWide= 364;
	int nHigh= 212;
 
	// account for line length needing to be 32-bit chunks
 
	int nDwordsPerLine= (nWide + 31)/32;
	int nBytesPerLine=  nDwordsPerLine * 4;
	int nPixelsPerLine= nBytesPerLine  * 8;
 
	int nDataLen= nBytesPerLine * nHigh;  // amount of data to read from the file
 
	BYTE* pabBitsRaw= new BYTE[nDataLen];
	BYTE* pabBits=    new BYTE[nDataLen];
 
	CFile cFile("c:\\temp\\bits.txt", CFile::modeRead );
 
	int n= cFile.Read(	pabBitsRaw, nDataLen );
	cFile.Close();
 
	// raw bitmap data must be set to top-line on the bottom, etc.
	//
	for (int y=0; y<nHigh; y++ ) {
		BYTE* pSrc= &pabBitsRaw[ ((nHigh-1)-y) * nBytesPerLine];
		BYTE* pDst= &pabBits   [  y            * nBytesPerLine];
		memmove( pDst, pSrc, nBytesPerLine );
	}
 
	HBITMAP hBmp= ::CreateBitmap( nPixelsPerLine, nHigh, 1, 1, pabBits );
 
	m_ctlBmp.SetBitmap( hBmp ); // this lets me display the result
 
	delete pabBits;           // cleanup allocations
	delete pabBitsRaw;
}

Open in new window

ASKER CERTIFIED SOLUTION
Avatar of DanRollins
DanRollins
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Sir, THANK YOU!!!!!!  It works perfectly.  Thanks again
I have one question though:

int nDwordsPerLine= (nWide + 31)/32;

Why 31?  Where do you get that from?

Thanks
Quoted from the grading comment:
   "Sir, THANK YOU!!!!!! It works perfectly. Thanks again"

You are welcome.  I'm glad to help and this type of problem always interests me.

As to:
  z= (n+31)/32

What that does is create a number (z) that is the next higher multiple of 32, but if n is already a multiple of 32, then z ends up the same as n.  It works perfectly when z is an integer datatype because in integer division, the remainder (what would be the fraction after the decimal point) is discarded.

Any number smaller than 31 would not work correctly in every case.

Note that this is similar to another  technique to "round a number"  up or down:
    z= (n+16)/32
Afterwards, z is the the lext lower multiple of 32 (if it is less than halfway between multiples), but will be the next higher multiple if n is more than halfway to the next multiple.  It's a bit easier to understand if using round number decimals, such as 100:
   z= (n+50)/100
the result (z) will always be a multiple of 100 (0, 100, 200, 300...) and if n is less than halfway between multiples (e.g., 100, 121, 135, 149, etc) then z will "round down" -- end up as 100).  But if n is *more than or exactly* halfway (150, 155, 179, 199) then z will "round up" and be the next higher multiple (200).
Thank you for the explanation.  I am pretty sure I understand now.  Of course that value (31) will have then to change if the image width increases or decreases.

Thanks again.
The formula (and the program code) will provide the correct size for any image width.  It calculates the width in "4-byte-aligned" units.
Oh, ok, thanks, so I did not really understand then.  Thanks for your patience.