1.メモ


	

2.GDI+ で IStream を使って画像を読み込む

例えば、暗号化された画像ファイルを読み込む場合などに使える
#include <windows.h>
#include <gdiplus.h>

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

#define MYWNDCLASS      "gdi_stream"
#define MYWNDTITLE      "gdi_stream"

using namespace     Gdiplus;
GdiplusStartupInput gdiSI;
ULONG_PTR           gdiToken;
Bitmap              *Bmp_R;
int                 wdh,hgt;
LPSTREAM            g_pStrm = NULL;

LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
void Read_Image(char *fname);

int APIENTRY WinMain(HINSTANCE hInst, HINSTANCE hInstPrev, LPSTR lpCmdLine, int nCmdShow)
{
    MSG        msg;
    WNDCLASSEX wc;
    HWND       hWnd;
    
    // 親ウィンドウ
    ZeroMemory(&wc, sizeof(wc));
    wc.cbSize           = sizeof(WNDCLASSEX);
    wc.lpfnWndProc      = (WNDPROC)WndProc;
    wc.hInstance        = hInst;
    wc.hIcon            = LoadIcon(hInst, IDI_APPLICATION);
    wc.hCursor          = LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW));
    wc.hbrBackground    = (HBRUSH)(COLOR_BTNFACE + 1);
    wc.lpszMenuName     = NULL;
    wc.lpszClassName    = MYWNDCLASS;
    RegisterClassEx(&wc);
    
    hWnd = CreateWindowEx(WS_EX_CLIENTEDGE | WS_EX_ACCEPTFILES,
                MYWNDCLASS,
                MYWNDTITLE,
                WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_VISIBLE,
                CW_USEDEFAULT, CW_USEDEFAULT, 480, 320,
                NULL,
                NULL,
                hInst,
                NULL);

    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return msg.wParam;
}// WinMain

LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
    case WM_CREATE:
        GdiplusStartup(&gdiToken,&gdiSI,NULL);
        return 0;
    case WM_SHOWWINDOW:
        if(__argc > 1){ // アイコンへのDrag&Drop
            Read_Image(__argv[1]);
            __argc = 0;
        }
        return 0;
    case WM_PAINT:
        {
            HDC             hDC;
            PAINTSTRUCT     ps;
            hDC = BeginPaint(hWnd,&ps);
            if(Bmp_R){
                Graphics    g(hDC);
                g.DrawImage(Bmp_R, 0, 0, wdh, hgt);
            }
            EndPaint(hWnd,&ps);
        }
        return 0;
    case WM_DROPFILES: // ウィンドウへのDrag&Drop
        char    fname[MAX_PATH];
        HDROP   hDrop;
        hDrop = (HDROP) wParam;
        DragQueryFile(hDrop, 0, fname, sizeof(fname));
        Read_Image(fname);
        DragFinish(hDrop);
        InvalidateRect(hWnd,NULL,TRUE);
        return 0;
    case WM_CLOSE:
        if(Bmp_R)
            delete Bmp_R;
        if(g_pStrm)
            g_pStrm->Release();
        DestroyWindow(hWnd);
        GdiplusShutdown(gdiToken);
        PostQuitMessage(0);
        return 0;
    }
    return DefWindowProc(hWnd, uMsg, wParam, lParam);
}// WndProc

// ファイルから画像を読み込む
void Read_Image(char *fname)
{
    HANDLE      hFile;
    DWORD       dwRead;
    
    hFile = CreateFile(fname,GENERIC_READ,FILE_SHARE_READ,
                        NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
    if(hFile == INVALID_HANDLE_VALUE){
        return;
    }
    DWORD size = GetFileSize(hFile, NULL);
    if(size > 0 && size != 0xFFFFFFFF){
        if(Bmp_R)
            delete Bmp_R;
        if(g_pStrm)
            g_pStrm->Release();
        HGLOBAL hMem = GlobalAlloc(GPTR, size);
        LPBYTE pData = (LPBYTE) GlobalLock(hMem);
        ReadFile(hFile, pData, size, &dwRead, NULL);
        CreateStreamOnHGlobal(hMem, TRUE, &g_pStrm);
        GlobalUnlock(hMem);
        Bmp_R = Bitmap::FromStream(g_pStrm, TRUE);
        wdh = Bmp_R->GetWidth();
        hgt = Bmp_R->GetHeight();
    }
    CloseHandle(hFile);
}// Read_Image

3.クリップボード

 DIBのコピーと貼り付け 。
 プログラムを実行する前に、ペイントなどで画像をコピーする必要がある。
 BITMAPINFO構造体には、1,4,8,16,24,32bit画像情報を格納できる。
 ただし、透明度は描画に反映されない。
#include <windows.h>
#include <stdio.h>
#include <GdiPlus.h>
#include "resource.h"

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

using namespace     Gdiplus;
GdiplusStartupInput gdiSI;
ULONG_PTR           gdiToken;
Bitmap              *Bmp2;

LRESULT CALLBACK WndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam);
Status Get_ClipBoard_DIB();
Status Set_ClipBoard_DIB();

LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
    case WM_CREATE:
        GdiplusStartup(&gdiToken,&gdiSI,NULL);  // GDI+オブジェクト初期化
        break;
    case WM_PAINT:
        {
            HDC             hDC;
            PAINTSTRUCT     ps;
            hDC = BeginPaint(hWnd,&ps);
            Graphics MyGraphics(hDC);
            if(Bmp2)
                MyGraphics.DrawImage(Bmp2, 0, 0);
            EndPaint(hWnd,&ps);
        }
        break;
    case WM_COMMAND:
        switch( LOWORD(wParam) )
        {
        case IDM_COPY:
            if(Bmp2){
                Set_ClipBoard_DIB();
            }
            break;
        case IDM_PASTE:
            delete Bmp2;
            Bmp2 = NULL;
            if(Get_ClipBoard_DIB() == Ok){
                InvalidateRect(hWnd,NULL,TRUE);
            }
            break;
        }
        break;
    case WM_CLOSE:
        delete Bmp2;
        Bmp2 = NULL;
        DestroyWindow(hWnd);
        GdiplusShutdown(gdiToken);
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, uMsg, wParam, lParam);
    }
    return 0;
}// CALLBACK WndProc

Status Get_ClipBoard_DIB()
{
    HANDLE          hMem;
    BITMAPINFO      *pbmi;
    BYTE            *pbits;         // ピクセルデータ
    UINT            nColors;        // パレットの色数
    UINT            nBitFields = 0; // ピクセルフォーマットマスクのサイズ
    
    if(!OpenClipboard(NULL)){
        MessageBox(NULL,"クリップボードを開けません",MYWNDTITLE,MB_OK | MB_ICONWARNING);
        return GenericError;
    }
    hMem = (HANDLE) GetClipboardData (CF_DIB);
    if(!hMem)   return GenericError;
    pbmi = (LPBITMAPINFO) GlobalLock (hMem);
    if(!pbmi){
        GlobalUnlock(hMem);
        return GenericError;
    }
    
    // パレットの色数
    if(pbmi->bmiHeader.biClrUsed != 0 )
        nColors = pbmi->bmiHeader.biClrUsed;
    else if(pbmi->bmiHeader.biBitCount <= 8)
        nColors = 1 << pbmi->bmiHeader.biBitCount;
    else
        nColors = 0;
    
    if(pbmi->bmiHeader.biCompression == BI_BITFIELDS)
        nBitFields = sizeof(DWORD) * 3;
    
    pbits = ((LPBYTE)pbmi + sizeof(BITMAPINFOHEADER)
                        + nBitFields + nColors * sizeof(RGBQUAD));
    
    if(!pbmi || !pbits){
        GlobalUnlock(hMem);
        return GenericError;
    }
    
    Bitmap Bmp1 (pbmi, pbits);
    
    Status      st;
    int         wdh    = Bmp1.GetWidth();
    int         hgt    = Bmp1.GetHeight();
    PixelFormat format = Bmp1.GetPixelFormat();
    
    if(Bmp2){
        delete Bmp2;
        Bmp2 = NULL;
    }
    Bmp2 = new Bitmap(wdh, hgt, format);
    st = Bmp2->GetLastStatus();
    if(st == Ok){
        // パレット
        if(format & PixelFormatIndexed){
            ColorPalette    *ppal = NULL;
            int             p_sz = Bmp1.GetPaletteSize();
            ppal = (ColorPalette *) new BYTE [p_sz];
            if(ppal){
                st = Bmp1.GetPalette(ppal, p_sz);
                if(st == Ok){
                    st = Bmp2->SetPalette(ppal);
                }
            }
            delete [] (LPBYTE) ppal;
            ppal = NULL;
        }
    }
    
    if(_winmajor >= 6 || !(format & PixelFormatIndexed) && format != PixelFormat32bppRGB){
    // _winmajor 6 は Windows7。 32bpp は 透明度が含まれる場合があるため。
        Graphics    gBmp(Bmp2);
        gBmp.DrawImage(&Bmp1, 0, 0, wdh, hgt);
    }
    else{
        BitmapData  bitmapData;
        int         bpp     = pbmi->bmiHeader.biBitCount;
        Rect        rect(0, 0, wdh, hgt);
        st = Bmp2->LockBits(&rect, ImageLockModeWrite, format, &bitmapData);
        if (st == Ok)
        {
            int y,y2;
        
            LPBYTE pixels = (LPBYTE) bitmapData.Scan0;
        
            int stride = abs(bitmapData.Stride);
        
            if(bpp <= 0 || bpp > 32){
                ZeroMemory(pixels, stride * hgt);
            }
            else{
                for(y=0;y<hgt;y++){
                    if(pbmi->bmiHeader.biHeight >= 0){
                        y2 = hgt - y - 1;
                    }
                    else{
                        y2 = y;
                    }
                    if(bpp >= 8){
                        memcpy(&pixels[y2 * stride], &pbits[y * stride], wdh * (bpp / 8));
                    }
                    else{
                        memcpy(&pixels[y2 * stride], &pbits[y * stride], wdh / (8 / bpp));
                    }
                }
            }
            st = Bmp2->UnlockBits(&bitmapData);
        }
        if(st != Ok){
            MessageBox(GetFocus(),"Bmp2 Lock or Unlock Error","Clipboard Error",MB_OK);
            if(Bmp2){
                delete Bmp2;
                Bmp2 = NULL;
            }
            return st;
        }
    }
    return Ok;
}// Get_ClipBoard_DIB

// クリップボードに画像データを置く
Status Set_ClipBoard_DIB()
{
    Status          st;
    HANDLE          hMem = NULL;
    BITMAPINFO      *pbmi;
    BYTE            *pbits,*buf;
    BitmapData      bitmapData;
    int             wdh     = Bmp2->GetWidth();
    int             hgt     = Bmp2->GetHeight();
    PixelFormat     format  = Bmp2->GetPixelFormat();
    int             bpp     = (BYTE)(format >> 8);  // カラーデプス
    int             pbmi_sz = 0;
    int             pbits_sz= 0;                    // 画像サイズ
    UINT            nColors = 0;                    // パレットの最大色数
    UINT            nBitFields = 0;                 // 16-R5G6B5 マスクのサイズ
    Rect            rect(0, 0, wdh, hgt);

    if(bpp <= 8)    nColors = 1 << bpp;
    
    if(format == PixelFormat16bppRGB565)
        nBitFields = sizeof(DWORD) * 3;
    
    pbmi_sz = sizeof(BITMAPINFOHEADER)+nBitFields+nColors*sizeof(RGBQUAD);
    
    pbmi = (LPBITMAPINFO) new BYTE [pbmi_sz];
    ZeroMemory(&pbmi->bmiColors, nBitFields+nColors*sizeof(RGBQUAD));
    ZeroMemory(&pbmi->bmiHeader, sizeof(BITMAPINFOHEADER));
    pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    pbmi->bmiHeader.biWidth = wdh;
    pbmi->bmiHeader.biHeight = hgt;
    pbmi->bmiHeader.biBitCount = bpp;
    pbmi->bmiHeader.biPlanes = 1;
    pbmi->bmiHeader.biClrUsed = 0;      // 互換性のため
    if(format == PixelFormat16bppRGB565)
        pbmi->bmiHeader.biCompression = BI_BITFIELDS;
    else
        pbmi->bmiHeader.biCompression = BI_RGB;
    
    if(format == PixelFormat16bppRGB565){
        DWORD mask[3] = {0xF800, 0x07E0, 0x001F};
        memcpy(&pbmi->bmiColors, mask, sizeof(mask));
    }
    else if(bpp <= 8){
        int p_sz = Bmp2->GetPaletteSize();
        ColorPalette *pal;
        pal = (ColorPalette*) new BYTE [p_sz];
        st = Bmp2->GetPalette(pal, p_sz);
        if(st == Ok){
            for(UINT i=0;i<pal->Count;i++){
                pbmi->bmiColors[i].rgbRed      = (BYTE) (pal->Entries[i] >> 16);
                pbmi->bmiColors[i].rgbGreen    = (BYTE) (pal->Entries[i] >> 8);
                pbmi->bmiColors[i].rgbBlue     = (BYTE) pal->Entries[i];
                pbmi->bmiColors[i].rgbReserved = 0;
            }
        }
        delete[] (LPBYTE) pal;
        pal = NULL;
        if(st != Ok){
            MessageBox (NULL,"パレットを設定できません",MYWNDTITLE,MB_OK);
            delete [] (LPBYTE) pbmi;
            pbmi = NULL;
            return st;
        }
    }
    
    st = Bmp2->LockBits(&rect, ImageLockModeRead, format, &bitmapData);
    if (st == Ok)
    {
        BYTE    *pixels1;
        int     x,y,y2;
        
        pixels1 = (LPBYTE) bitmapData.Scan0;
        
        int stride1 = abs(bitmapData.Stride);
    
        pbits_sz = stride1 * hgt * sizeof(BYTE);
        pbmi->bmiHeader.biSizeImage = pbits_sz;
        pbits = new BYTE [pbits_sz];
        
        for(y=0;y<hgt;y++){
            if(bitmapData.Stride < 0){
                y2 = y;
            }
            else{
                y2 = hgt - y - 1;
            }
            if(bpp >= 8){
                for(x=0;x<wdh*(bpp/8);x++){
                    pbits[y*stride1+x] = pixels1[y2*stride1+x];
                }
            }
            else{
                for(x=0;x<wdh;x++){
                    pbits[y*stride1+x/(8/bpp)] = pixels1[y2*stride1+x/(8/bpp)];
                }
            }
        }
        st = Bmp2->UnlockBits(&bitmapData);
    }
    if(st != Ok){
        MessageBox (NULL,"Bmp Lock or Unlock Error",MYWNDTITLE,MB_OK);
        delete [] (LPBYTE) pbits;
        pbits = NULL;
        delete [] (LPBYTE) pbmi;
        pbmi = NULL;
        return st;
    }
    
    OpenClipboard(NULL);
    hMem = GlobalAlloc(GMEM_MOVEABLE, pbmi_sz + pbits_sz);
    buf = (LPBYTE) GlobalLock(hMem);
    memcpy(buf, pbmi, pbmi_sz);
    memcpy(buf + pbmi_sz, pbits, pbits_sz);
    EmptyClipboard ();
    SetClipboardData(CF_DIB, hMem);
    GlobalUnlock(hMem);
    CloseClipboard();
    delete [] (LPBYTE) pbits;
    pbits = NULL;
    delete [] (LPBYTE) pbmi;
    pbmi = NULL;

    return Ok;
}// Set_ClipBoard_DIB

4.数式のグラフ

y = √(x/100) を表示する
#include <windows.h>
#include <stdio.h>
#include <math.h>
#include <gdiplus.h>

case WM_PAINT:
    {
        HDC             hDC;
        PAINTSTRUCT     ps;
        hDC = BeginPaint(hWnd,&ps);
        // 描画
        const int wdh = 120;
        const int hgt = 120;
        Bitmap Bmp(wdh,hgt,PixelFormat24bppRGB);
        Graphics gBmp(&Bmp);
        Region rgn(Rect(0, 0, wdh, hgt));
        gBmp.FillRegion(&SolidBrush(Color(255,255,255)), &rgn);
        gBmp.SetSmoothingMode(SmoothingModeAntiAlias);
        Pen pen(Color(0,0,0),1);
        gBmp.DrawLine(&pen, 0, 0, wdh, 0);
        gBmp.DrawLine(&pen, 0, 0, 0, hgt);
        Point   pt[wdh];
        int     x;
        for(x=0;x<wdh;x++){
            pt[x].X = x;
            pt[x].Y = (int)sqrt(x*100);
        }
        gBmp.DrawCurve(&pen, pt, wdh);
        Graphics    g(hDC);
        g.DrawImage(&Bmp, 0, 0, wdh, hgt);
        EndPaint(hWnd,&ps);
    }
    break;

5.