Capítulo 1 Carga de bitmaps

Lo primero es lo primero, y en este caso, lo primero es aprender a cargar un mapa de bits desde un fichero.

La función para cargar una imagen desde un fichero es FreeImage_Load o FreeImage_LoadU si se trata de cargar mapas de bits desde ficheros con nombres Unicode, pero estas funciones necesitan saber qué tipo de fichero queremos cargar, bmp, gif, jpg, png, etc. Los tipos soportados se pueden consultar en la tabla 1.

Hay varias maneras de averiguar este dato. La primera opción es usar FreeImage_GetFileType. Esta función intentará recuperar el tipo de mapa de bits a partir de la firma del fichero.

Si esta función no ha podido recuperar el tipo de mapa de bits, nos queda una segunda opción, y es deducir el tipo a partir de la extensión de fichero. Para eso sirve la función FreeImage_GetFIFFromFilename.

Si ambas funciones fracasan, probablemente estemos intentando cargar un fichero que no contiene un mapa de bits, o que está en un formato no soportado por FreeImage.

Pero incluso si hemos podido identificar el tipo de mapa de bits, eso no nos garantiza que FreeImage pueda cargarlo desde un fichero. Para averiguar si es posible usaremos la función FreeImage_FIFSupportsReading.

La función que propone la documentación de FreeImage para cargar un mapa de bits desde un fichero es esta:

FIBITMAP* GenericLoader(const char* lpszPathName, int flag)
{
    FREE_IMAGE_FORMAT fif = FIF_UNKNOWN;

    // Verifica la firma y deduce el formato
    // (El segundo argumento no se usa aún por FreeImage)
    fif = FreeImage_GetFileType(lpszPathName, 0);
    if(fif == FIF_UNKNOWN) {
        // ¿no hay firma?
        // Intenta obtener el formato a partir de la extensión de fichero
        fif = FreeImage_GetFIFFromFilename(lpszPathName);
    }
    // Verifica si el plugin puede leer este tipo de mapa de bits...
    if((fif != FIF_UNKNOWN) && FreeImage_FIFSupportsReading(fif)) {
        // Lo cargamos
        FIBITMAP *dib = FreeImage_Load(fif, lpszPathName, flag);
        // unless a bad file format, we are done !
        return dib;
    } else 
        return 0;
}

Ahora que sabemos cómo obtener un mapa de bits a partir de un fichero podemos hacer muchas cosas con él. FreeImage dispone de muchas funciones para modificar mapas de bits. En los próximos capítulos veremos algunas de ellas. Pero ahora, empecemos por visualizar el mapa de bits.

Visualizar el mapa de bits

Por supuesto, la forma de visualizar un mapa de bits dependerá del sistema operativo y del entorno de trabajo que estemos usando. En los ejemplos de este curso usaremos el API de Windows, pero no debería ser un gran problema adaptar estos ejemplos a otros entornos.

En mostrar mapas de bits se explica el modo de mostrar mapas de bits usando el API de Windows.

La función FreeImage_Load devuelve un objeto de tipo FIBITMAP, que no es otra cosa que un puntero genérico (void*). La memoria apuntada por ese puntero contiene toda la información necesaria para interpretar el mapa de bits.

Para mostrar un mapa de bits usando el API de Windows necesitamos un HBITMAP, es decir, un manipualdor de mapa de bits que posteriormente usaremos con las funciones de visualización de Windows, como BitBlt, StretchBlt, PlgBlt o MaskBlt.

Para obtener un HBITMAP usaremos la función CreateDIBitmap. Esta función requiere varios parámetros:

  • Un manipulador de contexto de dispositivo, HDC, que dependerá del dispositivo en el que queramos mostrar el mapa de bits. Cuando se procesa un mensaje WM_PAINT, este HDC lo obtendremos con una función BeginPaint.
  • Un puntero a una estructura BITMAPINFOHEADER. FreeImage nos permite obtener esta estructura mediante la función FreeImage_GetInfoHeader
  • Un flag de inicialización, que puede tomar dos valores: 0 ó CBM_INIT. El valor 0 indica que no se usan los datos para iniciar los bits del mapa, por lo tanto usaremos siempre el valor CBM_INIT.
  • Puntero a los bits con la información de los pixels de la imagen. Este puntero lo obtendremos mediante la función FreeImage_GetBits.
  • Un puntero a una estructura BITMAPINFO con los datos del formato de color del mapa de bits. Lo obtendremos mediante la función FreeImage_GetInfo.
  • Indica si la paleta de la estructura BITMAPINFO contiene una paleta o no. Usaremos el valor DIB_RGB_COLORS
    bitmap = CreateDIBitmap(hdc, FreeImage_GetInfoHeader(dib),
        CBM_INIT, FreeImage_GetBits(dib), FreeImage_GetInfo(dib), DIB_RGB_COLORS);

Una vez disponemos de un HBITMAP, procesaremos el mensaje WM_PAINT como vimos en el capítulo 23 del curso del WinAPI.

    case WM_PAINT:
        // Si no se pudo cargar el mapa de bits, retornar sin mostrar nada.
        if(!dib) return 0;
        hdc = BeginPaint(hwnd, LPPAINTSTRUCT(&ps));
        bitmap = CreateDIBitmap(hdc, FreeImage_GetInfoHeader(dib),
            CBM_INIT, FreeImage_GetBits(dib), FreeImage_GetInfo(dib), DIB_RGB_COLORS);
        memDC = CreateCompatibleDC(hdc);
        GetClientRect(hwnd, (LPRECT)&re);
        SelectObject(memDC, bitmap);
        BitBlt(hdc, re.left, re.top, re.right-re.left, re.bottom-re.top, memDC, 0, 0, SRCCOPY);
        DeleteDC(memDC);
        EndPaint(hwnd, LPPAINTSTRUCT(&ps));
        return 0;

Opciones de carga

Para algunos tipos de mapas de bits existen ciertas opciones de carga. Estas opciones se pasan en el tercer parámetro de la función FreeImage_Load. Las opciones disponibles se pueden consultar en la tabla 3.

Por ejemplo, para el tipo FIF_JPEG existen cinco opciones diferentes. Entre ellas JPEG_FAST intentará cargar la imagen lo más rápido posible, sacrificando calidad, JPEG_ACCURATE, al contrario, sacrificará velocidad de carga para aumentar la calidad o JPEG_GREYSCALE, cargará un mapa de bits en escala de grises.

Ejemplo 1

Este ejemplo carga algunos mapas de bits con diferentes opciones.

Nombre Fichero Fecha Tamaño Contador Descarga
Ejemplo 1 FreeImage FreeImage001.zip 2021-04-12 6659611 bytes 199

Guardar imagen

Si queremos guardar una imagen modificada, cambiar el formato o alterar alguna de las opciones, podemos usar la función FreeImage_Save, o bien la función FreeImage_SaveU si el nombre del fichero es una cadena Unicode.

Es posible, y sencillo, cambiar el formato de un fichero de imagen. Podemos, por ejemplo, cargar un fichero en formato jpg y guardarlo en formato png. Bastará con indicar en el primer parámetro en nuevo formato y seleccionar las opciones que prefiramos. Por supuesto, también es conveniente usar la extensión de fichero adecuada para el nuevo formato.

Por ejemplo, para convertir un fichero en formato jpg a png:

    FIBITMAP* dib;
    char *lpszPathName = "original.jpg";
    FREE_IMAGE_FORMAT fif = FIF_UNKNOWN;
...
    fif = FreeImage_GetFileType(lpszPathName, 0);
    if(fif == FIF_UNKNOWN) {
	fif = FreeImage_GetFIFFromFilename(lpszPathName);
    }
    if((fif != FIF_UNKNOWN) && FreeImage_FIFSupportsReading(fif)) {
        dib = FreeImage_Load(fif, lpszPathName, 0);
        FreeImage_Save(FIF_PNG, dib, "modificado.png", PNG_Z_BEST_COMPRESSION | PNG_INTERLACED);
    }
    FreeImage_Unload(dib);

La tabla 4 se pueden ver todas las opciones disponibles para cada tipo de fichero de imagen.