|
-
January 10th, 2007, 06:42 AM
#1
Obtaining HBitmap from HDC
Hello all,
I'm trying to resize the image of a CStatic to the size of the CStatic itself, because usually the CStatic resizes automatically to the size of the picture, and I want just the opposite. For that purpose, I have tried to use the CDC function StretchBlt to resize the containing HBITMAP from the original size to the size of the CStatic.
This works well but when trying to obtain the HBITMAP from the resized CDC i just get a black image but with the correct size.
Code:
void WriteBmp(char* name,int W,int H,int Bpp,int* data)
{
BITMAPINFO Bmi={0};
Bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
Bmi.bmiHeader.biWidth = W;
Bmi.bmiHeader.biHeight = H;
Bmi.bmiHeader.biPlanes = 1;
Bmi.bmiHeader.biBitCount = Bpp;
Bmi.bmiHeader.biCompression = BI_RGB;
Bmi.bmiHeader.biSizeImage = W*H*Bpp/8;
FILE* image = fopen (name,"wb");
if(image==0)
return;
int h = abs(Bmi.bmiHeader.biHeight);
int w = abs(Bmi.bmiHeader.biWidth);
Bmi.bmiHeader.biHeight=-h;
Bmi.bmiHeader.biWidth=w;
int sz = Bmi.bmiHeader.biSizeImage;
BITMAPFILEHEADER bfh;
bfh.bfType=('M'<<8)+'B';
bfh.bfOffBits=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER);
bfh.bfSize=sz+bfh.bfOffBits;
bfh.bfReserved1=0;
bfh.bfReserved2=0;
fwrite(&bfh,sizeof(bfh),1,image);
fwrite(&Bmi.bmiHeader,sizeof(BITMAPINFOHEADER),1,image);
fwrite(data,sz,1,image);
fclose(image);
}
int GuardarHBITMAPenFichero(HBITMAP hbmp,CString nombreFichero)
{
/// Save HBITMAP in the file nombreFichero
BITMAP bm;
GetObject(hbmp,sizeof(BITMAP),&bm);
int Bps = bm.bmBitsPixel;
int Width = bm.bmWidth;
int Height = bm.bmHeight;
int size = Bps/8 * ( Width * Height );
BYTE *lpBits = new BYTE[size];
BITMAPINFOHEADER bInfoHeader;
BITMAPINFO bInfo;
::ZeroMemory(&bInfoHeader,sizeof(BITMAPINFOHEADER));
bInfoHeader.biSize = sizeof(BITMAPINFOHEADER);
bInfoHeader.biWidth = Width;
bInfoHeader.biHeight = -Height;// si negativo origen en la parte superior izquierda, si positivo en la parte inferior izquierda
bInfoHeader.biPlanes = 1;
bInfoHeader.biBitCount = 24 /*bit per pixel 24,32 */ ;
bInfoHeader.biCompression = 0; //RGB
bInfoHeader.biSizeImage = bInfoHeader.biWidth*bInfoHeader.biHeight*bInfoHeader.biBitCount/8;
bInfo.bmiHeader=bInfoHeader;
HDC memDC = ::GetDC(0);
HBITMAP OldBM = (HBITMAP)::SelectObject(memDC, hbmp );
::GetDIBits(
memDC, // manipulador de contexto de dispositivo
hbmp, // manipulador de mapa de bits
0, // primera l*nea a colocar en el mapa de bits de destino
Height, // número de l*neas a copiar
lpBits, // dirección del array de bits del mapa de bits
&bInfo, // dirección de estructura con datos del mapa de bits
DIB_RGB_COLORS // RGB o *ndices de paleta
);
// lpbits es un puntero a byte a la ventana que quieres capturar
WriteBmp((char*)(LPCSTR)nombreFichero,Width,Height,24,(int*)lpBits);
delete [] lpBits;
::DeleteDC(memDC);
return 0;
}
HBITMAP Asignar(CStatic *panel,HBITMAP imagen)
{
/// This function draws the HBITMAP in the panel with the size of the panel
RECT r;
BITMAP bm;
GetObject(imagen,sizeof(BITMAP),&bm);
int Width = bm.bmWidth; // width of the original image
int Height = bm.bmHeight; // height of the original image
HBITMAP hResized_image;
panel->GetWindowRect(&r); // size of the panel where we'll draw the image
panel->ScreenToClient(&r);
HDC panel_hdc;
panel_hdc=panel->GetDC()->GetSafeHdc(); // HDC of the panel
HDC DCOrigen = ::CreateCompatibleDC ( panel_hdc ); // We create a compatible HDC to draw the image in, this DCs' dimensions will be the image's ones.
::SelectObject(DCOrigen,imagen); //We select the image into the HDC DCOrigen
/// here the image is resized
StretchBlt(
panel_hdc, // manipulador del contexto de dispositivo de destino
0, // coordenada x de la esquina superior izquierda del rectángulo de destino
0, // coordenada y de la esquina superior izquierda del rectángulo de destino
r.right-r.left, // anchura del rectángulo de destino
r.bottom-r.top, // altura del rectángulo de destino
DCOrigen, // manipulador del contexto de dispositivo de origen
0, // coordenada x de la esquina superior izquierda del rectángulo de origen
0, // coordenada y de la esquina superior izquierda del rectángulo de origen
Width , // anchura del rectángulo de origen
Height, // altura del rectángulo de origen
SRCCOPY // código de operación de rastreo
);
// I'm trying to get the HBITMAP of the resized HDC
hResized_image=(HBITMAP)::GetCurrentObject(panel_hdc, // handle to DC
// OBJ_BITMAP // object type
// );
/// Save into a file , save a black image
GuardarHBITMAPenFichero(hResized_image,"c:\\resized_HBITMAP.bmp");
/////
// Free resources ...
/////
return resized_image;
}
The problem is that i haven't been able to get the correct HBITMAP of the resized HDC , when i save it in a file the result is a black image. Why doesn't this work? is there another way that works to get the HBITMAP from a HDC?
Last edited by Marc G; January 11th, 2007 at 01:10 PM.
Reason: Added code tags
-
January 10th, 2007, 10:13 AM
#2
Re: Obtaining HBitmap from HDC
You must select a bitmap into the DC before calling StretchBlt.
1. Create a new DC compatible with panel_hdc. (CreateCompatibleDC)
2. Create a bitmap compatible with panel_hdc. (CreateCompatibleBitmap)
3. Select this bitmap into the new DC.
4. Do a StretchBlt of DCOrigen onto the new DC. (this will draw on your bitmap)
5. Do a BitBlt the of the new DC onto panel_dc. (this will copy the resized bitmap to screen)
If any problems, read here:
http://www.codeguru.com/forum/showthread.php?t=410645
Nobody cares how it works as long as it works
-
January 10th, 2007, 11:05 AM
#3
Re: Obtaining HBitmap from HDC
Thanks a lot. I have added the Bitblt and the new HDC and finally i have obtained the HBITMAP for the CStatic::SetBitmap function, so the refresh works well.
Code:
HBITMAP Asignar(CStatic *panel,HBITMAP imagen)
{
// Draw a HBITMAP into a CStatic
RECT r;
BITMAP bm;
GetObject(imagen,sizeof(BITMAP),&bm);
int Bps = bm.bmBitsPixel;
int Width = bm.bmWidth;
int Height = bm.bmHeight;
HBITMAP hResized_image;
panel->GetWindowRect(&r);
panel->ScreenToClient(&r);
HDC panel_hdc;
panel_hdc=panel->GetDC()->GetSafeHdc();
HDC DCOrigen = ::CreateCompatibleDC ( panel_hdc ); // DC for the image with the original size
HBITMAP hbitmap_anterior=(HBITMAP)::SelectObject(DCOrigen,imagen);
HDC hDC_new = ::CreateCompatibleDC ( panel_hdc );
hImagen_escalada = ::CreateCompatibleBitmap ( panel_hdc, r.right-r.left, r.bottom-r.top );
HGDIOBJ hOld = SelectObject(hDC_new, hResized_image);
StretchBlt(
hDC_new, // manipulador del contexto de dispositivo de destino
0, // coordenada x de la esquina superior izquierda del rectángulo de destino
0, // coordenada y de la esquina superior izquierda del rectángulo de destino
r.right-r.left, // anchura del rectángulo de destino
r.bottom-r.top, // altura del rectángulo de destino
DCOrigen, // manipulador del contexto de dispositivo de origen
0, // coordenada x de la esquina superior izquierda del rectángulo de origen
0, // coordenada y de la esquina superior izquierda del rectángulo de origen
Width , // anchura del rectángulo de origen
Height, // altura del rectángulo de origen
SRCCOPY // código de operación de rastreo
);
BitBlt(panel_hdc, 0, 0, r.right - r.left, r.bottom - r.top,hDC_new, 0, 0, SRCCOPY);
hResized_image= (HBITMAP)::SelectObject(hDC_new, hOld);
panel->SetBitmap(hResized_image); // it manage the image to be refreshed
::SelectObject(DCOrigen, hbitmap_anterior);
::DeleteDC(DCOrigen); // Destructora para CreateCompatibleDC
return hResized_image;
}
Only two more questions, why is neccesary other HDC? Is Bitblt really neccesary if i use SetBitmap? Well, thank you again :-) as i have said already works.
Last edited by Marc G; January 11th, 2007 at 01:10 PM.
Reason: Added code tags
-
January 10th, 2007, 11:26 AM
#4
Re: Obtaining HBitmap from HDC
 Originally Posted by Andonic
Thanks a lot. I have added the Bitblt and the new HDC and finally i have obtained the HBITMAP for the CStatic::SetBitmap function, so the refresh works well.
Only two more questions, why is neccesary other HDC? Is Bitblt really neccesary if i use SetBitmap? Well, thank you again :-) as i have said already works.
A DC obtained using GetDC() is a so called "window DC" because it draws directly onto a window. You should not select a bitmap into a window DC.
Instead you create a compatible DC. It will be called a "memory DC" after you have selected the bitmap into it because it then draws onto memory.
If your only goal is to obtain a bitmap for use with SetBitmap, BitBlt is not necessary. I got the impression that the bitmap should be drawn onto screen as well.
Nobody cares how it works as long as it works
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|