007-05  前へ←  ホームへ  →次へ  007-07

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 です。

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

・選択範囲を表示するのに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 = &gt_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 = &gt_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;
}


 007-05  前へ←  ホームへ  →次へ  007-07