No.007 - 06 矩形コピー |
画像から画像への矩形コピーを行います。 おなじみのコピー&貼り付けですが、異なるビット深度における変換をココでは比較的らくに実装できてます。 |
・ビット深度の変換組み合わせ |
|||
画像編集ソフトではおなじみのコピペですが、実際プログラムを組む側にまわると想像以上に面倒くさいことがわかります。 007-02 でも書いた事ですが 真正面からコーディングすると異なるビット深度間の変換を全ての組み合わせで書く羽目になり大変です。 延々コーディングしてりゃあ、いつかできますがそれではデバッグもだるいのです。 ここでピクセル反復子の出番です。 ピクセル反復子ならtemplateなので定数指定して関数を呼べば、コンパイル時にインライン的に展開されていくので 一個関数書くだけで1bit〜32bit全てのビット深度の変換組み合わせ(36個)の関数が作られるのです。 らくちんです。 ピクセル反復子、本領発揮です。 |
|||
・ビット定数指定 |
|||
template なので矩形コピーも、矩形塗り潰しのとき同様、内部で、定数で指定してやる必要があります。 ただコピー元とコピー先の両方のビット深度が要るので、定数も2つずつ、 その組み合わせ分すべて用意しなければなりません。 from_draw_pixput<1, 1>() from_draw_pixput<1, 4>() from_draw_pixput<1, 8>() ……… ……… from_draw_pixput<8, 32>() from_draw_pixput<16, 1>() from_draw_pixput<16, 4>() ……… ……… from_draw_pixput<32, 24>() from_draw_pixput<32, 32>() |
|||
・AからBに描画するのか、BからAに描画するのか(from_draw と to_draw) |
|||
コピー関数なら単純にdraw()とかcopy()とかいう関数名にすればいいじゃんって思う方もいると思います。 (筆者も最初はそれでやってました) でもそれだとa.draw(b);としたとき a から b に描画するのか、b から a に描画するのかよくわかりません。(通常 b から a ですが) いや最初はわかってるんだけど長い事やってるうちにわからなくなるんです。 それに、a から b に描画する関数も、b から a に描画する関数も両方あるほうが便利だな〜とさえ思いました。 なら明示しちゃえって事で。 「〜から描画」と「〜へ描画」です。 a.from_draw(b); // b から a に描画する(a from b なので) a.to_draw(b); // a から b に描画する(a to b なので) |
|||
・アルファ値の定数指定と、半透明 |
|||
コピー先にコピー元の透明度も反映させながら描画します。 とはいえ、毎回アルファ値があるかないかのフラグを立てながらコピーすれば遅くなるし、 かといって、アルファ値の有無別にメインループ部分を別々に書くのも結構大変です。 (筆者も最初メインループ部分を別々に書いたのですが関数が膨れて泣きそうでした) そこでピクセル反復子自体ににアルファ値の有無を template で付けてやれば実行速度を落とさず メインループ部分もひとつで済みます。 (それでも速度向上のため不透明コピー、半透明コピーでメインループ部分を別々に書いてたりしますが) ではアルファ値の有無をどういうふうに template で定数指定するのか。 ピクセル反復子はビット深度を定数指定する他に、 アルファ値の有無も指定してやらないといけないのですが、 下記サンプルソースでは 実際のコピーを行うメインループの関数from_draw_pixput<a, b>()を呼ぶ前に アルファ値の有無を定数指定するfrom_draw_set_alpha<a, b>()を呼んでいます。 こんな感じです。
|
|||
|
|||
下記サンプルソースは6つのファイルから成っています ピクセル反復子や、パレット(色テーブル)クラスを定義するヘッダの gt_img_parts.h と、 定数を定義している resource_06.h 、 画像クラスを定義している gt_img_06.h、 リソーススクリプトの gt_img_06.rc、 BMPファイルを読み書きするgt_img_bmp_io.cpp 、 メインファイルの gt_img_06.cpp です。
|
|||
・選択範囲を表示するのにPatBltとリージョンで矩形枠描画しています ・今回クリップボードには転送していないので他のアプリケーションに貼り付けできません。 |
|||
画像1と画像2にファイルを読み込んで下さい。 その後マウスでドラッグして 選択範囲を決めて、 右クリックメニューからコピーします そして貼り付けたいところに、右クリックメニューから貼り付けします |
|||
1. とりあえず 最初の状態です。 |
|
2. とにかくなんか ファイルを開きます 左が画像1 右が画像2になります |
|
3. マウス・ドラッグで範囲を選択します そのあと右クリックでコピーします |
|
4. コピーしたいとこにカーソルを合わせ 右クリックメニューで貼り付けします。 サンプル画像では 24bit → 8bit コピーしてます (RGB型→パレットの自動変換) |
resource_06.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_LOAD_DIB 2001 #define IDM_SAVE_DIB 2002 #define IDM_OPEN 2003 #define IDM_OPEN2 2004 #define IDM_COL 3000 #define IDM_COPY 3001 #define IDM_PASTE 3002 #define IDM_FILL 3003 #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_06.rc |
#include "resource_06.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 "画像1にひらく", IDM_OPEN MENUITEM "画像2にひらく", IDM_OPEN2 MENUITEM "保存", IDM_SAVE_DIB } 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_DIB_MENU_R MENU { POPUP "右クリックメニュー" { MENUITEM "コピー", IDM_COPY MENUITEM SEPARATOR MENUITEM "貼り付け", IDM_PASTE } } |
gt_img_06.h |
// 矩形コピー #include <stdio.h> #include <windows.h> #include "resource_06.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); // 矩形コピー from_draw(int x, int y, int cx, int cy, GT_IMG *p_img, int src_x, int src_y, int rate=255, int flag=ID_BLEND); template <int dst_bit, int src_bit> void from_draw_set_alpha(int dst_x, int dst_y, int cx, int cy, GT_IMG *p_img, int src_x, int src_y, int rate, int flag); template <int dst_bit, int dst_alpha, int src_bit, int src_alpha> void from_draw_pixput(int dst_x, int dst_y, int cx, int cy, GT_IMG *p_img, int src_x, int src_y, int rate, int flag); to_draw(int x, int y, int cx, int cy, GT_IMG *p_img, int src_x, int src_y, int rate=255, int flag=ID_BLEND); // カラー set_col_mask(UINT r, UINT g, UINT b); 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 ランレングス圧縮 }; //==========矩形コピー========== // 矩形コピー(to) GT_IMG::to_draw(int dst_x, int dst_y, int cx, int cy, GT_IMG *p_img, int src_x, int src_y, int rate, int flag){ return from_draw(dst_x, dst_y, cx, cy, p_img, src_x, src_y, rate, flag); } // 矩形コピー(from) GT_IMG::from_draw(int dst_x, int dst_y, int cx, int cy, GT_IMG *p_img, int src_x, int src_y, int rate, int flag){ if (!p_img) return -1; if (!p_img->m_pbits || !m_pbits) return -1; // マイナス座標の補正 if (dst_x<0){ cx+= dst_x; src_x-=dst_x; dst_x=0; }; if (dst_y<0){ cy+= dst_y; src_y-=dst_y; dst_y=0; }; if (src_x<0){ cx+= src_x; dst_x-=src_x; src_x=0; }; if (src_y<0){ cy+= src_y; dst_y-=src_y; src_y=0; }; // 限界コピー幅の補正 if ((dst_x+cx)>m_width) { cx= m_width -dst_x;}; if ((dst_y+cy)>m_height) { cy= m_height-dst_y;}; if ((src_x+cx)>p_img->m_width) { cx=p_img->m_width -src_x;}; if ((src_y+cy)>p_img->m_height) { cy=p_img->m_height-src_y;}; switch(m_bit_count){ case 1: switch(p_img->m_bit_count){ case 1: from_draw_set_alpha<1 , 1 >(dst_x, dst_y, cx, cy, p_img, src_x, src_y, rate, flag); break; case 4: from_draw_set_alpha<1 , 4 >(dst_x, dst_y, cx, cy, p_img, src_x, src_y, rate, flag); break; case 8: from_draw_set_alpha<1 , 8 >(dst_x, dst_y, cx, cy, p_img, src_x, src_y, rate, flag); break; case 16: from_draw_set_alpha<1 , 16>(dst_x, dst_y, cx, cy, p_img, src_x, src_y, rate, flag); break; case 24: from_draw_set_alpha<1 , 24>(dst_x, dst_y, cx, cy, p_img, src_x, src_y, rate, flag); break; case 32: from_draw_set_alpha<1 , 32>(dst_x, dst_y, cx, cy, p_img, src_x, src_y, rate, flag); break; } break; case 4: switch(p_img->m_bit_count){ case 1: from_draw_set_alpha<4 , 1 >(dst_x, dst_y, cx, cy, p_img, src_x, src_y, rate, flag); break; case 4: from_draw_set_alpha<4 , 4 >(dst_x, dst_y, cx, cy, p_img, src_x, src_y, rate, flag); break; case 8: from_draw_set_alpha<4 , 8 >(dst_x, dst_y, cx, cy, p_img, src_x, src_y, rate, flag); break; case 16: from_draw_set_alpha<4 , 16>(dst_x, dst_y, cx, cy, p_img, src_x, src_y, rate, flag); break; case 24: from_draw_set_alpha<4 , 24>(dst_x, dst_y, cx, cy, p_img, src_x, src_y, rate, flag); break; case 32: from_draw_set_alpha<4 , 32>(dst_x, dst_y, cx, cy, p_img, src_x, src_y, rate, flag); break; } break; case 8: switch(p_img->m_bit_count){ case 1: from_draw_set_alpha<8 , 1 >(dst_x, dst_y, cx, cy, p_img, src_x, src_y, rate, flag); break; case 4: from_draw_set_alpha<8 , 4 >(dst_x, dst_y, cx, cy, p_img, src_x, src_y, rate, flag); break; case 8: from_draw_set_alpha<8 , 8 >(dst_x, dst_y, cx, cy, p_img, src_x, src_y, rate, flag); break; case 16: from_draw_set_alpha<8 , 16>(dst_x, dst_y, cx, cy, p_img, src_x, src_y, rate, flag); break; case 24: from_draw_set_alpha<8 , 24>(dst_x, dst_y, cx, cy, p_img, src_x, src_y, rate, flag); break; case 32: from_draw_set_alpha<8 , 32>(dst_x, dst_y, cx, cy, p_img, src_x, src_y, rate, flag); break; } break; case 16: switch(p_img->m_bit_count){ case 1: from_draw_set_alpha<16, 1 >(dst_x, dst_y, cx, cy, p_img, src_x, src_y, rate, flag); break; case 4: from_draw_set_alpha<16, 4 >(dst_x, dst_y, cx, cy, p_img, src_x, src_y, rate, flag); break; case 8: from_draw_set_alpha<16, 8 >(dst_x, dst_y, cx, cy, p_img, src_x, src_y, rate, flag); break; case 16: from_draw_set_alpha<16, 16>(dst_x, dst_y, cx, cy, p_img, src_x, src_y, rate, flag); break; case 24: from_draw_set_alpha<16, 24>(dst_x, dst_y, cx, cy, p_img, src_x, src_y, rate, flag); break; case 32: from_draw_set_alpha<16, 32>(dst_x, dst_y, cx, cy, p_img, src_x, src_y, rate, flag); break; } break; case 24: switch(p_img->m_bit_count){ case 1: from_draw_set_alpha<24, 1 >(dst_x, dst_y, cx, cy, p_img, src_x, src_y, rate, flag); break; case 4: from_draw_set_alpha<24, 4 >(dst_x, dst_y, cx, cy, p_img, src_x, src_y, rate, flag); break; case 8: from_draw_set_alpha<24, 8 >(dst_x, dst_y, cx, cy, p_img, src_x, src_y, rate, flag); break; case 16: from_draw_set_alpha<24, 16>(dst_x, dst_y, cx, cy, p_img, src_x, src_y, rate, flag); break; case 24: from_draw_set_alpha<24, 24>(dst_x, dst_y, cx, cy, p_img, src_x, src_y, rate, flag); break; case 32: from_draw_set_alpha<24, 32>(dst_x, dst_y, cx, cy, p_img, src_x, src_y, rate, flag); break; } break; case 32: switch(p_img->m_bit_count){ case 1: from_draw_set_alpha<32, 1 >(dst_x, dst_y, cx, cy, p_img, src_x, src_y, rate, flag); break; case 4: from_draw_set_alpha<32, 4 >(dst_x, dst_y, cx, cy, p_img, src_x, src_y, rate, flag); break; case 8: from_draw_set_alpha<32, 8 >(dst_x, dst_y, cx, cy, p_img, src_x, src_y, rate, flag); break; case 16: from_draw_set_alpha<32, 16>(dst_x, dst_y, cx, cy, p_img, src_x, src_y, rate, flag); break; case 24: from_draw_set_alpha<32, 24>(dst_x, dst_y, cx, cy, p_img, src_x, src_y, rate, flag); break; case 32: from_draw_set_alpha<32, 32>(dst_x, dst_y, cx, cy, p_img, src_x, src_y, rate, flag); break; } break; } return 0; } // 矩形コピーのインライン・テンプレート template <int dst_bit, int src_bit> void GT_IMG::from_draw_set_alpha(int dst_x, int dst_y, int cx, int cy, GT_IMG *p_img, int src_x, int src_y, int rate, int flag){ if (is_alpha()){ if (p_img->is_alpha()) from_draw_pixput<dst_bit, 1, src_bit, 1>(dst_x, dst_y, cx, cy, p_img, src_x, src_y, rate, flag); else from_draw_pixput<dst_bit, 1, src_bit, 0>(dst_x, dst_y, cx, cy, p_img, src_x, src_y, rate, flag); } else { if (p_img->is_alpha()) from_draw_pixput<dst_bit, 0, src_bit, 1>(dst_x, dst_y, cx, cy, p_img, src_x, src_y, rate, flag); else from_draw_pixput<dst_bit, 0, src_bit, 0>(dst_x, dst_y, cx, cy, p_img, src_x, src_y, rate, flag); } } // 矩形コピーのインライン・テンプレート template <int dst_bit, int dst_alpha, int src_bit, int src_alpha> void GT_IMG::from_draw_pixput(int dst_x, int dst_y, int cx, int cy, GT_IMG *p_img, int src_x, int src_y, int rate, int flag){ PIXEL_ITR<dst_bit, dst_alpha> d_pix; PIXEL_ITR<src_bit, src_alpha> s_pix; BYTE *p_alpha; if (rate<0) return ; else if (rate>=255) rate=255; d_pix.init(m_pbits, m_alpha, m_byte_width, m_width, m_height, &m_col_table); s_pix.init(p_img->m_pbits, p_img->m_alpha, p_img->m_byte_width, p_img->m_width, p_img->m_height, &p_img->m_col_table); int ix, iy; if (rate>=255){ // 不透明コピー for(iy=0;iy<cy;iy++){ s_pix.set_pos(src_x, src_y+iy); d_pix.set_pos(dst_x, dst_y+iy); for(ix=0;ix<cx;ix++){ s_pix.to_draw(d_pix); d_pix++;s_pix++; } } } // 半透明コピー else if (flag & ID_NOBLEND) { // 半透明コピー(ブレンド無し) for(iy=0;iy<cy;iy++){ s_pix.set_pos(src_x, src_y+iy); d_pix.set_pos(dst_x, dst_y+iy); for(ix=0;ix<cx;ix++){ s_pix.to_no_blend_draw(d_pix, rate); d_pix++;s_pix++; } } } else { // 半透明コピー(ブレンド有り) for(iy=0;iy<cy;iy++){ s_pix.set_pos(src_x, src_y+iy); d_pix.set_pos(dst_x, dst_y+iy); for(ix=0;ix<cx;ix++){ s_pix.to_blend_draw(d_pix, rate); d_pix++;s_pix++; } } } }; //==========矩形描画========== // 矩形塗りつぶしのインライン・テンプレート 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 GT_IMG::set_pal_col(BYTE index, BYTE r, BYTE g, BYTE b){ if (m_col_table.m_cols_len<=index) return -1; m_col_table.set_col(index, r, g, b); return 0; } // カラーマスク設定 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(); 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(){ return m_col_table.apply_palette_all(m_hdc); } // パレットに色設定 inline GT_DIB::set_pal_col(BYTE index, BYTE r, BYTE g, BYTE b){ return m_col_table.set_pal_col(m_hdc, index, r, g, b); } // 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_06.cpp |
// 矩形コピー #include <stdio.h> #include <windows.h> #include "resource_06.h" #include "gt_img_06.h" GT_DIB gt_dib_1, gt_dib_2, *src_dib=NULL; POINT gt_dib_1_pos, gt_dib_2_pos; int src_x, src_y, copy_cx, copy_cy; static OPENFILENAME ofn = {0}; static char filename[MAX_PATH]; POINT start_po, mou_po; RECT select_range; int select_range_valid=0; int rate=255; // 枠線を反転描画する patblt_rect_frame(HDC hdc, RECT rc){ RECT rc2; HRGN hrgn, hrgn2, hrgn3; rc2.left = rc.left +1; rc2.top = rc.top +1; rc2.right = rc.right -1; rc2.bottom= rc.bottom-1; hrgn = CreateRectRgnIndirect(&rc); hrgn2 = CreateRectRgnIndirect(&rc2); hrgn3 = CreateRectRgn(0,0,0,0); CombineRgn(hrgn3, hrgn, hrgn2, RGN_DIFF); SelectObject(hdc, hrgn3); GetClipBox(hdc, &rc2); PatBlt(hdc, rc2.left, rc2.top, rc2.right, rc2.bottom, PATINVERT); if (hrgn) DeleteObject(hrgn); if (hrgn2) DeleteObject(hrgn2); if (hrgn3) DeleteObject(hrgn3); } // メニュー on_command(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp){ 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); gt_dib_2_pos.x = gt_dib_1.m_width+gt_dib_1_pos.x+20; InvalidateRect(hwnd, NULL, 1); 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); gt_dib_2_pos.x = gt_dib_1.m_width+gt_dib_1_pos.x+20; break; case IDM_OPEN2: ofn.Flags = OFN_FILEMUSTEXIST; if (!GetOpenFileName(&ofn)) break; gt_dib_2.load_dib(filename); gt_dib_2.apply_dc(hwnd); gt_dib_2.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_COPY: if (select_range.left<(gt_dib_1.m_width + gt_dib_1_pos.x)){ src_dib = >_dib_1; src_x = select_range.left - gt_dib_1_pos.x; src_y = select_range.top - gt_dib_1_pos.y; } else { src_dib = >_dib_2; src_x = select_range.left - gt_dib_2_pos.x; src_y = select_range.top - gt_dib_2_pos.y; } select_range_valid = 0; copy_cx = select_range.right-select_range.left; copy_cy = select_range.bottom-select_range.top; InvalidateRect(hwnd, NULL, 1); break; case IDM_PASTE: if (start_po.x<(gt_dib_1.m_width + gt_dib_1_pos.x)){ gt_dib_1.from_draw( start_po.x - gt_dib_1_pos.x, start_po.y - gt_dib_1_pos.y, copy_cx, copy_cy, src_dib, src_x, src_y, rate ); InvalidateRect(hwnd, NULL, 1); } else { gt_dib_2.from_draw( start_po.x - gt_dib_2_pos.x, start_po.y - gt_dib_2_pos.y, copy_cx, copy_cy, src_dib, src_x, src_y, rate ); InvalidateRect(hwnd, NULL, 1); } 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; break; } } LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) { HDC hdc; PAINTSTRUCT ps; static char s[50]; RECT rc; static int mou_down=0; HMENU hmenu_sub, hmenu_parent; switch (msg) { case WM_PAINT: GetClientRect(hwnd , &rc); hdc = BeginPaint(hwnd, &ps); // gt_dib_1 if (gt_dib_1.m_hdc){ BitBlt( hdc, gt_dib_1_pos.x, gt_dib_1_pos.y, gt_dib_1.m_width, gt_dib_1.m_height, gt_dib_1.m_hdc, 0, 0, SRCCOPY); } sprintf(s, "gt_dib_1\nヨコ %d X タテ %d %dビット", gt_dib_1.m_width, gt_dib_1.m_height, gt_dib_1.m_bit_count); rc.left=gt_dib_1_pos.x; rc.top=gt_dib_1.m_height + gt_dib_1_pos.y; if (gt_dib_1.m_hdc)rc.right=gt_dib_1.m_width + gt_dib_1_pos.x; DrawText(hdc, s, -1, &rc, DT_WORDBREAK ); // gt_dib_2 if (gt_dib_2.m_hdc){ BitBlt( hdc, gt_dib_2_pos.x, gt_dib_2_pos.y, gt_dib_2.m_width, gt_dib_2.m_height, gt_dib_2.m_hdc, 0, 0, SRCCOPY); } sprintf(s, "gt_dib_2\nヨコ %d X タテ %d %dビット", gt_dib_2.m_width, gt_dib_2.m_height, gt_dib_2.m_bit_count); GetClientRect(hwnd , &rc); rc.top=gt_dib_2.m_height + gt_dib_2_pos.y; rc.left=gt_dib_2_pos.x; DrawText(hdc, s, -1, &rc, DT_WORDBREAK ); if (select_range_valid) patblt_rect_frame(hdc, select_range); 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; gt_dib_1_pos.x= gt_dib_1_pos.y=20; gt_dib_2_pos.x= 250; gt_dib_2_pos.y= 20; break; case WM_LBUTTONDOWN: if (!mou_down){ hdc=GetDC(hwnd); if (select_range_valid) patblt_rect_frame(hdc, select_range); ReleaseDC(hwnd, hdc); GetCursorPos(&start_po); ScreenToClient(hwnd, &start_po); mou_down=1; } break; case WM_LBUTTONUP: if (mou_down){ mou_down=0; GetCursorPos(&mou_po); ScreenToClient(hwnd, &mou_po); select_range.left = start_po.x; select_range.top = start_po.y; select_range.right = mou_po.x; select_range.bottom= mou_po.y; InvalidateRect(hwnd, NULL, 1); select_range_valid=1; } mou_down=0; break; case WM_RBUTTONUP: hmenu_parent = LoadMenu(GetModuleHandle(NULL), TEXT("GT_DIB_MENU_R")); hmenu_sub = GetSubMenu(hmenu_parent, 0); // 描画位置を保持 GetCursorPos(&start_po); ScreenToClient(hwnd, &start_po); // ポップアップ GetCursorPos(&mou_po); TrackPopupMenu(hmenu_sub, TPM_LEFTALIGN | TPM_TOPALIGN, mou_po.x, mou_po.y, 0, hwnd, NULL); DestroyMenu(hmenu_sub); DestroyMenu(hmenu_parent); break; case WM_MOUSEMOVE: if (mou_down){ hdc=GetDC(hwnd); GetClientRect(hwnd , &rc); if (mou_down==2) patblt_rect_frame(hdc, select_range); mou_down=2; GetCursorPos(&mou_po); ScreenToClient(hwnd, &mou_po); select_range.left = start_po.x; select_range.top = start_po.y; select_range.right = mou_po.x; select_range.bottom= mou_po.y; patblt_rect_frame(hdc, select_range); 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, 600, 280, NULL, NULL, hInstance, NULL ); if (hwnd == NULL) return 1; while (GetMessage(&msg, NULL, 0, 0 )) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } |