007-04  前へ←  ホームへ  →次へ  007-06

No.007 - 05  半透明処理


半透明処理を行います。
パレット型の半透明も少しやります。


半透明処理
半透明を扱うのにどこでその透明度を指定するかという問題があります。
画像クラス側のメンバ変数で指定するのか、それとも矩形コピーや、矩形塗りつぶしなどの関数呼び出し時に指定するのか。

正解は両方です。
画像クラス側のメンバ変数 + 関数呼び出し時の引数指定 のあわせ技です。

画像クラス側のメンバ変数で扱う透明度は「アルファ値」。
関数呼び出し時の引数には画像全体をどれくらいの透明度で描画するかという「rate」引数を与えます。

アルファ値、rate引数、共に0〜255です。255で不透明、0で透明になります。


アルファ値は別のメモリ
半透明を扱うのでアルファ値メモリのことを考えます。
アルファ値は1ピクセル毎に付けられる透明度です。

アルファ値のメモリは32bit画像の4バイト目?とか考えがちですが、そういうわけにいきません。
ピクセル・メモリとは別の領域に確保します。
大きな理由はこうです。
1.ビットマップとの互換を保つため。(ビットマップに通常アルファ値はないので)
2.ピクセル・メモリと同一メモリにすると一回り大きな連続メモリが必要になってしまう。
3.ピクセル・メモリと同一メモリにすると画像作成後にアルファ値を生成するときや、途中でアルファ値を破棄する時にメモリ再配置が必要になる。

前回までの画像クラスに暗黙的に m_alpha っていうメンバ変数がはいっていましたが、これです。
このポインタにメモリ確保します。

今回のサンプルソースでは半透明の矩形塗りつぶしだけなのでアルファ値使いませんが、次回「矩形コピー」への布石と思ってください。


アルファ値の反復子
1ピクセル進めるとアルファ値側のポインタも1つ進めなければなりません。
とはいえ何万回もくりかえすピクセル操作でいちいちif を使うわけにもいきません。
そこでアルファ値も template でアルファ値のあるときと無いときをうまくコンパイル時に展開されるようにしようってことです。

具体的にはピクセル反復子を宣言するときの template 第二定数をアルファ値の有無にしてやります。


色のブレンド
通常半透明というと元の画像の上にうっすらと透明なパネルとかがあるのをイメージすると思います。
あれは透明なパネルの色と元の画像の色を1ピクセルずつ混ぜています。
かなり面倒ですが、そんなに難しい話ではない(アルゴリズム的にも)です。
ただ色を混ぜないとき、混ぜたくないときもあるので、そこはflag 引数で各場面にて使い分けます。

以下のサンプルソースで、色を混ぜないときのrate引数って一瞬意味あんの?って思うかもしれませんが意味有ります。
渡されたr, g, b 引数にrate 率を掛けた色合いで塗りつぶしを行います。


色パレットと半透明を可能にする
ビット深度16bit 以上の画像ならRGB値が個別にあるので半透明操作は滞り無く処理できます。
でも8bit以下のパレット型は256色以下しか使えず、半透明をパレット型に適用するのは一見難しそうです。
実際PNGファイルではパレット型に半透明を使うコトはできません。

でも8bitもあれば十分なグレスケールが作れるはずなのだから諦めるのは尚早です。
近似色を求めるルーチンに少し手を加えてやれば意外とカンタンです。
(とはいいつつも近似色を求めるルーチンはどうしても遅くなるので、強くはおすすめしませんが)

以下のサンプルソースでは16bit以上の他、4bit と 8bit の半透明処理まで可能です。
1bit画像だけできません(モノクロなので)




サンプル解説 
下記サンプルソースは6つのファイルから成っています

ピクセル反復子や、パレット(色テーブル)クラスを定義するヘッダの gt_img_parts.h と、
定数を定義している resource_05.h と、
画像クラスを定義している gt_img_05.h
リソーススクリプトの gt_img_05.rc
BMPファイルを読み書きするgt_img_bmp_io.cpp
メインファイルの gt_img_05.cpp です。

gt_img_parts.hファイルは007-02のものと全く同じものを使います。ここには書きませんのでご注意ください。
gt_img_bmp_io.cppファイルは007-04のモノの中身は同じものを使います。ここには書きませんのでご注意ください。
#include "gt_img_04.h"  を   #include "gt_img_05.h"   に変えてください)




メニューから何かファイルを開いて、マウスをドラッグすると半透明矩形塗りつぶしが出来ます。
透明度は最初50%に設定されていますが、メニューから透明度を選択してください。

4bit , 8bit 画像では透明度をうまく調整しないと半透明にならないことがあります(色数が少ないので)。



↑24ビット画像での半透明塗りつぶし ↑8ビット画像での半透明塗りつぶし



resource_05.h

#define IDM_MAKE_DIB_0      1000
#define IDM_MAKE_DIB_1      1001
#define IDM_MAKE_DIB_4      1004
#define IDM_MAKE_DIB_8      1008
#define IDM_MAKE_DIB_16     1016
#define IDM_MAKE_DIB_24     1024
#define IDM_MAKE_DIB_32     1032

#define IDM_OPEN            2000
#define IDM_LOAD_DIB        2001
#define IDM_SAVE_DIB        2002

#define IDM_COL             3000

#define IDM_ALPHA_100       4100
#define IDM_ALPHA_90        4090
#define IDM_ALPHA_80        4080
#define IDM_ALPHA_70        4070
#define IDM_ALPHA_60        4060
#define IDM_ALPHA_50        4050
#define IDM_ALPHA_40        4040
#define IDM_ALPHA_30        4030
#define IDM_ALPHA_20        4020
#define IDM_ALPHA_10        4010
#define IDM_ALPHA_0         4000


gt_img_04.rc

#include "resource_05.h"

//リソーススクリプト
GT_DIB_MENU MENU {
    POPUP "ファイル" {
        POPUP "作成" {
            MENUITEM "1 bit" , IDM_MAKE_DIB_1
            MENUITEM "4 bit" , IDM_MAKE_DIB_4
            MENUITEM "8 bit" , IDM_MAKE_DIB_8
            MENUITEM "16 bit", IDM_MAKE_DIB_16
            MENUITEM "24 bit", IDM_MAKE_DIB_24
            MENUITEM "32 bit", IDM_MAKE_DIB_32
        }
        MENUITEM "ひらく",      IDM_OPEN
        MENUITEM "保存",        IDM_SAVE_DIB
    }
    MENUITEM "色",              IDM_COL
    POPUP "透明度" {
        MENUITEM "不透明",      IDM_ALPHA_100
        MENUITEM "90%",         IDM_ALPHA_90
        MENUITEM "80%",         IDM_ALPHA_80
        MENUITEM "70%",         IDM_ALPHA_70
        MENUITEM "60%",         IDM_ALPHA_60
        MENUITEM "50%",         IDM_ALPHA_50
        MENUITEM "40%",         IDM_ALPHA_40
        MENUITEM "30%",         IDM_ALPHA_30
        MENUITEM "20%",         IDM_ALPHA_20
        MENUITEM "10%",         IDM_ALPHA_10
        MENUITEM "0%",          IDM_ALPHA_0
    }
}


gt_img_05.h
// 半透明操作

#include <stdio.h>
#include <windows.h>
#include "resource_05.h"
#include "gt_img_parts.h"

// ======== GT_IMG ==================================
class GT_IMG {
    public :
    GT_COL_TABLE m_col_table;
    unsigned long *m_col_mask;
    char *m_alpha;

    int m_width, m_height, m_byte_width, m_bit_count;
    BYTE *m_pbits;

    GT_IMG();
    virtual ~GT_IMG();

    // 作成と破棄
    virtual destroy();
    virtual create(int cx, int cy, int a_bit_count, int a_color_size=0);

    // ピクセル描画
    set_pixel(int x, int y, DWORD col);
    DWORD get_pixel(int x, int y);

    // アルファ値
    is_alpha(){ return (m_alpha!=NULL); }

    // 半透明用フラグ定数
    enum { ID_BLEND=0, ID_NOBLEND=1 };

    // 矩形塗りつぶし
    fill(int x, int y, int cx, int cy, BYTE r, BYTE g, BYTE b, int rate=255, int flag=ID_BLEND);
    template <int d_bit> void fill_pixput(int x, int y, int cx, int cy, BYTE r, BYTE g, BYTE b, int rate, int flag);

    // カラー
    set_col_mask(UINT r, UINT g, UINT b);
    void set_pal_col(BYTE index, BYTE r, BYTE g, BYTE b);

    // 読込
    load_dib(char *filename);
    load_dib_rle4(HANDLE hfile);    // 4bit ランレングス圧縮
    load_dib_rle8(HANDLE hfile);    // 8bit ランレングス圧縮

    // 書込み
    save_dib(char *filename, int rle_compress_flag=0);
    save_dib_rle4(HANDLE hfile);    // 4bit ランレングス圧縮
    save_dib_rle8(HANDLE hfile);    // 8bit ランレングス圧縮

};

//==========矩形描画==========
// 矩形塗りつぶしのインライン・テンプレート
template <int d_bit> inline void 
GT_IMG::fill_pixput(int x, int y, int cx, int cy, BYTE r, BYTE g, BYTE b, int rate, int flag){
    PIXEL_ITR<d_bit,0> d_pix;
    d_pix.init(m_pbits, m_alpha, m_byte_width, m_width, m_height, &m_col_table);
    if (rate<0) rate=0;
    if (rate>=255) rate=255;
    int ix, iy;
    BYTE col_index;
    if (d_bit<=8 && rate>=255){ // (パレット版・不透明) 
        col_index=m_col_table.get_col_index<d_bit>(r*rate/255, g*rate/255, b*rate/255);
        for(iy=0;iy<cy;iy++){
            d_pix.set_pos(x, y+iy);
            for(ix=0;ix<cx;ix++){ d_pix.set_col(col_index); d_pix++; }
        }
    }
    else if (flag & ID_NOBLEND) {   // 色ブレンド無し
        for(iy=0;iy<cy;iy++){
            d_pix.set_pos(x, y+iy);
            for(ix=0;ix<cx;ix++){ d_pix.set_col_no_blend(r, g, b, rate); d_pix++; }
        }
    }
    else {  // 色ブレンド有り
        for(iy=0;iy<cy;iy++){
            d_pix.set_pos(x, y+iy);
            for(ix=0;ix<cx;ix++){ d_pix.set_col(r, g, b, rate); d_pix++; }
        }
    }
};
// 矩形塗りつぶし
GT_IMG::fill(int x, int y, int cx, int cy, BYTE r, BYTE g, BYTE b, int rate, int flag){
    if (!m_pbits) return -1;

    if (cx<0) { x+=cx; cx=-cx; };
    if (cy<0) { y+=cy; cy=-cy; };

    // マイナス座標の補正
    if (x<0) { cx+=x; x=0; };
    if (y<0) { cy+=y; y=0; };
    // 限界コピー幅の補正
    if ((x+cx)>=m_width) { cx=m_width -x;};
    if ((y+cy)>=m_height){ cy=m_height-y;};

    // コピー
    switch(m_bit_count){
    case 1 : fill_pixput<1> (x, y, cx, cy, r, g, b, rate, flag);     break;
    case 4 : fill_pixput<4> (x, y, cx, cy, r, g, b, rate, flag);     break;
    case 8 : fill_pixput<8> (x, y, cx, cy, r, g, b, rate, flag);     break;
    case 16: fill_pixput<16>(x, y, cx, cy, r, g, b, rate, flag);     break;
    case 24: fill_pixput<24>(x, y, cx, cy, r, g, b, rate, flag);     break;
    case 32: fill_pixput<32>(x, y, cx, cy, r, g, b, rate, flag);     break;
    }
    return 0;
}

// コンストラクタ
GT_IMG::GT_IMG(){
    m_col_mask =NULL;
    m_alpha =NULL;
    m_width = m_height = m_byte_width = m_bit_count =0;
    m_pbits =NULL;
}
// デストラクタ
GT_IMG::~GT_IMG(){
    destroy();
}
// GIMG 破棄
GT_IMG::destroy(){
    m_width=0;
    m_height=0;
    m_byte_width=0;
    m_bit_count=0;
    if (m_pbits) delete[] m_pbits;
    m_pbits = NULL;
    if (m_col_mask) delete[] m_col_mask;
    m_col_mask = NULL;
    m_col_table.destroy();
    return 0;
};
// GIMG 作成
GT_IMG::create(int cx, int cy, int a_bit_count, int a_color_size){
    int i, palette_len, info_size;
    destroy();  // ファイルが開けたら既存データ破棄

    if (cx<=0 || cy<=0) return -1;
    if (a_bit_count!=1 && a_bit_count!=4 && a_bit_count!=8
        && a_bit_count!=16 && a_bit_count!=24 && a_bit_count!=32) return -1;

    if (a_bit_count<=8 && a_color_size==0)  palette_len=1<<a_bit_count; // 8bit以下でパレット色数指定無しなら
    else palette_len=a_color_size;

    // パレット・メモリ確保
    m_col_table.make(palette_len);

    /* バッファの1ラインの長さを計算 */
    m_byte_width=4*((cx*a_bit_count+31)/32);
    m_pbits = new BYTE[m_byte_width*cy];
    ZeroMemory(m_pbits, m_byte_width*cy);

    if (!m_pbits) return -1;
    m_width= cx;
    m_height=cy;
    m_bit_count=a_bit_count;

    // パレット自動配色
    // 適当な基本色
    RGBTRIPLE rgb[8]={
        {0,0,0},{255, 255, 255}, {0,0,255}, {255,0,0}, {0,255,0}, {255, 255,0}, {255,0,255},{0,255,255}
    };

    for(i=0;i<min(palette_len, 8);i++){
        m_col_table.add_col(rgb[i].rgbtRed, rgb[i].rgbtGreen, rgb[i].rgbtBlue);
    }

    return 0;
}
// パレットに色設定
inline void GT_IMG::set_pal_col(BYTE index, BYTE r, BYTE g, BYTE b){
    if (m_col_table.m_cols_len<=index) return ;
    m_col_table.set_col(index, r, g, b);
}
// カラーマスク設定
GT_IMG::set_col_mask(UINT r, UINT g, UINT b){
    if (!m_col_mask) m_col_mask = new unsigned long[3];
    m_col_mask[0] = r;
    m_col_mask[1] = g;
    m_col_mask[2] = b;
}
// 1点ピクセル取得
DWORD GT_IMG::get_pixel(int x, int y){
    if (!m_pbits) return 0;
    if (x<0 || x>=m_width || y<0 || y>=m_height) return 0;
    BYTE *ppix;
    ppix=m_pbits+(m_height-y-1)*m_byte_width + (x*m_bit_count>>3);

    switch(m_bit_count){
    case 1: return 0x01 & (*ppix >> (7-(x&7)));
    case 4: return 0x0f & (*ppix >> ((x&1)?0:4));
    case 8: return *ppix ;
    case 16: return *(WORD*)ppix;
    case 24: return 0x00FFffFF & *(DWORD*)ppix;
    case 32: return *(DWORD*)ppix ;
    }
    return 0;
}
// 1点ピクセル書きこみ
GT_IMG::set_pixel(int x, int y, DWORD col){
    if (!m_pbits) return 0;
    if (x<0 || x>=m_width || y<0 || y>=m_height) return 0;
    BYTE *ppix;
    ppix=m_pbits+(m_height-y-1)*m_byte_width + (x*m_bit_count>>3);

    switch(m_bit_count){
    case 1: *ppix &= ~(1         <<(7-(x&7)));
            *ppix |= ((bool)col) <<(7-(x&7));
            break;
    case 4: *ppix &= 0x0f << ((x&1)?4:0);
            *ppix |= (0x0f & col)  << ((x&1)?0:4);
            break;
    case 8: *ppix = (BYTE)col;                          break;
    case 16: *(WORD*)ppix = (WORD)col;                  break;
    case 24: *(RGBTRIPLE*)ppix = *(RGBTRIPLE*)&col;     break;
    case 32: *(DWORD*)ppix = *(DWORD*)&col;             break;
    }
    return 0;
}

// ======== GT_DIB ==================================
class GT_DIB : public GT_IMG{
    public :
    HDC m_hdc;
    HBITMAP m_hbmp;

    GT_DIB();
    ~GT_DIB();

    // DC 適用
    apply_dc(HDC hdc);
    apply_dc(HWND hwnd);

    // 作成と破棄
    create(int cx, int cy, int a_bit_count, int a_color_size=0);
    virtual destroy();

    // カラー
    apply_palette_all();
    void set_pal_col(BYTE index, BYTE r, BYTE g, BYTE b);

};
// コンストラクタ
GT_DIB::GT_DIB(){
    m_hdc = NULL;
    m_hbmp = NULL;
}
// デストラクタ
GT_DIB::~GT_DIB(){
    destroy();
}
// HDCパレット設定(全て)
GT_DIB::apply_palette_all(){
    if (!m_col_table.m_cols_len) return -1;
    RGBQUAD *p_rgb, *rgb_table;
    rgb_table=new RGBQUAD[m_col_table.m_cols_len];
    for (int i=0;i<m_col_table.m_cols_len;i++){
        p_rgb=&(rgb_table[i]);
        p_rgb->rgbRed   =m_col_table.m_cols[i].m_r;
        p_rgb->rgbGreen =m_col_table.m_cols[i].m_g;
        p_rgb->rgbBlue  =m_col_table.m_cols[i].m_b;
        p_rgb->rgbReserved=0;
    }
    if (m_hdc) SetDIBColorTable(m_hdc, 0, m_col_table.m_cols_len, rgb_table);
    delete[] rgb_table;
    return 0;
}
// パレットに色設定
inline void GT_DIB::set_pal_col(BYTE index, BYTE r, BYTE g, BYTE b){
    if (m_col_table.m_cols_len<=index) return ;
    m_col_table.set_col(index, r, g, b);

    RGBQUAD rgb;
    rgb.rgbRed      =r;
    rgb.rgbGreen    =g;
    rgb.rgbBlue     =b;
    rgb.rgbReserved =0;
    if (m_hdc) SetDIBColorTable(m_hdc, index, 1, &rgb);
}

// DC有効化
GT_DIB::apply_dc(HDC hdc){
    if (m_hdc) { DeleteDC(m_hdc);   m_hdc=NULL; }
    m_hdc = CreateCompatibleDC(hdc);
    SelectObject(m_hdc, m_hbmp);
    return 0;
}
// DC有効化(HWND hwnd) 
GT_DIB::apply_dc(HWND hwnd){
    if (m_hdc) { DeleteDC(m_hdc);   m_hdc=NULL; }
    HDC hwnd_hdc = GetDC(hwnd);
    m_hdc = CreateCompatibleDC(hwnd_hdc);
    SelectObject(m_hdc, m_hbmp);
    ReleaseDC(hwnd, hwnd_hdc);
    return 0;
}

// 破棄
GT_DIB::destroy(){
    if (m_hdc)      { DeleteDC(m_hdc);  m_hdc=NULL; }
    if (m_hbmp)     { DeleteObject(m_hbmp); m_hbmp=NULL; }
//  if (m_pbits) delete[] m_pbits;
    m_pbits = NULL;
    m_width=0;
    m_height=0;
    m_byte_width=0;
    m_bit_count=0;
    if (m_col_mask) delete[] m_col_mask;
    m_col_mask = NULL;
    m_col_table.destroy();
    return 0;
}
// 作成
GT_DIB::create(int cx, int cy, int a_bit_count, int a_color_size){
    BITMAPINFO *bmp_info;
    int i, palette_entry, info_size;
    destroy();  // 作成済みメモリを破棄する

    if (cx<=0 || cy<=0) return -1;
    if (a_bit_count!=1 && a_bit_count!=4 && a_bit_count!=8
        && a_bit_count!=16 && a_bit_count!=24 && a_bit_count!=32) return -1;

    palette_entry=1;
    if      (a_color_size!=0) palette_entry=a_color_size;
    else if (a_bit_count<=8)  palette_entry=1<<a_bit_count; // 8bit以下でパレット色数指定無しなら

    info_size=sizeof(BITMAPINFOHEADER) + (palette_entry-1)*sizeof(RGBQUAD)+1;
    bmp_info = (BITMAPINFO*)malloc(info_size);
    if (!bmp_info) return -1;
    ZeroMemory(bmp_info, info_size);

    // 適当な基本色
    RGBTRIPLE rgb[8]={
        {0,0,0},{255, 255, 255}, {0,0,255}, {255,0,0}, {0,255,0}, {255, 255,0}, {255,0,255},{0,255,255}
    };

    m_col_table.make(palette_entry);
    for(i=0;i<min(palette_entry, 8);i++){
        bmp_info->bmiColors[i].rgbBlue  = rgb[i].rgbtBlue;
        bmp_info->bmiColors[i].rgbGreen = rgb[i].rgbtGreen;
        bmp_info->bmiColors[i].rgbRed   = rgb[i].rgbtRed;
        bmp_info->bmiColors[i].rgbReserved = 0;
        m_col_table.add_col(rgb[i].rgbtRed, rgb[i].rgbtGreen, rgb[i].rgbtBlue);
    }

    /* BITMAPINFO構造体設定 */
    bmp_info->bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
    bmp_info->bmiHeader.biWidth=cx;
    bmp_info->bmiHeader.biHeight=cy;
    bmp_info->bmiHeader.biPlanes=1;
    bmp_info->bmiHeader.biBitCount=a_bit_count;
    bmp_info->bmiHeader.biCompression=BI_RGB;
    bmp_info->bmiHeader.biSizeImage=0;
    bmp_info->bmiHeader.biXPelsPerMeter=0;
    bmp_info->bmiHeader.biYPelsPerMeter=0;
    bmp_info->bmiHeader.biClrUsed=palette_entry;
    bmp_info->bmiHeader.biClrImportant=0;

    m_hbmp = CreateDIBSection(NULL, bmp_info, DIB_RGB_COLORS, (VOID**)&m_pbits, NULL, 0);
    if (!m_hbmp) {
        free(bmp_info);
        return -1;
    }
    m_width= cx;
    m_height=cy;
    m_bit_count=a_bit_count;

    /* バッファの1ラインの長さを計算 */
    m_byte_width=4*((m_width*m_bit_count+31)/32);
    ZeroMemory(m_pbits, m_byte_width*m_height);

    free(bmp_info);
    return 0;
}


gt_img_05.cpp
// 半透明操作

#include <stdio.h>
#include <windows.h>
#include "resource_05.h"
#include "gt_img_05.h"

GT_DIB gt_dib_1;
static OPENFILENAME ofn = {0};
static char filename[MAX_PATH];

CHOOSECOLOR cc = {0};
COLORREF color = 0, col_costom[16];
int col_index = 0;
BYTE r=0, g=255, b=255;
int rate=50*255/100;    // 50%
POINT start_po, end_po;

// メニュー
on_command(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp){
    static CHOOSECOLOR cc = {0};
    static DWORD col_costom[8] = {0};
    switch(LOWORD(wp)) {
    case IDM_MAKE_DIB_0:
    case IDM_MAKE_DIB_1:
    case IDM_MAKE_DIB_4:
    case IDM_MAKE_DIB_8:
    case IDM_MAKE_DIB_16:
    case IDM_MAKE_DIB_24:
    case IDM_MAKE_DIB_32:
        gt_dib_1.create(201, 151, LOWORD(wp)-IDM_MAKE_DIB_0, 0);
        gt_dib_1.apply_dc(hwnd);
        InvalidateRect(hwnd, NULL, 0);
        break;
    case IDM_OPEN:
        ofn.Flags = OFN_FILEMUSTEXIST;
        if (!GetOpenFileName(&ofn)) break;
        gt_dib_1.load_dib(filename);
        gt_dib_1.apply_dc(hwnd);
        gt_dib_1.apply_palette_all();
        InvalidateRect(hwnd, NULL, 1);
        break;
    case IDM_SAVE_DIB:
        ofn.Flags = 0;
        if (!GetSaveFileName(&ofn)) break;
        gt_dib_1.save_dib(filename);
        break;
    case IDM_COL:
        cc.lStructSize  = sizeof (CHOOSECOLOR);
        cc.hwndOwner    = hwnd;
        cc.rgbResult    = color;
        cc.lpCustColors = col_costom;
        cc.Flags    = CC_FULLOPEN | CC_RGBINIT;
        if (!ChooseColor(&cc)) break;
        color = cc.rgbResult;
        r = GetRValue(color);
        g = GetGValue(color);
        b = GetBValue(color);

        // パレット
        col_index = 0;
        switch(gt_dib_1.m_bit_count) {
        case 1 : gt_dib_1.m_col_table.get_col_index<1>(r,g,b); break;
        case 4 : gt_dib_1.m_col_table.get_col_index<4>(r,g,b); break;
        case 8 : gt_dib_1.m_col_table.get_col_index<8>(r,g,b); break;
        }
        gt_dib_1.apply_palette_all();
        break;
    case IDM_ALPHA_100:
    case IDM_ALPHA_90 :
    case IDM_ALPHA_80 :
    case IDM_ALPHA_70 :
    case IDM_ALPHA_60 :
    case IDM_ALPHA_50 :
    case IDM_ALPHA_40 :
    case IDM_ALPHA_30 :
    case IDM_ALPHA_20 :
    case IDM_ALPHA_10 :
    case IDM_ALPHA_0  :
        rate = ((LOWORD(wp) - IDM_ALPHA_0)*255)/100;
    }
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) {
    HDC hdc;
    PAINTSTRUCT ps;
    POINT po;
    static char s[50];
    RECT rc;
    HRGN hrgn, hrgn2;
    static POINT mou_po, po_array[4];
    static int mou_down=0;

    switch (msg) {
    case WM_PAINT:
        hdc = BeginPaint(hwnd, &ps);
        if (gt_dib_1.m_hdc){
            BitBlt( hdc, 20, 20, gt_dib_1.m_width, gt_dib_1.m_height, gt_dib_1.m_hdc, 0, 0, SRCCOPY);
        }
        sprintf(s, "  ヨコ %d X タテ %d  %dビット",
                gt_dib_1.m_width, gt_dib_1.m_height, gt_dib_1.m_bit_count);
        GetClientRect(hwnd , &rc);
        rc.top=gt_dib_1.m_height+20;
        DrawText(hdc, s, -1, &rc, DT_WORDBREAK );
        EndPaint(hwnd, &ps);
        break;
    case WM_COMMAND:
        on_command(hwnd, msg, wp, lp);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    case WM_CREATE:
        ofn.lStructSize = sizeof (OPENFILENAME);
        ofn.hwndOwner = hwnd;
        ofn.lpstrFilter =   
                    TEXT("bmp files {*.bmp}\0*.bmp\0")
                    TEXT("All files {*.*}\0*.*\0\0");
        ofn.lpstrCustomFilter = NULL;
        ofn.nMaxCustFilter = 0;
        ofn.nFilterIndex = 0;
        ofn.lpstrFile = filename;
        ofn.nMaxFile = MAX_PATH;
        ofn.Flags = OFN_FILEMUSTEXIST;
        break;
    case WM_LBUTTONDOWN:
        if (!mou_down){
            GetCursorPos(&start_po);
            ScreenToClient(hwnd, &start_po);
            mou_down=1;
        }
        break;
    case WM_LBUTTONUP:
        if (mou_down){
            mou_down=0;
            GetCursorPos(&end_po);
            ScreenToClient(hwnd, &end_po);
            gt_dib_1.fill(start_po.x-20, start_po.y-20,
                    end_po.x-start_po.x, end_po.y-start_po.y, r, g, b, rate);
            InvalidateRect(hwnd, NULL, 1);
        }
        mou_down=0;
        break;
    case WM_MOUSEMOVE:
        if (mou_down){
            hdc=GetDC(hwnd);
            GetClientRect(hwnd , &rc);
            if (mou_down==2){
                po_array[0] = po_array[3] = start_po;
                po_array[1] = po_array[2] = mou_po;
                po_array[1].y=start_po.y;   po_array[3].y=mou_po.y;
                hrgn = CreatePolygonRgn(po_array , 4 , WINDING);
                SelectObject(hdc, hrgn);        
                PatBlt(hdc,  0, 0, rc.right, rc.bottom, PATINVERT);
                DeleteObject(hrgn);
            }
            mou_down=2;

            GetCursorPos(&mou_po);
            ScreenToClient(hwnd, &mou_po);
            po_array[0] = po_array[3] = start_po;
            po_array[1] = po_array[2] = mou_po;
            po_array[1].y=start_po.y;   po_array[3].y=mou_po.y;
            hrgn2 = CreatePolygonRgn(po_array , 4 , WINDING);
            SelectObject(hdc, hrgn2);       
            PatBlt(hdc,  0, 0, rc.right, rc.bottom, PATINVERT);
            DeleteObject(hrgn2);
            ReleaseDC(hwnd, hdc);
        }
        break;
    }
    return DefWindowProc(hwnd, msg, wp, lp);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,    PSTR lpCmdLine, int nCmdShow) {
    HWND hwnd;
    MSG msg;
    WNDCLASS winc;

    winc.style      = CS_HREDRAW | CS_VREDRAW;
    winc.lpfnWndProc    = WndProc;
    winc.cbClsExtra = winc.cbWndExtra   = 0;
    winc.hInstance      = hInstance;
    winc.hIcon      = LoadIcon(NULL, IDI_APPLICATION);
    winc.hCursor        = LoadCursor(NULL, IDC_ARROW);
    winc.hbrBackground  = (HBRUSH)GetStockObject(WHITE_BRUSH);
    winc.lpszMenuName   = TEXT("GT_DIB_MENU");
    winc.lpszClassName  = TEXT("GT_IMG");

    if (!RegisterClass(&winc)) return 1;

    hwnd = CreateWindow(
            TEXT("GT_IMG"), TEXT("半透明操作"), WS_OVERLAPPEDWINDOW | WS_VISIBLE, 
            CW_USEDEFAULT, CW_USEDEFAULT, 400, 300, 
            NULL, NULL, hInstance, NULL
    );

    if (hwnd == NULL) return 1;

    while (GetMessage(&msg, NULL, 0, 0 )) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return msg.wParam;
}


 007-04  前へ←  ホームへ  →次へ  007-06