Regiones GDI+ en VB.NET

Capturar la ventana completa, con o sin decoración, o una región que se corresponde con un control PictureBox, usando GDI+ en Visual Basic .NET

Aprovechando mi anterior artículo sobre un control PictureBox redondeado continuaré trabajando con GDI (Graphics Device Interface). GDI es es uno de los tres componentes de la interfaz de usuario de Microsoft Windows. Trabaja junto con el núcleo y la API de Windows. Estas son las imágenes capturadas tal como se muestran en el documento HTML:

Como dice Arbis Percy Reyes en uno de sus artículos:

GDI+ es una interfaz de programación de aplicaciones (API) que se expone a través de un conjunto de clases implementadas como código administrado. GDI+ viene a ser la interfaz de dispositivo gráfico que se encarga de mostrar información en pantallas e impresoras, la cual nos permite a nosotros, como programadores de aplicaciones, mostrar información en una pantalla o impresora sin tener que preocuparnos por los detalles de un dispositivo de presentación específico, es decir, cuando desarrollemos aplicaciones usando los métodos suministrados por las clases de GDI+, no tendremos que preocuparnos por el hardware gráfico, ya que todo este trabajo lo harán los métodos GDI+ llamando a los controladores de dispositivo específicos, de esta manera GDI+ separa la aplicación del hardware gráfico, y esta separación es la que nos permite crear aplicaciones independientes del dispositivo. Ahora podemos decir con seguridad que GDI+ es una interfaz de dispositivo gráfico que permite a los programadores escribir aplicaciones independientes del dispositivo.”

Retomando el ejercicio del control PictureBox redondeado se añade la funcionalidad de captura de pantalla usando métodos de las clases de GDI+, explicando cómo hacer para capturar la ventana de la aplicación, con o sin decoración (bordes, barras de herramientas, de menús y de scroll, etc.) o una región específica de la ventana, la del control PictureBox, y guardar el resultado como una imagen JPG en el directorio del ensamblado. Estas imágenes JPG se muestran en un documento HTML.

Invocación de plataforma

Se definen unas funciones (imagenFormA, imagenFormB y imagenFormC) que:

  • crean un objeto Graphics de origen (desde la ventana o región)
  • crean un Bitmap para contener la imagen (con la anchura y la altura del formulario o de la región)
  • crean otro objeto Graphics de destino (desde el Bitmap)
  • usan el tipo IntPtr (entero específico de la plataforma – sistema operativo) para obtener el hDC (device context handle – enlace al contexto de dispositivo gráfico) de los 2 objetos Graphics generados
  • usan la función BitBlt (BitBlast) para copiar la imagen en el Bitmap
  • esta imagen es guardada a disco con el formato JPG

Las funciones propias de la clase realizan capturas diferentes:

  • imagenFormA: captura la ventana con decoración y la guarda como CapturaA.jpg
  • imagenFormB: captura la ventana sin decoración y la guarda como CapturaB.jpg
  • imagenFormC: captura la región PictureBox y la guarda como CapturaC.jpg

Las funciones que se llaman desde librerías externas se declaran así:

Imports System.Drawing
Imports System.Drawing.Drawing2D
Imports System.Drawing.Imaging
<System.Runtime.InteropServices.DllImport("gdi32.dll")> _
Public Shared Function BitBlt(ByVal hdcDest As IntPtr, ByVal nXDest As Integer, ByVal nYDest As Integer, ByVal nWidth As Integer, ByVal nHeight As Integer, ByVal hdcSrc As IntPtr, ByVal nXSrc As Integer, ByVal nYSrc As Integer, ByVal dwRop As System.Int32) As Boolean
End Function
 
'constante para usar como último parámetro de la función BitBlt
Private Const SRCCOPY As Integer = &amp;HCC0020 'destino = origen
 
'GetWindowDC devuelve el contexto de dispositivo (DC) correspondiente a la ventana entera,
'con bordes, barras de herramientas, de menús y de scroll, etc. Un DC de la ventana permite
'pintar sobre la ventana ya que el origen del DC es la esquina superior izda. de la ventana
'y no la esquina superior izda. del área cliente de la ventana
'
<System.Runtime.InteropServices.DllImport("User32.dll")> _
Public Shared Function GetWindowDC(ByVal hwnd As System.IntPtr) As System.IntPtr
End Function

La explicación de los parámetros de la función BitBlt es la siguiente:

  • hdcDest: apunta al contexto de dispositivo destino
  • nXDest: coordenada x del rectángulo destino
  • nYDest: coordenada y del rectángulo destino
  • nWidth: anchura de los rectángulos origen y destino
  • nHeight: altura de los rectángulos origen y destino
  • hdcSrc: apunta al contexto de dispositivo origen
  • nXSrc: coordenada x del rectángulo origen
  • nYSrc: coordenada y del rectángulo origen
  • dwRop: código de operación, define la manera en que los datos del origen se combinan con los del destino .

En esta aplicación se usa el tipo de dato IntPtr. Se ha diseñado el tipo IntPtr para que sea un número entero cuyo tamaño sea específico de la plataforma (sistema operativo). Es decir, se espera que una instancia de este tipo tenga lugar en sistemas operativos y hardware de 32 bits, y en sistemas operativos y hardware de 64 bits. El tipo IntPtr se puede utilizar como un medio común para hacer referencia a los datos entre lenguajes (admitan o no punteros). El tipo IntPtr es compatible con CLS (Common Language Specification) que es el conjunto de características básicas de lenguaje englobadas en .NET Framework. El tipo IntPtr pertenece al espacio de nombres System.

Código en Visual Basic .NET

Como ejemplo, expondré una de las 3 funciones de la clase, la que captura la ventana pero sin la decoración (el código es casi idéntico en las 3 funciones).

Al pulsar un botón, se declara un Bitmap obtenido desde la función y se guarda como JPG:

'GUARDAR LA VENTANA SIN BORDES COMO JPG
Private Sub btWin2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btWin2.Click
Try
Dim bm As Bitmap = imagenFormB()
bm.Save(Application.StartupPath &amp; "CapturaB.jpg", ImageFormat.Jpeg)
Catch pollo As Exception
MsgBox("ERROR: " &amp; pollo.Message, MsgBoxStyle.Information, "Aviso")
End Try
End Sub

La función imagenFormB es la que contiene código relacionado con GDI+:

'OBTENER UN BITMAP CON LA IMAGEN DE LA VENTANA SIN DECORACIÓN
Private Function imagenFormB() As Bitmap
Try
'objeto Graphics de origen (desde la ventana o región) 
Dim g1 As Graphics = Me.CreateGraphics
'Bitmap para contener la imagen (anchura y altura del área cliente del formulario)
Dim bm As New Bitmap(Me.ClientSize.Width, Me.ClientSize.Height, g1)
'objeto Graphics de destino (desde el Bitmap)
Dim g2 As Graphics = g1.FromImage(bm)
'IntPtr: entero específico de la plataforma (sistema operativo)
'hDC: device context handle (enlace al contexto de dispositivo del objeto g2)
Dim bm_hdc As IntPtr = g2.GetHdc
' hDC del formulario, se debe hacer después de crear el Bitmap (utiliza g1)
Dim me_hdc As IntPtr = g1.GetHdc
'copiar la imagen del formulario en el Bitmap, el rectángulo origen y destino tienen coordenadas x.y = 0
BitBlt(bm_hdc, 0, 0, Me.ClientSize.Width, Me.ClientSize.Height, me_hdc, 0, 0, SRCCOPY)
'liberar recursos
g1.ReleaseHdc(me_hdc)
g2.ReleaseHdc(bm_hdc)
'devolver el resultado
Return bm
Catch pollo As Exception
MsgBox("ERROR: " &amp; pollo.Message, MsgBoxStyle.Information, "Aviso")
End Try
End Function


Abrir un documento HTML

El código siguiente, ejecutado al pulsar un botón, abre un documento HTML mediante su programa asociado, pasando una cadena con el nombre del archivo; el documento HTML muestra las capturas que ha realizado el programa:

'Iniciar y detener procesos del sistema local
Imports System.Diagnostics
Private Sub btMostrarA_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btMostrarA.Click
'abrir un archivo mediante su programa asociado, pasando una cadena con el nombre del archivo
System.Diagnostics.Process.Start(Application.StartupPath &amp; "imgCapturas.htm")
End Sub