Al trabajar con gráficos en la interfaz de programación de aplicaciones (API) de Windows, especialmente con GDI (Graphics Device Interface), es común necesitar funciones para manipular y dibujar mapas de bits. Dos funciones principales para el escalado de imágenes son StretchBlt y StretchDIBits, cada una con características y usos específicos que vale la pena entender.
Uso de StretchBlt
La función StretchBlt es responsable de copiar un mapa de bits de un rectángulo de origen a un rectángulo de destino, escalando o comprimiendo la imagen según sea necesario para ajustarse a las dimensiones del destino. Operra sobre mapas de bits dependientes del dispositivo (DDB), identificados por un manejador HBITMAP. Si el contexto de dsipositivo de destino (HDC) es el de una ventana, el mapa de bits se dibujará directamente en esa ventana. A continuación, se presenta un ejemplo de su implementación:
void RenderizarMapaBits(HDC hdcDestino, HBITMAP hBitmapOrigen, const RECT& rectDestino)
{
// Crear un contexto de dispositivo compatible para el origen del mapa de bits.
HDC hdcMemoria = CreateCompatibleDC(hdcDestino);
if (!hdcMemoria) {
// Manejo de error
return;
}
// Seleccionar el mapa de bits de origen en el HDC de memoria.
// Guardar el mapa de bits anterior para restaurarlo después.
HBITMAP hBitmapPrevio = (HBITMAP)SelectObject(hdcMemoria, hBitmapOrigen);
if (!hBitmapPrevio) {
DeleteDC(hdcMemoria);
return;
}
// Obtener las dimensiones del mapa de bits de origen.
BITMAP infoBitmap;
if (!GetObject(hBitmapOrigen, sizeof(infoBitmap), &infoBitmap)) {
SelectObject(hdcMemoria, hBitmapPrevio);
DeleteDC(hdcMemoria);
return;
}
// Calcular las dimensiones del rectángulo de destino.
int anchoDestino = rectDestino.right - rectDestino.left;
int altoDestino = rectDestino.bottom - rectDestino.top;
// Realizar la copia y escalado del mapa de bits.
StretchBlt(
hdcDestino, // HDC del contexto de destino.
rectDestino.left, // Coordenada X superior izquierda del destino.
rectDestino.top, // Coordenada Y superior izquierda del destino.
anchoDestino, // Ancho del destino.
altoDestino, // Alto del destino.
hdcMemoria, // HDC del contexto de origen (memoria).
0, // Coordenada X superior izquierda del origen.
0, // Coordenada Y superior izquierda del origen.
infoBitmap.bmWidth, // Ancho del mapa de bits de origen.
infoBitmap.bmHeight, // Alto del mapa de bits de origen.
SRCCOPY // Operación de copia directa.
);
// Restaurar el mapa de bits original en el HDC de memoria.
SelectObject(hdcMemoria, hBitmapPrevio);
// Liberar el HDC de memoria.
DeleteDC(hdcMemoria);
}
Uso de StretchDIBits
Por otro lado, la función StretchDIBits se encarga de copiar los datos de píxeles de un mapa de bits independiente del dispositivo (DIB) a un rectángulo de destino especificado. Los DIBs son estructuras de datos que contienen la información de color de los píxeles y su formato, y se almacenan directamente en memoria, sin estar ligados a un dispositivo específico. Al igual que StretchBlt, si el HDC de destino es el de una ventana, la imagen se dibujará en ella. Un ejemplo de uso se muestra a continuación:
void DibujarDIBEnPantalla(HDC hdcContexto, const BITMAPINFOHEADER* pInfoBitmap,
const void* pDatosPixel, const RECT& rectObjetivo)
{
// Calcular las dimensiones del rectángulo de destino.
int anchoDestino = rectObjetivo.right - rectObjetivo.left;
int altoDestino = rectObjetivo.bottom - rectObjetivo.top;
// Copiar y escalar los datos del DIB al HDC de destino.
StretchDIBits(
hdcContexto, // HDC del contexto de destino.
rectObjetivo.left, // Coordenada X superior izquierda del destino.
rectObjetivo.top, // Coordenada Y superior izquierda del destino.
anchoDestino, // Ancho del destino.
altoDestino, // Alto del destino.
0, // Coordenada X superior izquierda del origen DIB.
0, // Coordenada Y superior izquierda del origen DIB.
pInfoBitmap->biWidth, // Ancho del DIB de origen.
abs(pInfoBitmap->biHeight), // Alto del DIB de origen (puede ser negativo).
pDatosPixel, // Puntero a los datos de píxeles del DIB.
(const BITMAPINFO*)pInfoBitmap, // Puntero a la estructura BITMAPINFO.
DIB_RGB_COLORS, // Las entradas de la tabla de colores son valores RGB.
SRCCOPY // Operación de copia directa.
);
}
Diferencias Clave y Consideraciones de Rendimiento
La distinción fundamental entre StretchBlt y StretchDIBits radica en el tipo de mapa de bits con el que operan:
StretchBlttrabaja con mapas de bits dependientes del dispositivo (DDB), representados por un manejadorHBITMAP. Estos mapas de bits están optimizados para el dispositivo de visualización actual.StretchDIBitsmaneja mapas de bits independientes del dispositivo (DIB), que son bloques de memoria que contienen directamente los datos de píxeles (por ejemplo, datos RGB) y su estructura de cabecera (BITMAPINFOHEADER).
En el contexto de algunas bibliotecas multimedia, como DirectShow, se han observado discusiones sobre las implicaciones de rendimiento entre estas dos funciones. Se ha mencionado que StretchDIBits podría incurrir en una sobrecarga adicional debido a la necesidad de copiar los datos de imagen desde el espacio de direcciones de la aplicación al espacio de direcciones de GDI antes de que se muestren en pantalla. Sin embargo, en sistemas operativos modernos (como Windows XP y Windows 7, y versiones posteriores), la diferencia de eficiencia entre ambas funciones es a menudo insignificante. Esto se debe a que GDI puede optimizar esta copia, a veces simplemente mapeando el búfer de memoria a su propio espacio, reduciendo el costo real. Por lo tanto, en la práctica, es posible utilizar StretchDIBits con confianza, especialmente cuando se trabaja con datos de imagen en memoria que no están necesariamente ligados a un HBITMAP.