Link to home
Start Free TrialLog in
Avatar of flynny
flynnyFlag for United Kingdom of Great Britain and Northern Ireland

asked on

help creating monochrome bitmap from existing bitmap

Hi

I'm trying to wrtie a method that will highlight an images. i.e. set al the pixels of a set rgb to be black and all others to be white. I then want to return this as HBITMAP.

its almost working but i can't work out where i'm going wrong and hope you can help me.

i create the bitmap like so

BITMAPFILEHEADER* bfh = (BITMAPFILEHEADER *) malloc(sizeof(BITMAPFILEHEADER));
bfh->bfType='B'+('M'<<8);
bfh->bfOffBits= sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER) + 8; //offset to bitmap pixel data + 8 is for the two colour bytes
bfh->bfSize= paddedSize + bfh->bfOffBits;
bfh->bfReserved1=0;
bfh->bfReserved2=0;

BITMAPINFOHEADER* Bmi      = (BITMAPINFOHEADER *) malloc(sizeof(BITMAPINFOHEADER));
Bmi->biSize                  = sizeof(BITMAPINFOHEADER);
Bmi->biWidth                  = WorkBmp.bmWidth; //WorkBmp is the orginal BITMAP
Bmi->biHeight            = WorkBmp.bmHeight;
Bmi->biPlanes            = 1;
Bmi->biBitCount            = 1;
Bmi->biCompression            = BI_RGB;  //BI_RGB=0
Bmi->biSizeImage            = paddedSize;
Bmi->biXPelsPerMeter      = 0;
Bmi->biYPelsPerMeter      = 0;
Bmi->biClrUsed      = 0;
Bmi->biClrImportant      = 0;

where paddedSize

int paddedSize = WorkBmp.bmHeight * ( WorkBmp.bmWidth/8 + (4- (WorkBmp.bmWidth/8%4)));
            
RGBQUAD colors[2];
   colors[0].rgbBlue = colors[0].rgbGreen = colors[0].rgbRed = 0;
   colors[1].rgbBlue = colors[1].rgbGreen = colors[1].rgbRed = 255;
   colors[0].rgbReserved = colors[1].rgbReserved = 0;

HDC hdc = GetDC(NULL);
LPBITMAPINFO bi = (LPBITMAPINFO) malloc(sizeof(LPBITMAPINFO));
bi->bmiHeader = *Bmi;
bi->bmiColors[0] = colors[0];
bi->bmiColors[1] = colors[1];

HBITMAP hBitmap = ::CreateDIBSection(hdc, (LPBITMAPINFO)bi, DIB_RGB_COLORS, (LPVOID *)pBmiSrc, NULL, 0);
ReleaseDC(NULL, hdc);

to write the image to a file i use

CBitmap* cBitmap = CBitmap::FromHandle(highlightedBitmap);

CPalette cPal;
HANDLE bHandle = DDBToDIB(*cBitmap, BI_RGB ,&cPal);
BOOL writtenOK = WriteDIB(outstr, bHandle);      

where DDBToDIB and WriteDIB were pulled from the web and i have tesed them and they have worked for me in the past.

however the problem is it simpy creates black images if i write it to a file using the returned HBITMAP. I know that pBmiSrc, the bit array, is correct as i have tried manually adding its contents into a hex editor and the bitmap is then appears as it should.
Avatar of Zoppo
Zoppo
Flag of Germany image

Hi flynny,

maybe the problem comes from how you allocate the BITMAPINFO:

> LPBITMAPINFO bi = (LPBITMAPINFO) malloc(sizeof(LPBITMAPINFO));

First you use 'sizeof(LPBITMAPINFO)' which is for sure wrong since this just allocates the size of a pointer (4 bytes) ... further I think you'll have to allocate in addition the memory for the colortable, so maybe somehow like this should work:

> LPBITMAPINFO bi = (LPBITMAPINFO) malloc(sizeof( BITMAPINFO ) + 2 * sizeof( RGBQUAD ) );

Hope that helps,

ZOPPO
I think that "hBitmap" is already a DIB, so you can pass it directly to WriteDIB() without using CBitmap and DDBToDIB:


HBITMAP hBitmap = ::CreateDIBSection(hdc, (LPBITMAPINFO)bi, DIB_RGB_COLORS, (LPVOID *)pBmiSrc, NULL, 0);
BOOL writtenOK = WriteDIB(outstr, hBitmap );      
Maybe the following link is helpful:

http://support.microsoft.com/kb/77282/en-us

Regards, Alex
Avatar of flynny

ASKER

hi guys thanks for the replies.

yes i think the problem looks like it could be in the LPBITMAPINFO as if i do the following it writes the bitmap ok

    FILE *p = fopen( "c:\\test12345.bmp", "wb" );
    fwrite( bfh, sizeof(BITMAPFILEHEADER), 1, p );
    fwrite( Bmi, sizeof(BITMAPINFOHEADER), 1, p );
    fwrite( &colors[0],4, 1, p );
    fwrite( &colors[1],4, 1, p );
    fwrite( pBmiSrc,Bmi->biSizeImage, 1, p );
    fclose( p );

like you said alb66 i tried passing the hbitmap to theWrteDIB method and it doesnt appear to be writing the hbitmap

i create and pass as follows

BOOL writtenOK = WriteDIB("c:\\test12345.bmp", hBitmap );

and it seems to fail here
int nColors = 1 << lpbi->biBitCount;

i assume because its not been able to cast hDIB to a LPBITMAPINFOHEADER? any ideas why it does this?




BOOL CBitmapOCR::WriteDIB( LPTSTR szFile, HANDLE hDIB)
{
	BITMAPFILEHEADER	hdr;
	LPBITMAPINFOHEADER	lpbi;
 
	if (!hDIB)
		return FALSE;
 
	CFile file;
	if( !file.Open( szFile, CFile::modeWrite|CFile::modeCreate) )
		return FALSE;
 
	lpbi = (LPBITMAPINFOHEADER)hDIB;
	int nColors = 1 << lpbi->biBitCount;
 
	// Fill in the fields of the file header 
	hdr.bfType		= ((WORD) ('M' << 8) | 'B');	// is always "BM"
	hdr.bfSize		= GlobalSize (hDIB) + sizeof( hdr );
 
	hdr.bfReserved1 	= 0;
	hdr.bfReserved2 	= 0;
	hdr.bfOffBits		= (DWORD) (sizeof( hdr ) + lpbi->biSize +
						nColors * sizeof(RGBQUAD));
 
	// Write the file header 
	file.Write( &hdr, sizeof(hdr) );
 
	// Write the DIB header and the bits 
	file.Write( lpbi, GlobalSize(hDIB) );
 
	return TRUE;
}

Open in new window

> and it seems to fail here
what do you mean with it fails? does it crash?
Avatar of flynny

ASKER

yes it crashes after

lpbi = (LPBITMAPINFOHEADER)hDIB;

once i try and access any variable in the LPBITMAPINFOHEADER. I read somewhere that i will need to convert the HBitmap to a handle by globalalloc-ing the memory. I tried this but it didn't seem to work using the following

HBITMAP hBitmap = ::CreateDIBSection(hdc, (LPBITMAPINFO)bi, DIB_RGB_COLORS, (LPVOID *)&pBmiSrc, NULL, 0);
HGLOBAL memPtr = GlobalAlloc(GMEM_FIXED, sizeof(hBitmap)); //pointer to mem block

HBITMAP tmpBitmap;
if( memPtr && (tmpBitmap = (HBITMAP)GlobalLock(memPtr)) != NULL )
      tmpBitmap = hBitmap;

BOOL writtenOK = WriteDIB("c:\\test12345.bmp", tmpBitmap);

this just did exactly the same thing.
>>>> lpbi = (LPBITMAPINFOHEADER)hDIB;

The hDIB is a handle to a bitmap. It is some kind of 'id' used from Windows to identify its resources. Though most likely there is a association from the handle to some structure, the handle itself is not a pointer and therefore it crashes.  

Normally, you have a HBITMAP handle to a DDB (a device-dependent-bitmap where the device is the screen) and you call GetDIBits to get the bits from that bitmap.

You should check the link I gave you above. There is full source code for exactly the task you asked for.
Avatar of flynny

ASKER

hi itsme, sorry i did mention the link in my first reply but unfortunately the ie crashed and so had to retype and in my rush forgot to readd about this. ;)

The difference between the link and what i want to do is that the link will simply convert the image to monochrome and i have no control upon which pixel/s will be black and which will be white (for example in theory i woulld like to be able to specify the colour white to be highlighted.)

However using the CreateBitmap method seemed to solve the problem of creating the bitmap however its still working a little strangely.

i now create the bitmap like so

HBITMAP hbmMono = ::CreateBitmap(WorkBmp.bmWidth, WorkBmp.bmHeight, 1, 1, pBmiSrc);

where

int paddedSize = WorkBmp.bmHeight * ( WorkBmp.bmWidth/8 + (4- (WorkBmp.bmWidth/8%4)));
BYTE* pBmiSrc = new BYTE[ paddedSize ];

and send this to the method included below. however it seems to only be pulling back half of the byte array?

instead of outputting  

424D62000000000000003E0000002800000005000000090000000100010000000000240000000000000000000000000000000000000000000000FFFFFF00880000007000000070000000700000007000000070000000700000007000000088000000

i'm outputting

424D62000000000000003E0000002800000005000000090000000100010000000000240000000000000000000000000000000000000000000000FFFFFF00880000007000000070000000700000007000CDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCD

any ideas why this could be?

many thanks for all the help,

Matt.


bool CBitmapOCR::WriteToFile(HBITMAP bmp, LPTSTR path)
{
	BITMAP WorkBmp;
	if(GetObject(bmp, sizeof(WorkBmp), &WorkBmp) == 0)
	{
		CString dwErr = ::GetLastError();
		logMsg(dwErr); //simply prints to a log file in error			
	}
 
	int paddedSize = WorkBmp.bmHeight * ( WorkBmp.bmWidth/8 + (4- (WorkBmp.bmWidth/8%4)));
 
	BITMAPFILEHEADER* bfh = (BITMAPFILEHEADER *) malloc(sizeof(BITMAPFILEHEADER));
	bfh->bfType='B'+('M'<<8); 
	bfh->bfOffBits= sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER) + 8; //offset to bitmap pixel data + 8 is for the two colour bytes
	bfh->bfSize= paddedSize + bfh->bfOffBits;
	bfh->bfReserved1=0; 
	bfh->bfReserved2=0; 
 
	//next the bitmap info
	BITMAPINFOHEADER* Bmi	= (BITMAPINFOHEADER *) malloc(sizeof(BITMAPINFOHEADER));
	Bmi->biSize				= sizeof(BITMAPINFOHEADER);
	Bmi->biWidth			= WorkBmp.bmWidth;
	Bmi->biHeight			= WorkBmp.bmHeight;
	Bmi->biPlanes			= 1;//WorkBmp.bmPlanes;
	Bmi->biBitCount			= 1;//WorkBmp.bmBitsPixel; 
	Bmi->biCompression		= BI_RGB;  //BI_RGB=0
	Bmi->biSizeImage		= paddedSize; //WorkBmp.bmHeight * WorkBmp.bmWidth /8; //should ust be ths as only one bit er pixel
	Bmi->biXPelsPerMeter	= 0;
	Bmi->biYPelsPerMeter	= 0;
	Bmi->biClrUsed			= 0;
	Bmi->biClrImportant		= 0;
		
	RGBQUAD colors[2];
    colors[0].rgbBlue = colors[0].rgbGreen = colors[0].rgbRed = 0;
    colors[1].rgbBlue = colors[1].rgbGreen = colors[1].rgbRed = 255;
    colors[0].rgbReserved = colors[1].rgbReserved = 0;
 
	BYTE* pBits = new BYTE[ paddedSize ];
	GetBitmapBits(bmp,WorkBmp.bmWidth * WorkBmp.bmHeight,pBits);
 
	FILE *p = fopen( path, "wb" );
    fwrite( bfh, sizeof(BITMAPFILEHEADER), 1, p );
    fwrite( Bmi, sizeof(BITMAPINFOHEADER), 1, p );
    fwrite( &colors[0],4, 1, p );
    fwrite( &colors[1],4, 1, p );
    fwrite( pBits,Bmi->biSizeImage, 1, p );
    fclose( p );
 
	return true;
}

Open in new window

hi matt,

the calculation of the padded rowsize does not work properly. if you put a width of 160 the result should be 20, but your formula gives 24

WorkBmp.bmWidth: 160

(WorkBmp.bmWidth/8 + (4- (WorkBmp.bmWidth/8%4))); -> result 24 but should be 20


ike
>>>> (4- (WorkBmp.bmWidth/8%4)));
You should add some more parantheses. I don't know in which order the operators / and % were evaluated. It maybe done in that way you expect it ... or not.

>>>> GetBitmapBits(bmp,WorkBmp.bmWidth * WorkBmp.bmHeight,pBits);
The GetBitmapBits will copy the bits of the colored bitmap to a buffer (pBits) which was sized for a monochrome bitmap. Note, when changing the Bmi struct  members you do not change any of the 'internal' resources associated to the 'bmp' handle. But that handle (and width and height) was the only info passed to the GetBitmapBits.

You should size the pBits buffer to bmWidth * bmHeight * sizeof(RGBQUAD) and get the colors for the colored bitmap. Then, you could evaluate the RGBQUAD items, and set the bits of a second buffer for the monochrome bitmap (sized to 'paddedSize') like the following:

      for (int i = 0; i < WorkBmp.bmWidth * WorkBmp.bmHeight; ++i)
      {
            RGBQUAD rgbq = *(((RGBQUAD*)pBits) + i);  // get ith item of RGBQUAD array
            // check color whether it should be black or white
            bool black =  (rgbq.rgbRed > 178 && ... );
            if (black)
            {
                  pMonoBits[i/8] |= 1<<(i%8);   // set corresponding bit
            }
      }

After that you could store the pMonoBits together with the bitmap header you already filled correctly.

Regards, Alex



Avatar of flynny

ASKER

Hi itsme and ikework

ikework, thanks for pointing that out i've replaced this  to the following now;

double bytesPerPixel = WorkBmp.bmBitsPixel/8.000;
int dActualWidth = (int) ((WorkBmp.bmWidth * bytesPerPixel) + 0.999f); //round up to narest byte

while(dActualWidth%4 != 0)
   dActualWidth++;

itsme, thanks for that. yes this is the approach trying to take however the problem i mentioned prviously is still happening. (I have noticed though that when i tested i on a 19 x 9 image it worked ok)

so i have my highlighting method working now the problem seems to be i'm not getting enough bitmap bits when trying to write to the file (i printing out the contents of the byte array before creatring the bitmap in the highlight method and this is correct.)

i've changed my GetBitmapBit cal to be

int paddedSize = WorkBmp.bmHeight * dActualWidth;

BYTE* pBits = new BYTE[paddedSize];
GetBitmapBits(bmp, paddedSize, pBits);

i create the HBITMAP bmp as follows

HBITMAP hbmMono = ::CreateBitmap((WORD)WorkBmp.bmWidth, (WORD)WorkBmp.bmHeight, 1, 1, pBmiSrc); //pBmiSrc is correct as i have printed the contents out

am i reading the incorrect amount of bytes?
Avatar of flynny

ASKER

hi guys,

i have noticed something strange, as an experiment, due to the fact it seemed to only be sending half the row, i tried the following

HBITMAP hbmMono = ::CreateBitmap((WORD)WorkBmp.bmWidth, (WORD)WorkBmp.bmHeight*2, 1, 1, pBmiSrc);

then when i was writing to the file i did the following

int paddedSize = WorkBmp.bmHeight/2 * dActualWidth;

set the BITMAPHEADERINFO bmHeight to be divided by 2 also. and this is working? why i dont know. any ideas?
>>>> when i tested i on a 19 x 9 image
Do you really need to have bitmaps with 'odd' width and height. If your sizes were a multiple of 8 (what is not much for a paper device), you can spare using doubles for calculating bits.

>>>> double bytesPerPixel = WorkBmp.bmBitsPixel/8.000;
the following is equivalent:

     int bytesPerPixel = (WorkBmp.bmBitsPixel + 7)/8;

It rounds up to the next multiple of 8.

>>>> int paddedSize = WorkBmp.bmHeight * dActualWidth;
That makes paddedSize the number of bytes in case the dActualWidth was calulated correctly. But I have doubts ...

>>>> double bytesPerPixel = WorkBmp.bmBitsPixel/8.000;
>>>> int dActualWidth = (int) ((WorkBmp.bmWidth * bytesPerPixel) + 0.999f); //round up to narest byte
>>>> while(dActualWidth%4 != 0)
>>>>   dActualWidth++;
That is bad code.

Take 'monochrome' bitmap where bmWidth = 19 and bytesPerPixel is 0.125. Then dActualWidth = 2 and will be padded up to 4.

Take RGB bitmap, where bmWidth = 19 and bytesPerPixel is 4. Then dActualWidth = 76 and was not padded up.

I don't know whether the results were that you expected but the following would give the same results.

   int iActualWidth = ((WorkBmp.bmBitsPixel * WorkBmp.bmWidth) + 7) / 8;
   iActualWidth += 4 - (iActualWidth%4);

>>>> am i reading the incorrect amount of bytes?
I have problems to see what is the source bitmap and what is the target bitmap. I assumed the passed bmp handle was the handle to a colored bitmap. If so, the GetBitmapBits will return (width * height) * bitsPerPixel  bits, which may be padded up to a multiple of 32 bits. Until here there is *not* the sligthest reason to mixup bits and bytes. If you rounded up to a multiple of 32 (once!), you easily can divide by 8 (no roundings) and get the number of bytes the buffer needs to be allocated (and what was returned by GetBitmapBits hopefully). The only variable which may make trouble in the above calculation is the bitsPerPixel as I can't say from your code that you 'retrieve' it somewhere. You would get the *correct* bitsPerPixel for a valid HBITMAP handle if you would call the GetDiBits function with a NULL argument for the lpBits. Then, GetDiBits only fills the BITMAPINFOHEADER structure where the biBitCount member gives the requested information. In your code I can't see how you retrieved the WorkBmp.bmBitsPixel  (I saw that you set bmi.biBitCount fix to 1)  but that is the essential part.

Can you give some samples where you tell waht you got for 'bmBitsPixel', width and height, paddedSize, and where you tell why you think, that the requested buffer doesn't get all bits. Note, you easily could check that by not creating a monochrome bitmap but creating a copy of the existing bitmap. If you don't get the correct number of bits, that copy would be incomplete. If that works ok, the issue is when you finally 'store' the bits of the monochrome bitmap (where I actually didn't see any code til now).


 
>>>> iActualWidth += 4 - (iActualWidth%4);
Correction:
      iActualWidth = (( iActualWidth + 3)/4) * 4;
Avatar of flynny

ASKER

hi its me thanks for your reply.

>>Do you really need to have bitmaps with 'odd' width and height. If your sizes were a multiple of 8 (what is not much for a paper device), you can spare using doubles for calculating bits.
potentially the bitmap could be any size so i will need to use doubles

>>     int bytesPerPixel = (WorkBmp.bmBitsPixel + 7)/8;
great thank for that.

>>That is bad code.
ok. i see. Just to check then because the reason i moved away from this way was due the tohe poiint the ikework made.

take iActualWidth = 4 (where the actual width is of modulo or 160 as in ikeworks example)
iActualWidth += 4 - (iActualWidth%4);
= 8

will i need to pad like this?

>>I have problems to see what is the source bitmap and what is the target bitmap.
sorry. basically i want to have a method HBITMAP highlightimage(HBITMAP, int,int,int) which will take a sent HBITMAP create a new highlighted monochrome image and then return it. so.. the passed HBITMAP will be the colour bitmap, and the returned HBITMAP will be the monochrome, highlighted one.

I then have another method BOOL WriteToFile(HBITMAP, path) which will write the sent HBITMAP to the specified path.

>>Can you give some samples where you tell waht you got for 'bmBitsPixel', width and height, paddedSize, and where you tell why you think, that the requested buffer doesn't get all bits.

ok, i'll do some test and post the results.

thanks again for all your help.
>>>> iActualWidth += 4 - (iActualWidth%4);
That was wrong. Look at my correction above.
Avatar of flynny

ASKER

hi its me sorry, maybe i'm reading it wrong but would this work?

>>>iActualWidth = (( iActualWidth + 3)/4) * 4;
e.g. for 4
4+3 = 7
and the division and multplying would cancel each other out?

>>>> and the division and multplying would cancel each other out?
No, it is an integer divison which would round to the next lower integer, so

  ((0 + 3)/4) * 4 = 0 * 4 = 0
  ((1 + 3)/4) * 4 = 1 * 4 = 4
  ((2 + 3)/4) * 4 = 1 * 4 = 4
  ((3 + 3)/4) * 4 = 1 * 4 = 4
  ((4 + 3)/4) * 4 = 1 * 4 = 4
  ((5 + 3)/4) * 4 = 2 * 4 = 8
  ((6 + 3)/4) * 4 = 2 * 4 = 8
  ((7 + 3)/4) * 4 = 2 * 4 = 8
  ((8 + 3)/4) * 4 = 2 * 4 = 8
  ((9 + 3)/4) * 4 = 3 * 4 = 12

the whole thing always rounds up to the next multiple of 4.


As told above you better should calculate the bits, round up to a  multiple of 32 and get the bytes then.

Microsoft samples do that by using the following macro:

// How wide, in bytes, would this many bits be, DWORD aligned?

#define WIDTHBYTES(bits)      ((((bits) + 31)>>5)<<2)


The above takes the number of bits, adds 31, divides by 32  (a right shift of 5 is the same as dividing by 2^5==32) and multiplies the result by 4 (a left-shift of 2 is the same as multiplying with 2^2 == 4).

Avatar of flynny

ASKER

sorry about that itsme, didnt see the integer division. i've been testing the method on 24bit bitmaps and (using paint) and it doesnt work for any bitmap i pass it. for example in the following bitmap

424D9A00000000000000360000002800000006000000050000000100180000000000640000000000000000000000000000000000000000000000000000000000000000FF0000FF000000FFFFFF00000000000000000000FF0000FF000000FFFFFFFFFFFF00000000000000FF0000FF000000FFFFFFFFFFFFFFFFFF00000000FF0000FF000000FFFFFFFFFFFFFFFFFFFFFFFF00FF0000FF000000

i get the following output from iterating through the byte array

ffffffffffffffffffffffff00ff0000ff00ffffffffffffffffff00000000ff0000ff00ffffffffffff00000000000000ff0000ff00ffffff00000000000000000000ff0000ff0000000000000000000000000000ff0000ff0000000000000000000000

i'll do some more tests on different bitmaps, but any ideas here?
HBITMAP CBitmapOCR::HighlightImage(HBITMAP hBmp, int rVal, int gVal, int bVal)
{
	BITMAP WorkBmp;
	if(GetObject(hBmp, sizeof(WorkBmp), &WorkBmp) == 0)
	{
		CString dwErr = ::GetLastError();
		logMsg(dwErr);			
	}
 
	//pad so multiple of 4
	int bytesPerPixel = ((WorkBmp.bmBitsPixel+7)/8);
	int dActualWidth = (( (WorkBmp.bmWidth * bytesPerPixel) + 3)/4) * 4;
 
	//calculate the mono bitmap width
	int dActualMonoWidth = (( (WorkBmp.bmWidth * 0.125) + 3)/4) * 4;	
	int paddedSize = WorkBmp.bmHeight * dActualMonoWidth;
	BYTE* pBmiSrc = new BYTE[ paddedSize ];
 
	BYTE* bmBits = (BYTE*)GlobalAlloc(GPTR,WorkBmp.bmWidthBytes*WorkBmp.bmHeight);
	GetBitmapBits(hBmp,dActualWidth*WorkBmp.bmHeight,bmBits);//was bmwidthbytes
 
	int x;
	for(x=0; x<dActualWidth*WorkBmp.bmHeight;x++)
	{ //simply logs out to file 
		ocrMsg.Format(":Original Byte:%x: count[%d]", 	bmBits[x],x);
		logMsg(ocrMsg);
	}

Open in new window

ASKER CERTIFIED SOLUTION
Avatar of itsmeandnobodyelse
itsmeandnobodyelse
Flag of Germany 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
Avatar of flynny

ASKER

hi itsme, thanks for the reply and your help you've been brilliant.

ok i will be wanting to process both 24 and 32 bit bitmap so i will have to make the method general rather than just for 32bit.

>>           (allBitsOfBitmap + 31) / 32
so to check, would to following work generically to calculate the actualwidht of a bitmap line?

(((width*bitsperpixel)+31)/32) * 4; // i.e. using th WIDTHBYTES macro?

so for a 5x5 bitmap for example

for 24bit;

(((5 * 24) + 31) /32) * 4 =  120 + 31 / 32 *4 = 151 /32 *4 = 4 * 4 = 16

for 32 bit

(((5 * 32) + 31) /32) * 4 =  160 + 31 / 32 *4 = 191 /32 *4 = 5 * 4 = 20








>>>> for 24bit;
>>>> (((5 * 24) + 31) /32) * 4 =  120 + 31 / 32 *4 = 151 /32 *4 = 4 * 4 = 16

>>>> for 32 bit
>>>> (((5 * 32) + 31) /32) * 4 =  160 + 31 / 32 *4 = 191 /32 *4 = 5 * 4 = 20

Yes, for 24 bits you have 3 bytes per pixel, so it is 15 bytes padded up to the next multiple of 4 --> 16

Yes, for 32 bits you have 4 bytes per pixel, so it is 20 bytes what is already a multiple of 4 --> 20
Avatar of flynny

ASKER

great thanks itsme, ok so now to access each individual pixel in the byte array i will need to do the following? . e.g. to just prin out each pixels rgb value

int bytesPerPixel = ((WorkBmp.bmBitsPixel+7)/8); //will give 4 for 32bit and 3 for 24bit
int dActualWidth = (((WorkBmp.bmWidth*WorkBmp.bmBitsPixel)+31)/32) * 4;

for(y=0;y<WorkBmp.bmHeight;y++)
{
      for(x=0;x<WorkBmp.bmWidth;x++)
      {
            r = *((BYTE*)WorkBmp.bmBits + (y * dActualWidth) + (x * bytesPerPixel) + 2);
            g = *((BYTE*)WorkBmp.bmBits + (y * dActualWidth) + (x * bytesPerPixel) + 1);
            b = *((BYTE*)WorkBmp.bmBits + (y * dActualWidth) + (x * bytesPerPixel) + 0);

            ocrMsg.Format("TEST [x%d,y%d] r%d,g%d,b%d",x,y,r,g,b); //basically just outputs text to log file
            logMsg(ocrMsg);
      }
}
SOLUTION
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
Avatar of flynny

ASKER

thanks for that itsme,

it working perfectly. ;)
Avatar of flynny

ASKER

Itsme broke the question down with detailed examples, helping to understand the process clearly and easiely. many thanks