Question for Bitmap Decoding
Hi, I am trying to get the pixel info from a bitmap file but encountered some difficulties. The ones that I am trying is a monochrome (biBitCount == 1) and their header info are as follows:
Test File ----------- (1) ----------- (2) --------- (3) ---------- (4) --------- (5) -------- (6)
info got from bitmap header:
bmWidth ---------- 84 ---------- 168 -------- 252 --------- 335 -------- 419 ------- 586
bmHeight -------- 606 -------- 1211 ------ 1817 -------- 2422 ------- 3028 ----- 4239
bmWidthBytes --- 12 ----------- 24 ---------- 32 ----------- 44 ---------- 56 -------- 76
==========================================================
# bytes to get --- 12 ----------- 22 ---------- 32 ----------- 42 ---------- 54 ------- 74
I know that Each line in the array of data for the bitmap must be LONG aligned (divisible by 4 bytes).
Since I was decoding row by row, if taking the number of bytes specified as "bmWidthBytes" in the header for the entire row, and encoded the bit of each byte for the pixels (1 => white, 0 => black), only test file (1) and (3) got the image right, others would get a skewed result and some info missing at the bottom of image. This makes me think more bytes have been taken than necessary, which belong to the next row of image.
If taking the number of bytes as "# bytes to get", then everything was OK. I got these with trial and error!
Does any one see what is wrong and how to figure out the right number of bytes to take for the entire row? Thanks for any help in advance.
Raymond
Re: Question for Bitmap Decoding
The bmWidthBytes values are the correct.
I think the problem is in your processing code.
Re: Question for Bitmap Decoding
Quote:
Originally quoted by rayq
I know that Each line in the array of data for the bitmap must be LONG aligned (divisible by 32).
The number of bytes in each line in the bitmap must be evenly divisible by 4, if it isn't windows will pad the the line with either 1, 2 or 3 bytes to make it evenly divisible by 4.
In the bitmap file header, the width is bytes 18 through 21 and the height is bytes 22 through 25. You have to take the bytes and create an unsigned long value to get the numbers. This can be done easily with the MAKEWORD and MAKELONG macros. The total size of the header is 54 bytes.
One final note, the first line in the bitmap is the last line in the file.
Hope that helps
Re: Question for Bitmap Decoding
Thanks for your replies!
I don't see (or can't see) anything wrong with my code :confused: . below is what I wrote to deal with monochrome bitmap:
{:
CBitmap bitmap;
bitmap.Attach(hBmp);
// get info from bitmap file hdr.DIBSECTION ds;
bitmap.GetObject(sizeof(ds), &ds);
int width = ds.dsBmih.biWidth;
int height = ds.dsBmih.biHeight;
long imgSiz = ds.dsBmih.biSizeImage;
BYTE *bmBits = new BYTE[imgSiz]; // To store bitmap pixels.
// get bm bits from bitmap.
bitmap->GetBitmapBits(imgSiz, bmBits);
// to store indices to cgm color table
USHORT *cellarray = new USHORT[width * height];
int numwidthbytes = ds.dsBm.bmWidthBytes;
// to store pixels of whole row
BYTE *widthbyte = new BYTE[numwidthbytes];
int row, col, cntr;
for (row = 0, cntr = 0; row < height; row++)
{
// copy entire row bytes
memcpy(widthbyte, &bmBits[row * 22], 22); // ***
for (col = 0; col < width; col++)
cellarray[cntr++] = set_Pixels(widthbyte[col / 8], col);
}
:
:
delete [] widthbyte;
delete [] cellarray;
delete [] bmBits;
}
// Decode bit info for exported pixel
USHORT CgsCGMFile::set_Pixels(const BYTE bmbyte, const int col)
{
int bitpos = (col + 1) % 8;
USHORT pixel = 0; // set to black
switch (bitpos) // order from left to right
{
case 1: // 1xxx xxxx
if (bmbyte & 0x80)
pixel = 1; // set to white
break;
case 2: // x1xx xxxx
if (bmbyte & 0x40)
pixel = 1; // set to white
break;
case 3: // xx1x xxxx
if (bmbyte & 0x20)
pixel = 1; // set to white
break;
case 4: // xxx1 xxxx
if (bmbyte & 0x10)
pixel = 1; // set to white
break;
case 5: // xxxx 1xxx
if (bmbyte & 0x08)
pixel = 1; // set to white
break;
case 6: // xxxx x1xx
if (bmbyte & 0x04)
pixel = 1; // set to white
break;
case 7: // xxxx xx1x
if (bmbyte & 0x02)
pixel = 1; // set to white
break;
case 0: // xxxx xxx1
if (bmbyte & 0x01)
pixel = 1; // set to white
break;
default:
break;
}
return pixel;
}
What I am working on is to convert bitmap to CGM format with cgmcell_array(). The array "cellarray" is to store pixel information for use in "cgmcell_array" function. The problem happened in the line (with comment // ***) inside the for loop. Note that I used "22" (for test (2)) not "numwidthbytes" (= ds.dsBm.bmWidthBytes) or "24" to get the correct result.
Thanks for any help in advance.
Raymond