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.
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 de tadeor
1