ソフトウェア開発 Win32プログラミング

GIF画像をビットマップとして読み込む

戻る


GIF画像をビットマップとして読み込むには、次のような コードを使うとよい。

#include <windows.h>

#include <stdlib.h>
#include <stdio.h>

#ifdef __cplusplus
extern "C"
{
#endif

#include <kohn_gif.h>

#ifdef __cplusplus
}
#endif

#pragma comment(lib, "kohn_gif.lib")

typedef struct tagBITMAPINFOEX
{
    BITMAPINFOHEADER bmiHeader;
    RGBQUAD          bmiColors[256];
} BITMAPINFOEX, FAR * LPBITMAPINFOEX;

HBITMAP LoadGifAsBitmap(LPCSTR pszFileName, COLORREF *prgbTransparent)
{
    struct gif_info_t *gif;
    BITMAPINFOEX bix;
    HBITMAP hbm;
    HDC hDC;
    UINT i, x, y, t, v, widthbytes, num_bytes;
    BYTE *pbBits;

    gif = kgif_alloc_decompress();
    if (gif == NULL)
        return NULL;

    gif->fp = fopen(pszFileName, "rb");
    if (gif->fp == NULL)
    {
        kgif_info_free(gif);
        return NULL;
    }

    if (kgif_read_header(gif) != 0)
    {
        fclose(gif->fp);
        kgif_info_free(gif);
        return NULL;
    }

#define WIDTHBYTES(i) (((i) + 31) / 32 * 4)
    widthbytes = WIDTHBYTES(gif->width * 32);

    ZeroMemory(&bix.bmiHeader, sizeof(BITMAPINFOHEADER));
    bix.bmiHeader.biSize        = sizeof(BITMAPINFOHEADER);
    bix.bmiHeader.biWidth       = gif->width;
    bix.bmiHeader.biHeight      = -(INT)gif->height;
    bix.bmiHeader.biPlanes      = 1;
    bix.bmiHeader.biBitCount    = 32;

    hDC = CreateCompatibleDC(NULL);
    if (hDC == NULL)
    {
        fclose(gif->fp);
        kgif_info_free(gif);
        return NULL;
    }

    hbm = CreateDIBSection(hDC, (BITMAPINFO *)&bix, DIB_RGB_COLORS, 
                           (VOID **)&pbBits, NULL, 0);
    DeleteDC(hDC);
    if (hbm == NULL)
    {
        fclose(gif->fp);
        kgif_info_free(gif);
        return NULL;
    }

    if (gif->transparency_index != -1)
    {
        v = gif->color_map[gif->transparency_index];
        *prgbTransparent = RGB(v >> 16, v >> 8, v);
    }
    else
    {
        *prgbTransparent = CLR_INVALID;
    }

    if ((gif->flags & 0x40) == 0x40)
    {
        /* interlace */
        static const int offsets[] = { 0, 4, 2, 1 };
        static const int jumps[] = { 8, 8, 4, 2 };

        x = y = i = 0;
        while (i < 4)
        {
            if (gif->y > y)
                break;

            num_bytes = kgif_decompress(gif);

            for (t = 0; t < num_bytes; t++)
            {
                v = gif->decomp_buff[t];
                if (gif->transparency_index != -1 && v == gif->transparency_index)
                {
                    v = gif->color_map[v];
                    pbBits[y * widthbytes + x * 4 + 0] = (BYTE)v;
                    pbBits[y * widthbytes + x * 4 + 1] = (BYTE)(v >> 8);
                    pbBits[y * widthbytes + x * 4 + 2] = (BYTE)(v >> 16);
                    pbBits[y * widthbytes + x * 4 + 3] = 0;
                }
                else
                {
                    v = gif->color_map[v];
                    pbBits[y * widthbytes + x * 4 + 0] = (BYTE)v;
                    pbBits[y * widthbytes + x * 4 + 1] = (BYTE)(v >> 8);
                    pbBits[y * widthbytes + x * 4 + 2] = (BYTE)(v >> 16);
                    pbBits[y * widthbytes + x * 4 + 3] = 0xFF;
                }
                x++;
                if (x >= gif->width)
                {
                    x = 0;
                    y += jumps[i];
                    if (y >= gif->height)
                    {
                        i++;
                        y = offsets[i];
                    }
                }
            }
        }
    }
    else
    {
        x = y = 0;
        while (y < gif->height)
        {
            if (gif->y > y)
                break;

            num_bytes = kgif_decompress(gif);
            for (t = 0; t < num_bytes; t++)
            {
                v = gif->decomp_buff[t];
                if (gif->transparency_index != -1 && v == gif->transparency_index)
                {
                    v = gif->color_map[v];
                    pbBits[y * widthbytes + x * 4 + 0] = (BYTE)v;
                    pbBits[y * widthbytes + x * 4 + 1] = (BYTE)(v >> 8);
                    pbBits[y * widthbytes + x * 4 + 2] = (BYTE)(v >> 16);
                    pbBits[y * widthbytes + x * 4 + 3] = 0;
                }
                else
                {
                    v = gif->color_map[v];
                    pbBits[y * widthbytes + x * 4 + 0] = (BYTE)v;
                    pbBits[y * widthbytes + x * 4 + 1] = (BYTE)(v >> 8);
                    pbBits[y * widthbytes + x * 4 + 2] = (BYTE)(v >> 16);
                    pbBits[y * widthbytes + x * 4 + 3] = 0xFF;
                }
                x++;
                if (x >= gif->width)
                {
                    x = 0;
                    y++;
                }
            }
        }
    }

    fclose(gif->fp);
    kgif_info_free(gif);
    return hbm;
}

#ifdef UNITTEST
BOOL SaveBitmapToFile(LPCTSTR pszFileName, HBITMAP hbm)
{
    ...
}

int main(void)
{
    COLORREF clr;
    HBITMAP hbm = LoadGifAsBitmap("a.gif", &clr);
    printf("%08lX\n", clr);
    SaveBitmapToFile("a.bmp", hbm);
    DeleteObject(hbm);
    return 0;
}
#endif  /* def UNITTEST */

LoadGifAsBitmap関数がGIF画像の読み込みを行う。引数のprgbTransparentは、 透過する色を返す。 途中の CLR_INVALID は、Windowsによって使われている、無効な色を表す特殊な値である。

なお、このコードをコンパイルするには、libkohn_gifライブラリが必要だ。

ソース: loadgif.zip


戻る

©片山博文MZ
katayama.hirofumi.mz@gmail.com

inserted by FC2 system