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 です。
|
|||
メニューから何かファイルを開いて、マウスをドラッグすると半透明矩形塗りつぶしが出来ます。 透明度は最初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; } |