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

ビットマップをPNG画像として保存する

戻る


ビットマップをPNG画像として保存したい場合は、次のような コードを使うとよい。

#define WIN32_LEAN_AND_MEAN
#include <windows.h>

#include <stdio.h>
#include <setjmp.h>

#include <png.h>
#pragma comment(lib, "libpng.lib")
#pragma comment(lib, "zlib.lib")

#define WIDTHBYTES(i) (((i) + 31) / 32 * 4)

BOOL SaveBitmapAsPngFile(LPCSTR pszFileName, HBITMAP hbm)
{
    png_structp png;
    png_infop info;
    png_color_8 sBIT;
    png_bytep *lines;
    FILE *outf;
    HDC hMemDC;
    BITMAPINFO bi;
    BITMAP bm;
    DWORD dwWidthBytes, cbBits;
    LPBYTE pbBits;
    BOOL f;
    INT y;
    INT nDepth;
    
    if (GetObject(hbm, sizeof(BITMAP), &bm) != sizeof(BITMAP))
        return FALSE;

    nDepth = (bm.bmBitsPixel == 32 ? 32 : 24);
    dwWidthBytes = WIDTHBYTES(bm.bmWidth * nDepth);
    cbBits = dwWidthBytes * bm.bmHeight;
    pbBits = (LPBYTE)HeapAlloc(GetProcessHeap(), 0, cbBits);
    if (pbBits == NULL)
        return FALSE;

    f = FALSE;
    hMemDC = CreateCompatibleDC(NULL);
    if (hMemDC != NULL)
    {
        ZeroMemory(&bi, sizeof(BITMAPINFOHEADER));
        bi.bmiHeader.biSize     = sizeof(BITMAPINFOHEADER);
        bi.bmiHeader.biWidth    = bm.bmWidth;
        bi.bmiHeader.biHeight   = bm.bmHeight;
        bi.bmiHeader.biPlanes   = 1;
        bi.bmiHeader.biBitCount = (WORD)nDepth;
        f = GetDIBits(hMemDC, hbm, 0, bm.bmHeight, pbBits, &bi, 
                      DIB_RGB_COLORS);
        DeleteDC(hMemDC);
    }
    if (!f)
    {
        HeapFree(GetProcessHeap(), 0, pbBits);
        return FALSE;
    }

    outf = fopen(pszFileName, "wb");
    if (!outf)
    {
        HeapFree(GetProcessHeap(), 0, pbBits);
        return FALSE;
    }

    png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (png == NULL)
    {
        HeapFree(GetProcessHeap(), 0, pbBits);
        fclose(outf);
        DeleteFile(pszFileName);
        return FALSE;
    }

    info = png_create_info_struct(png);
    if (info == NULL)
    {
        HeapFree(GetProcessHeap(), 0, pbBits);
        png_destroy_write_struct(&png, NULL);
        fclose(outf);
        DeleteFile(pszFileName);
        return FALSE;
    }

    lines = NULL;
    if (setjmp(png_jmpbuf(png)))
    {
        HeapFree(GetProcessHeap(), 0, pbBits);
        if (lines != NULL)
            HeapFree(GetProcessHeap(), 0, lines);
        fclose(outf);
        DeleteFile(pszFileName);
        return FALSE;
    }

    png_init_io(png, outf);
    png_set_IHDR(png, info, bm.bmWidth, bm.bmHeight, 8, 
        (nDepth == 32 ? PNG_COLOR_TYPE_RGB_ALPHA : PNG_COLOR_TYPE_RGB),
        PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_BASE);

    sBIT.red = 8;
    sBIT.green = 8;
    sBIT.blue = 8;
    sBIT.alpha = (png_byte)(nDepth == 32 ? 8 : 0);
    png_set_sBIT(png, info, &sBIT);

    png_write_info(png, info);
    png_set_bgr(png);

    lines = (png_bytep *)HeapAlloc(GetProcessHeap(), 0, 
                                   sizeof(png_bytep *) * bm.bmHeight);
    for (y = 0; y < bm.bmHeight; y++)
        lines[y] = (png_bytep)&pbBits[dwWidthBytes * (bm.bmHeight - y - 1)];

    png_write_image(png, lines);
    png_write_end(png, info);
    png_destroy_write_struct(&png, &info);

    HeapFree(GetProcessHeap(), 0, pbBits);
    HeapFree(GetProcessHeap(), 0, lines);
    fclose(outf);

    return TRUE;
}

#ifdef UNITTEST
int main(void)
{
    HBITMAP hbm = (HBITMAP)LoadImage(NULL, "alpha.bmp", IMAGE_BITMAP,
                                     0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
    SaveBitmapAsPngFile("alpha.png", hbm);
    DeleteObject(hbm);
    return 0;
}
#endif

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

ソース: savepng.zip


戻る

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

inserted by FC2 system