Capturar ventana e imprimirla

Desde un programa C con interfaz gráfica en windows 2000, tengo que capturar la imagen de su ventana e imprimirla.
He investigado bastante el API de windows, y he conseguido, capturarla, escalarla para adaptarla a la resolución de la impresora e imprimirla.
Pero entonces se me plantea el problema de que cuando tengo el escritorio a 32 bits, a no ser que la ventana sea muy pequeña, me da error de memoria insuficiente para realizar la operación.
Intenté entonces enviarla a la impresora en bloques pequeños, no toda a la vez, y así, consigo que se imprima en casi todos los tamaños (pero no siempre). Además tarda mucho y con la CPU siempre al 100%. He probado distintos tamaños de bloque, pero nada.
Aquí te pongo el fragmento de código que me hace todo esto:
//************************************
lHDCImpresora = CreateDC( "WINSPOOL",lImpresora,NULL,NULL );
ResetDC( lHDCImpresora, lpDevMode ); //Antes he mostrado el diálogo de la impresora para editar sus opciones
//y se han guardado en la estructura 'lpDevMode'
GetWindowRect( dHWND,&lRect ); //Obtengo los vértices de la ventana
hdcScreen = GetWindowDC(dHWND); //Obtengo el DC de la ventana
hdcCompatible = CreateCompatibleDC(hdcScreen); //Creo un DC compatible para escalar la ventana
fScaleX = factor de escala en eje X para adaptar resolución de pantalla a resolución de impresora
fScaleY = factor de escala en eje Y para adaptar resolución de pantalla a resolución de impresora
ancho = ( lRect.right - lRect.left ); //Ancho de la ventana en pantalla
alto = ( lRect.bottom - lRect.top ); //Alto de la ventana en pantalla
nAncho = (int) ((float) ancho * fScaleX); //Ancho de la ventana en el papel
nAlto = (int) ((float) alto * fScaleY); //Alto de la ventana en el papel
hbmScreen = CreateCompatibleBitmap(hdcScreen,nAncho,nAlto); //Creamos un bitmap para contener la ventana escalada
if (hbmScreen == 0) { //Error }
if (!SelectObject(hdcCompatible, hbmScreen)) { //Error } //Seleccionamos el bitmap dentro del DC
ShowWindow(dHWND, SW_SHOW); //Mostramos la ventana a capturar (por si estaba escondida -en depuración-)
if ( !StretchBlt( hdcCompatible,
0, 0, nAncho, nAlto,
hdcScreen,
0,0, ancho, alto,
SRCCOPY) ) //Escalamos la imágen de la ventana
{
//Error
}
num = 0;
anchoBloque = 10; //Copiamos la imágen a la impresora, en bloques
altoBloque = nAlto;
for ( x = 0; x<xLeft+nAncho; x+=anchoBloque )
{
for ( y = 0; y<yTop+nAlto; y+=altoBloque )
{
if ( !BitBlt( lHDCImpresora,
x+xLeft, y+yTop, anchoBloque, altoBloque,
hdcCompatible,
x,y,
SRCCOPY) )
{
}
}
}
DeleteObject(hbmScreen); //Eliminamos los objetos creados.
DeleteDC(hdcCompatible);
DeleteDC(hdcScreen);
//************************************
Mi pregunta es:
¿Qué tengo que hacer para que esta operación no sea tan costosa?
¿Hay alguna otra forma de hacerlo, más económica (en recursos, claro)?
Tiene que haberla, porque si capturas el escritorio con la tecla 'Impr Pant', lo pegas en el 'paint' y lo imprimes, va como un tiro y no consume casi CPU.
Bueno, esto es todo, cualquier ayuda será bien recibida.

1 Respuesta

Respuesta
1
Prueba este código que a mi no me consume tanta memoria como te pasa a ti:
/**********************************************************/
BITMAPINFO bmi; // used to define the bitmap-format we want to create
BITMAPFILEHEADER bfh; // used to define the BMP-file-format
HBITMAP hbm=0; // handle to the newly created bitmap
HBITMAP ohbm;
HDC hdc=0; // screen-DC to take image from
HDC mhdc=0; // screen-compatible DC for the new bitmap
BYTE *imagedata;
HDC phdc=0; // the printer-DC
int width = 0, height = 0;
hdc = ::GetDC(0); // get screen DC
GetWindowRect( dHWND,&lRect ); //Obtengo los vértices de la ventana
width = ( lRect.right - lRect.left ); //Ancho de la ventana en pantalla
height = ( lRect.bottom - lRect.top ); //Alto de la ventana en pantalla
// now let's prepare the bitmap-format
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); // the size helps to distinguish between different versions
bmi.bmiHeader.biWidth = width;
bmi.bmiHeader.biHeight = height;
bmi.bmiHeader.biPlanes = 1; // has to be 1
bmi.bmiHeader.biBitCount = 24; // as we want true-color
bmi.bmiHeader.biCompression = BI_RGB; // no compression
bmi.bmiHeader.biSizeImage = (((width * 24 + 31) & ~31) >> 3) * height; // lines have to be DWORD aligned
bmi.bmiHeader.biXPelsPerMeter = 0;
bmi.bmiHeader.biYPelsPerMeter = 0; // could be used to describe physical dimension
bmi.bmiHeader.biClrImportant = 0;
bmi.bmiHeader.biClrUsed = 0; // we are not using palette
// enough information to create a DIBSECTION in memory
hbm = ::CreateDIBSection(hdc,&bmi,DIB_RGB_COLORS,(void**)&imagedata,0,0);
mhdc = ::CreateCompatibleDC(hdc); // create a screen-compatible DC
ohbm = (HBITMAP)::SelectObject(mhdc,hbm); // select the new bitmap into the compatible DC
::BitBlt(mhdc, 0,0, width, height, hdc, 52,95, SRCCOPY); // copy the screen-image into the bitmap
::SelectObject(mhdc,ohbm); ::DeleteDC(mhdc); mhdc = 0; // the compatible DC is no longer needed
CPrintDialog prtdlg(FALSE);
DOCINFO di={0};
CSize ppix; // printer-page size in pixel
CSize pmm; // printer-page size in mm
int pwidth,pheight;
if ( prtdlg.DoModal() == IDOK ) // let the user select printer + settings
{
phdc = prtdlg.GetPrinterDC(); // get the printer-DC
ppix.cx = GetDeviceCaps(phdc,HORZRES);
ppix.cy = GetDeviceCaps(phdc,VERTRES); // get page-size in pixel
pmm.cx = GetDeviceCaps(phdc,HORZSIZE);
pmm.cy = GetDeviceCaps(phdc,VERTSIZE); // get page-size in mm
pwidth = 150 * ppix.cx / pmm.cx;
pheight = height * pwidth / width; // match height to image-aspect
// now prepare the print-job
di.cbSize = sizeof(DOCINFO);
di.lpszDocName = "Gráfica";
StartDoc(phdc,&di);
StartPage(phdc); // only one page needed
// stretch the image to the printer-DC
StretchDIBits(phdc,250,500,pwidth,pheight,0,0,width,height,imagedata,&bmi,DIB_RGB_COLORS,SRCCOPY);
EndPage(phdc);
EndDoc(phdc);
}
/**********************************************************/
Cuentame que tal te ha ido.
Muchas gracias!
Esto va como un tiro!
En fin, es lo que quería, mis sospechas giraban entorno a los DIB, pero no sabía justo cómo utilizarlos.
Olvidé decirte que solamente podía utilizar C, nada de C++, con lo que tuve que modificar el código que me indicaste (pero solamente para adaptarlo).
Bien, mi problema está resuelto.
De nuevo, muchas gracias.
Un saludo.

Añade tu respuesta

Haz clic para o

Más respuestas relacionadas