yuxiliu
asked on
DIB Resizing by VC/Win32 API
I need to resize a DIB bitmap(not DDB!), and I have load DIB to memory and got the DIB handle and memory block, now I need to resize it in memory, For example, I have a DIB size is 100*100, then I want to change the size of it to 20*20, (not put to screen, I just need a new DIB handle which handle a 20*20 size DIB). I do this in Win98SE/VC++. Could you give me some tips? Thanks a lot!
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
I have try your code, and the size now is OK but I can't see the picture inside. I think I give it a wrong imagesize. So, Could you tell me how to caculate image size? Befor I still not alloc memory for a new DIB image.
Thank you very much!
I need a 24bits
Thank you very much!
I need a 24bits
ASKER
I have try your code, and the size now is OK but I can't see the picture inside. I think I give it a wrong imagesize. So, Could you tell me how to caculate image size? Befor I still not alloc memory for a new DIB image.
Thank you very much!
I need a 24bits
Thank you very much!
I need a 24bits
>> Could you tell me how to caculate image size?
Do you mean the actual size, like width and height? I can't help you there, that depends on what you need. Or do you mean the size in bytes for the pixel data? That depends on the format you are using? do you know what format you are using?
duh. 24bits. I missed that.
You would think it is the number of pixels times the number of bytes used to store a pixel (3 bytes in this case). But that is not right, although it is close. The problem is that the length of a single row of pxiels must be padded so it is a multiple of 4 bytes. so for example, if you image was only 1 pixel wide, you would need 3 bytes in a row, but the row has to be padded to a multiple of 4, so you actually have to have 4 bytes per row. Okay? so you would do something like
int RowSize = Width*3
RowSiz += 3; // Add 3 to force the divide to round up.
RowSiz /= 4; // Calculate number of multiples of 4.
RowSiz *= 4; // Calculate size.
int ImageSize = RowSiz*Height;
okay?
Do you mean the actual size, like width and height? I can't help you there, that depends on what you need. Or do you mean the size in bytes for the pixel data? That depends on the format you are using? do you know what format you are using?
duh. 24bits. I missed that.
You would think it is the number of pixels times the number of bytes used to store a pixel (3 bytes in this case). But that is not right, although it is close. The problem is that the length of a single row of pxiels must be padded so it is a multiple of 4 bytes. so for example, if you image was only 1 pixel wide, you would need 3 bytes in a row, but the row has to be padded to a multiple of 4, so you actually have to have 4 bytes per row. Okay? so you would do something like
int RowSize = Width*3
RowSiz += 3; // Add 3 to force the divide to round up.
RowSiz /= 4; // Calculate number of multiples of 4.
RowSiz *= 4; // Calculate size.
int ImageSize = RowSiz*Height;
okay?
ASKER
It still not works, StretchDIBits() successful and return the number of scanlines, but GetDIBits() allways return 0, I try to use GetLastError(), it return 0(ERROR_SUCCESS);
why? Could you give me more tips?
why? Could you give me more tips?
Post your code.
ASKER
These codes almost work now, some how, it still have some problem I don't know.
The color is not right, and some picture will have a offset on x or y direction, but some display good.
Is there still some problem with these code?
//Get hdc for painting
CDC* pDC = (GetDlgItem(IDC_DISPLAY_PA NE))->GetD C();
HDC hdc = pDC->GetSafeHdc();
//Source DIB
BITMAPINFO* pSrcBmpInfo;
BITMAPINFOHEADER* pSrcBmpInfoHeader;
BYTE* pSrcBits;
long lSrcWidth, lSrcHeight;
pSrcBmpInfo = (LPBITMAPINFO)GlobalLock(h DIB);
pSrcBmpInfoHeader = (LPBITMAPINFOHEADER)pSrcBm pInfo;
pSrcBits = (BYTE*)pSrcBmpInfo + sizeof(BITMAPINFOHEADER);
lSrcWidth = pSrcBmpInfoHeader->biWidth ;
lSrcHeight = pSrcBmpInfoHeader->biHeigh t;
//Destination DIB
BITMAPINFO* pDstBmpInfo;
BITMAPINFOHEADER* pDstBmpInfoHeader;
BYTE* pDstBits;
long lDstWidth, lDstHeight;
long lDstImageSize;
lDstHeight = 400; //The size I want
lDstWidth = 600;
lDstImageSize = ((((lDstWidth * 24) + 31)& ~31) >> 3) * lDstHeight; //I Get From MSDN
pDstBmpInfo = (LPBITMAPINFO)GlobalAlloc( GMEM_FIXED | GMEM_ZEROINIT, lDstImageSize+sizeof(BITMA PINFO));
pDstBmpInfoHeader = (LPBITMAPINFOHEADER)pDstBm pInfo;
pDstBits =(BYTE*) pDstBmpInfo + sizeof(BITMAPINFOHEADER);
//Before filling in Dst DIB info header copy palette
memcpy(pDstBmpInfo, pSrcBmpInfo,sizeof(BITMAPI NFOHEADER) );
//Fill in Dst DIB info header
pDstBmpInfoHeader->biHeigh t = lDstHeight;
pDstBmpInfoHeader->biWidth = lDstWidth;
pDstBmpInfoHeader->biBitCo unt = 24;
/*
pDstBmpInfoHeader->biSize = sizeof(BITMAPINFO);
pDstBmpInfoHeader->biSizeI mage = lDstImageSize;
pDstBmpInfoHeader->biXPels PerMeter = 0;
pDstBmpInfoHeader->biYPels PerMeter = 0;
pDstBmpInfoHeader->biCompr ession = BI_RGB;
pDstBmpInfoHeader->biPlane s = 1;
*/
//Prepare for resize
HDC hdcMem;
HBITMAP hbmMem, hbmOld, bmp;
//bmp = ::CreateBitmap(lDstWidth, lDstHeight,1,24,NULL);
hdcMem = CreateCompatibleDC(hdc); //Create a memory DC
hbmMem = CreateCompatibleBitmap(hdc , lDstWidth, lDstHeight); //Create a memory Bitmap
hbmOld = (HBITMAP)SelectObject(hdcM em, hbmMem); //I think after this, all operation on hdcMem will put into hbmMem, am I right?
//Stretch Src DIB to memory Bmp, Successful here I get return scan lines
int ret = StretchDIBits(hdcMem, 0, 0, lDstWidth, lDstHeight, 0, 0, lSrcWidth, lSrcHeight, pSrcBits, pSrcBmpInfo, DIB_RGB_COLORS, SRCCOPY);
//Get Bits from memory bitmap
int x = GetDIBits(hdcMem, hbmMem, 0, lDstHeight, NULL, pDstBmpInfo, DIB_RGB_COLORS);
x = GetDIBits(hdcMem, hbmMem, 0, lDstHeight, pDstBits, pDstBmpInfo, DIB_RGB_COLORS);
int err = GetLastError();
//Display to screen for testing
x = ::SetDIBitsToDevice(
hdc, // handle to device context
0, // x-coordinate of upper-left corner of dest. rect.
0, // y-coordinate of upper-left corner of dest. rect.
lDstWidth, // source rectangle width
lDstHeight, // source rectangle height
0, // x-coordinate of lower-left corner of source rect.
0, // y-coordinate of lower-left corner of source rect.
0, // first scan line in array
lDstHeight, // number of scan lines
pDstBits, // address of array with DIB bits
pDstBmpInfo, // address of structure with bitmap info.
DIB_RGB_COLORS // RGB or palette indexes
);
GlobalUnlock(hDIB);
GlobalFree(pDstBmpInfo);
The color is not right, and some picture will have a offset on x or y direction, but some display good.
Is there still some problem with these code?
//Get hdc for painting
CDC* pDC = (GetDlgItem(IDC_DISPLAY_PA
HDC hdc = pDC->GetSafeHdc();
//Source DIB
BITMAPINFO* pSrcBmpInfo;
BITMAPINFOHEADER* pSrcBmpInfoHeader;
BYTE* pSrcBits;
long lSrcWidth, lSrcHeight;
pSrcBmpInfo = (LPBITMAPINFO)GlobalLock(h
pSrcBmpInfoHeader = (LPBITMAPINFOHEADER)pSrcBm
pSrcBits = (BYTE*)pSrcBmpInfo + sizeof(BITMAPINFOHEADER);
lSrcWidth = pSrcBmpInfoHeader->biWidth
lSrcHeight = pSrcBmpInfoHeader->biHeigh
//Destination DIB
BITMAPINFO* pDstBmpInfo;
BITMAPINFOHEADER* pDstBmpInfoHeader;
BYTE* pDstBits;
long lDstWidth, lDstHeight;
long lDstImageSize;
lDstHeight = 400; //The size I want
lDstWidth = 600;
lDstImageSize = ((((lDstWidth * 24) + 31)& ~31) >> 3) * lDstHeight; //I Get From MSDN
pDstBmpInfo = (LPBITMAPINFO)GlobalAlloc(
pDstBmpInfoHeader = (LPBITMAPINFOHEADER)pDstBm
pDstBits =(BYTE*) pDstBmpInfo + sizeof(BITMAPINFOHEADER);
//Before filling in Dst DIB info header copy palette
memcpy(pDstBmpInfo, pSrcBmpInfo,sizeof(BITMAPI
//Fill in Dst DIB info header
pDstBmpInfoHeader->biHeigh
pDstBmpInfoHeader->biWidth
pDstBmpInfoHeader->biBitCo
/*
pDstBmpInfoHeader->biSize = sizeof(BITMAPINFO);
pDstBmpInfoHeader->biSizeI
pDstBmpInfoHeader->biXPels
pDstBmpInfoHeader->biYPels
pDstBmpInfoHeader->biCompr
pDstBmpInfoHeader->biPlane
*/
//Prepare for resize
HDC hdcMem;
HBITMAP hbmMem, hbmOld, bmp;
//bmp = ::CreateBitmap(lDstWidth, lDstHeight,1,24,NULL);
hdcMem = CreateCompatibleDC(hdc); //Create a memory DC
hbmMem = CreateCompatibleBitmap(hdc
hbmOld = (HBITMAP)SelectObject(hdcM
//Stretch Src DIB to memory Bmp, Successful here I get return scan lines
int ret = StretchDIBits(hdcMem, 0, 0, lDstWidth, lDstHeight, 0, 0, lSrcWidth, lSrcHeight, pSrcBits, pSrcBmpInfo, DIB_RGB_COLORS, SRCCOPY);
//Get Bits from memory bitmap
int x = GetDIBits(hdcMem, hbmMem, 0, lDstHeight, NULL, pDstBmpInfo, DIB_RGB_COLORS);
x = GetDIBits(hdcMem, hbmMem, 0, lDstHeight, pDstBits, pDstBmpInfo, DIB_RGB_COLORS);
int err = GetLastError();
//Display to screen for testing
x = ::SetDIBitsToDevice(
hdc, // handle to device context
0, // x-coordinate of upper-left corner of dest. rect.
0, // y-coordinate of upper-left corner of dest. rect.
lDstWidth, // source rectangle width
lDstHeight, // source rectangle height
0, // x-coordinate of lower-left corner of source rect.
0, // y-coordinate of lower-left corner of source rect.
0, // first scan line in array
lDstHeight, // number of scan lines
pDstBits, // address of array with DIB bits
pDstBmpInfo, // address of structure with bitmap info.
DIB_RGB_COLORS // RGB or palette indexes
);
GlobalUnlock(hDIB);
GlobalFree(pDstBmpInfo);
At the moment, I don't see anything wrong,b ut you are not clearning up at all, at least not int he portion of the code you posted. You must seelcte the original bitmap back into the memory DC and you must delete the memory DC and bitmap. That is very important!
What is hDIB? how did you get it?
You say the colors are off, did you check the pixel data for the source bitmap to make sure that you are getting the right colors there? If you are getting a pointer to the source pixel data incorrectly, then everythign after that will be wrong (could cause a shift in the image, could cause bad colors.)
What is hDIB? how did you get it?
You say the colors are off, did you check the pixel data for the source bitmap to make sure that you are getting the right colors there? If you are getting a pointer to the source pixel data incorrectly, then everythign after that will be wrong (could cause a shift in the image, could cause bad colors.)
int DstHgt = ?; // destination height.
int SrcWdt = ?; // source width.
int SrcHgt = ?; // source height.
void *SrcBitPtr = ?; // -> source bits;
void *DstBitPtr = ?; // -> dest bits;
BITMAPINFO SrcBmpInf = ?; // Source bitmap format.
BITMAPINFO DstBmpInf; // destination bitmap format
// This is probably sufficient to set DstbmpInf for your needs.
// if the image size isn't being set to 0 (for a uncompressed RGB bitmap)
// then you will also need to set the size.
DstbmpInf = SrcBmpInf;
DstBmpInf.bmiHeader.biWidt
DstBmpInf.bmiHeader.biHeig
HDC MemDC = CreateCompatibleDC(NULL);
HBITMAP BmpHnd = CreateBitmap(DstWdt,DstHgt
HBITMAP OldBmp = SelectObject(MemDC,BmpHnd)
StretchDIBits(MemDC,0,0,Ds
GetDIBits(MemDC,BmpHnd,0,0
SelectObject(MemDC,OldBmp)
DeleteObject(BmpHnd);
DeleteDC(MemDC);
Let me know if you have any questions.