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

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

戻る


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

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <malloc.h>
 
#include <png.h>
 
#include <setjmp.h>
 
#pragma comment(lib, "zlib.lib")
#pragma comment(lib, "libpng.lib")
 
#define WIDTHBYTES(i) (((i) + 31) / 32 * 4)

HBITMAP LoadPngAsBitmap(LPCSTR pszFileName)
{
    FILE            *inf;
    HBITMAP         hbm;
    png_structp     png;
    png_infop       info;
    png_uint_32     y, width, height, rowbytes;
    int             color_type, depth, widthbytes;
    double          gamma;
    BITMAPINFO      bi;
    BYTE            *pbBits;
    png_bytepp      row_pointers;
 
    inf = fopen(pszFileName, "rb");
    if (inf == NULL)
        return NULL;
 
    png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (png == NULL)
    {
        fclose(inf);
        return NULL;
    }
 
    info = png_create_info_struct(png);
    if (info == NULL || setjmp(png_jmpbuf(png)))
    {
        png_destroy_read_struct(&png, NULL, NULL);
        fclose(inf);
        return NULL;
    }
 
    if (setjmp(png_jmpbuf(png)))
    {
        png_destroy_read_struct(&png, &info, NULL);
        fclose(inf);
        return NULL;
    }
 
    png_init_io(png, inf);
    png_read_info(png, info);
 
    png_get_IHDR(png, info, &width, &height, &depth, &color_type,
                 NULL, NULL, NULL);
    png_set_strip_16(png);
    png_set_gray_to_rgb(png);
    png_set_palette_to_rgb(png);
    png_set_bgr(png);
    png_set_packing(png);
    if (png_get_gAMA(png, info, &gamma))
        png_set_gamma(png, 2.2, gamma);
    else
        png_set_gamma(png, 2.2, 0.45455);
 
    png_read_update_info(png, info);
    png_get_IHDR(png, info, &width, &height, &depth, &color_type,
                 NULL, NULL, NULL);
 
    rowbytes = png_get_rowbytes(png, info);
    row_pointers = (png_bytepp)malloc(height * png_sizeof(png_bytep));
    for (y = 0; y < height; y++)
    {
        row_pointers[y] = (png_bytep)png_malloc(png, rowbytes);
    }
 
    png_read_image(png, row_pointers);
    png_read_end(png, NULL);
    fclose(inf);
 
    ZeroMemory(&bi.bmiHeader, sizeof(BITMAPINFOHEADER));
    bi.bmiHeader.biSize        = sizeof(BITMAPINFOHEADER);
    bi.bmiHeader.biWidth       = width;
    bi.bmiHeader.biHeight      = height;
    bi.bmiHeader.biPlanes      = 1;
    bi.bmiHeader.biBitCount    = depth * png_get_channels(png, info);
 
    hbm = CreateDIBSection(NULL, &bi, DIB_RGB_COLORS, (VOID **)&pbBits, 
                           NULL, 0);
    if (hbm == NULL)
    {
        png_destroy_read_struct(&png, &info, NULL);
        return NULL;
    }
 
    widthbytes = WIDTHBYTES(width * bi.bmiHeader.biBitCount);
    for(y = 0; y < height; y++)
    {
        CopyMemory(pbBits + y * widthbytes, 
                   row_pointers[height - 1 - y], rowbytes);
    }
 
    png_destroy_read_struct(&png, &info, NULL);
    free(row_pointers);
    return hbm;
}
 
#ifdef UNITTEST
typedef struct tagBITMAPINFOEX
{
    BITMAPINFOHEADER bmiHeader;
    RGBQUAD          bmiColors[256];
} BITMAPINFOEX, FAR * LPBITMAPINFOEX;
 
BOOL SaveBitmapToFile(LPCTSTR pszFileName, HBITMAP hbm)
{
    BOOL f;
    DWORD dwError;
    BITMAPFILEHEADER bf;
    BITMAPINFOEX bi;
    BITMAPINFOHEADER *pbmih;
    DWORD cb;
    DWORD cColors, cbColors;
    HDC hDC;
    HANDLE hFile;
    LPVOID pBits;
    BITMAP bm;
    
    if (!GetObject(hbm, sizeof(BITMAP), &bm))
        return FALSE;
    
    pbmih = &bi.bmiHeader;
    ZeroMemory(pbmih, sizeof(BITMAPINFOHEADER));
    pbmih->biSize             = sizeof(BITMAPINFOHEADER);
    pbmih->biWidth            = bm.bmWidth;
    pbmih->biHeight           = bm.bmHeight;
    pbmih->biPlanes           = 1;
    pbmih->biBitCount         = bm.bmBitsPixel;
    pbmih->biCompression      = BI_RGB;
    pbmih->biSizeImage        = bm.bmWidthBytes * bm.bmHeight;
    
    if (bm.bmBitsPixel < 16)
        cColors = 1 << bm.bmBitsPixel;
    else
        cColors = 0;
    cbColors = cColors * sizeof(RGBQUAD);
    
    bf.bfType = 0x4d42;
    bf.bfReserved1 = 0;
    bf.bfReserved2 = 0;
    cb = sizeof(BITMAPFILEHEADER) + pbmih->biSize + cbColors;
    bf.bfOffBits = cb;
    bf.bfSize = cb + pbmih->biSizeImage;
    
    pBits = HeapAlloc(GetProcessHeap(), 0, pbmih->biSizeImage);
    if (pBits == NULL)
        return FALSE;
    
    f = FALSE;
    hDC = GetDC(NULL);
    if (hDC != NULL)
    {
        if (GetDIBits(hDC, hbm, 0, bm.bmHeight, pBits, (BITMAPINFO*)&bi, 
            DIB_RGB_COLORS))
        {
            hFile = CreateFile(pszFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL,
                               CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | 
                               FILE_FLAG_WRITE_THROUGH, NULL);
            if (hFile != INVALID_HANDLE_VALUE)
            {
                f = WriteFile(hFile, &bf, sizeof(BITMAPFILEHEADER), &cb, NULL) &&
                    WriteFile(hFile, &bi, sizeof(BITMAPINFOHEADER), &cb, NULL) &&
                    WriteFile(hFile, bi.bmiColors, cbColors, &cb, NULL) &&
                    WriteFile(hFile, pBits, pbmih->biSizeImage, &cb, NULL);
                if (!f)
                    dwError = GetLastError();
                CloseHandle(hFile);
                
                if (!f)
                    DeleteFile(pszFileName);
            }
            else
                dwError = GetLastError();
        }
        else
            dwError = GetLastError();
        ReleaseDC(NULL, hDC);
    }
    else
        dwError = GetLastError();
    
    HeapFree(GetProcessHeap(), 0, pBits);
    SetLastError(dwError);
    return f;
}
 
int main(void)
{
    HBITMAP hbm;
    WIN32_FIND_DATA find;
    HANDLE hFind;
    
    hFind = FindFirstFile("*.png", &find);
    if (hFind != INVALID_HANDLE_VALUE)
    {
        do 
        {
            hbm = LoadPngAsBitmap(find.cFileName);
            lstrcat(find.cFileName, ".bmp");
            SaveBitmapToFile(find.cFileName, hbm);
            DeleteObject(hbm);
        } while(FindNextFile(hFind, &find));
        FindClose(hFind);
    }
    
    return 0;
}
#endif  /* def UNITTEST */

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

ソース: loadpng.zip


戻る

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

inserted by FC2 system