007-07  前へ←  ホームへ  →次へ  007-09(1)

No.007 - 08  拡大縮小コピー


拡大縮小コピーです。
直線描画のとき同様 bresenham(ブレゼンハム)の 方法を使って処理を行います


・拡大縮小ルーチンの基本

まず簡単な拡大縮小を考えます。
コピー元のサイズがコピー先のきっちり2倍(コピー先 : コピー元 = 1 : 2 )なら、
コピー先のX座標が1つ進めば、コピー元は2つ進みます

dst_x : コピー先のX座標
dst_cx : コピー先のXサイズ
src_x : コピー元のX座標
src_cx : コピー元のXサイズ
なら
コピー先のX座標が1つ進めば、コピー元の位置は、src_cx/dst_cxだけ進みます


拡大縮小コピーの基本となるルーチンはこちらです。遅いですよ。
基本

for(iy=iy_start;iy<iy_end;iy++){
        d_pix.set_pos(dst_x, dst_y+iy);

        for(ix=ix_start;ix<ix_end;ix++){
                nx = src_x + ix*src_cx/dst_cx;
                ny = src_y + iy*src_cy/dst_cy;
                s_pix.set_pos(nx, ny);
                s_pix.to_draw(d_pix); d_pix++;
        }
}

コピー先とコピー元のサイズが違っても要は、コピー先の範囲が全部埋まりゃあいいので、
コピー先のサイズを基軸にループを作ります。
ix_start”X座標側のループは、ix_start 進んだ状態でスタ−トしますよ”という意味 です。
描画範囲が画像の外まで広がってる時の補正用です。(初期XY座標自体を補正してしまうと、倍率が変化してしまうので)
iy_start も同様です。



・Bresenham で拡大縮小ルーチン(メインループ部分)


上記の基本ルーチン・ソースにおいて、速度低下の原因は明らかに
  nx = src_x + ix*src_cx/dst_cx;
  ny = src_y + iy*src_cy/dst_cy;
の部分です。

Bresenham なので直線描画のとき同 様
割り算を無くすことを考えます。

まず
nxix が1つ増えると、src_cx/dst_cx だけ増えます
つまり
  e += src_cx/dst_cx;
  if (e>1){
          nx++;
          e -= 1;
  }

という計算式が成り立つので、
通常の増減
コピー先の座標が
1個進むと e がsrc_cx/dst_cxだけ
増える
e が 1以上溜まったら
・・・
コピー元の座標が
1個進む
割り算を無くすため両辺にdst_cxを掛けると、
  e += src_cx;
  if (e>dst_cx){
          nx++;
          e -= dst_cx;
  }

と、このようなコードが出来上がります。

さらに
ループ中、コピー先の座標は1つずつしか進みませんが、
コピー元側の座標は2つ進んだり、3つ進んだりするので、
  e += src_cx;
  while (e>dst_cx){
          nx++;
          e -= dst_cx;
  }

と、ifwhile に変えてコピー元側の座標は複数進めるようにします。
Bresenham の増減
コピー先の座標が
1個進むと e がsrc_cxだけ
増える
e が dst_cx 以上溜まったら
・・・
コピー元の座標が
1個進む


これをY座標側にも適用したのがこちらのコードです。
"X座標の e" → e_x 、"Y座標の e" → e_y に名前を分けました
bresenham で拡大縮小

    // 初期値
    my = dst_y+iy_start*dst_add_y;
    ny = src_y+iy_start*src_cy/abs_dst_cy;
    e_y= (iy_start*abs_src_cy)%abs_dst_cy;
    int mx_start = dst_x+ix_start*dst_add_x;
    int nx_start = src_x+ix_start*src_cx/abs_dst_cx;
    int e_x_start = (ix_start*abs_src_cx)%abs_dst_cx;

    // メインループ
    for(iy=iy_start;iy<iy_end;iy++){
        mx = mx_start;
        nx = nx_start;
        e_x= e_x_start;
        d_pix.set_pos(mx, my);

        for(ix=ix_start;ix<ix_end;ix++){
            s_pix.set_pos(nx, ny);
            s_pix.to_draw(d_pix);    // 描画
            d_pix+=dst_add_x;    // インクリメント

            e_x += abs_src_cx;
            while(e_x>=abs_dst_cx) { nx+=src_add_x; e_x-=abs_dst_cx; }
            mx += dst_add_x;
        }
        e_y += abs_src_cy;
        while(e_y>abs_dst_cy) { ny+=src_add_y; e_y-=abs_dst_cy; }
        my+=dst_add_y;
    }
    return 0;


以上でメインルーチン部分は完成です。






・範囲補正を行う前に

引数の保持についてです。
指定されたコピーサイズは保持しておかなければなりません。
範囲補正を行うとき、拡大・縮小の倍率を変えてしまわないようにです。

倍率を小数値で保持すれば当然誤差がでるので、しかたなく分母と分子を保持する意味で元の引数のサイズを使います。
画像よりハミでた部分は映らない分でも縦横が歪んだらやだなぁと思うので。


・拡大縮小での範囲補正1
   
(コピー先の範囲をチェック)


コピー先の補正の考え方は通常の矩形コピーと同じです。画像よりハミでた部分と同じ値だけ補正すればいいだけです。
コピー先補正

    if (dst_x<0) ix_start=-dst_x;
    else if (dst_x>m_width)  ix_start=dst_x-(m_width-1);

    if (dst_y<0) iy_start=-dst_y;
    else if (dst_y>m_height) iy_start=dst_y-(m_height-1);

    if ((dst_x+dst_cx)<0) ix_end=dst_x+1;
    else if ((dst_x+dst_cx)>m_width) ix_end=m_width-dst_x;

    if ((dst_y+dst_cy)<0) iy_end=dst_y+1;
    else if ((dst_y+dst_cy)>m_height) iy_end=m_height-dst_y;

はい、カンタンですね。



・拡大縮小での範囲補正2

   (初期値がコピー元の範囲内にあるかをチェック)


次にコピー元側の座標が画像の外にハミでていないかチェックします。
コピー元のX座標の初期値は
nx = src_x+ix_start*src_cx/abs_dst_cx;
です。

これは普通の数学でやってもこの式がでますが、いまひとつ直感的でないので
いっちょ試しに
上記Bresenhamを使ったメインループのルーチ ンから考えて見ます。


コピー元のX座標の初期値
@
コピー先が
1個進むと
e が
src_cxだけ
増える
A
コピー先が
n個進むと
e が
n*src_cxだけ
増える
B
e が
dst_cx 増えると
コピー元が1個
増えるので

コピー元は
e/dst_cx
増える



コピー先の座標が 1 個進むと esrc_cx    だけ増えます。
コピー先の座標が n 個進むと esrc_cx*n だけ増えます。
なので
コピー先の初期座標が ix_start 分進んだ状態でスタートするので
esrc_cx*ix_start 分増えた状態でスタートします。

ここで、ちょっと思い出してください。
edst_cx    だけ増えると コピー元の座標が 1 個進みます。
edst_cx*n だけ増えると コピー元の座標が n 個進みます。

つまり
esrc_cx*ix_start 分増えた状態でスタートするので
コピー元の座標は (src_cx*ix_start)/dst_cx増えた状態で
スタートすることになります。

従って、コピー元のX座標の初期値は
nx = src_x+ix_start*src_cx/abs_dst_cx;



ちなみに、e_xsrc_cx*ix_start 分増えた状態でスタートしますが、
dst_cx を超えた分はコピー元のX座標として吸収されるので、
e_x の初期値はdst_cx の余算に
なります。
e_x = (src_cx*ix_start)%dst_cx;
です。


さて
nx = src_x+ix_start*src_cx/abs(dst_cx);
という初期値がコピー元の画像の外にハミでているかどうかで、
ハミでているときどう処理するかが問題でした。

src_cxがマイナス値のとき鏡面コピーになります。
if (nx<0 || nx>=p_src_img->m_width){
    if (src_cx>0){
        if (nx<0) src_start = -src_x;
        if (nx>=p_src_img->m_width) return -1;
    }
    else{
       if (nx<0) return -1;
        if (nx>=p_src_img->m_width) src_start = src_x - p_src_img->m_width;
    }
    ix_start = src_start*abs(dst_cx)/src_cx;
    if (src_start*abs(dst_cx)%src_cx) ix_start++;
}


とまあ数学的にはこんな感じですが、またいまひとつ直感的でないので。
もういっちょ試しに上記Bresenhamを使ったメインループの ルーチンから考えて見ます。


コピー元のX座標からループ初期値(ix_start) を補正する


コピー元側から補正するとき
コピー元側の初期値は src_start 進んだ状態でスタートすると考えると、
e は
e >= src_start*dst_cx;
の状態でスタートするはずです。

ここで、ちょっと思い出してください。
コピー先の座標が 個進むと esrc_cx    だけ増えます。
コピー先の座標が m 個進むと esrc_cx*m だけ増えます。

つまり
e は src_cx の倍数なので、(コピー先のX座標が m)
m * src_cx >= src_start*dst_cx;
この式が成り立つような
最小の m が ix_startです。
(コピー先の座標が ix_start 個進んだ状態でスタートする)

右辺の (src_start*dst_cx)src_cxで割り切れれば      m = src_start*dst_cx/src_cx;
右辺の (src_start*dst_cx)src_cxで割り切れなければ m = src_start*dst_cx/src_cx +1;

従って
ix_start = src_start*dst_cx/src_cx;
if (src_start*dst_cx%src_cx) ix_start++;


もちろん src_start
src_x が 0 より小さければ src_start = -src_x;
src_x が 画像幅 より大きければ src_start = -src_img_width;
                            (src_img_width はコピー元画像幅とします)


m*src_cx >= src_start*dst_cx;

これをY座標側にも適用すれば初期値OKです。


・拡大縮小での範囲補正3

      (終了値がコピー元の範囲内にあるかをチェック)


さて今度は終了値です。
tx = src_x+(ix_end-1)*src_cx/abs(dst_cx);
という値がコピー元の画像の外にハミでているかどうかです。



コピー元のX座標の終了値


コピー元のX座標の最終値は
tx = src_x+(ix_end-1)*src_cx/abs_dst_cx;

コピー元のX座標が n 個進んだとき
X座標 == src_x + n; で
e>=n * dst_cx;
の値をとります

もし、X座標 (src_x + n) が == src_img_width で限界を超えてるようなら(src_img_width はコピー元画像幅)
e は (n * dst_cx) より小さくなければなりません
n = src_img_width - src_x;
e< (n * dst_cx);

つまりe は(n * dst_cx)よりは小さんだけど、
出来る限り端っこまで描画したいので、
(n * dst_cx)に一番近くて大きい e を考えます。

ここで、ちょっと思い出してください。
コピー先の座標が 1  個進むと esrc_cx     だけ増えます。
コピー先の座標が m 個進むと esrc_cx*m だけ増えます。

e は src_cx の倍数なので
(m*src_cx) < (n * dst_cx)
コピー先の座標が m 個進んでいて、
コピー元の座標は n 個進んでいる状態です。
このときの最大のmを求めます

(n * dst_cx) が src_cx で割り切れれば    m = (n * dst_cx)/src_cx -1
(n * dst_cx) が src_cx で割り切れなければ m = (n * dst_cx)/src_cx

m = (n * dst_cx)/src_cx;
if ((n * dst_cx)%src_cx ==0) m--;

また、この m がメインループの最終値となればいいので
m = ix_end - 1;
のはずです。

なので
ix_end = (n * dst_cx)/src_cx +1;
if ((n * dst_cx)%src_cx ==0) ix_end--;


もちょっとスマートにまとめると
ix_end = (n * dst_cx)/src_cx;
if ((n * dst_cx)%src_cx) ix_end++;
ただし n は
(src_x + n) が == src_img_width で限界を超えてるようなら n = src_img_width - src_x;
(src_x + n) が < 0 で限界を超えてるようなら n = -1 - src_x;


上述の初期値の補正と式そっくりですが、敢えて一つにしたりしません。
分けてあるほうが、分かりやすく演算も速いからです。




サンプル解説 

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

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

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


・選択範囲を表示するのにPatBltとリージョンで矩形枠描画しています
・今回クリップボードには転送していないので他のアプリケーションに貼り付けできません。


画像1と画像2にファイルを読み込んで下さい。
その後マウスでドラッグして
選択範囲を決めて、
右クリックメニューからコピーします

そして今度は描画する範囲を決めて
貼り付けたいところに、右クリックメニューから貼り付けします


1.
最初の画面です。
2.
画像1と画像2にファイルを読み込んで下さい。
3.
コピー範囲を指定してから、
右クリックでコピーしてください

(クリップボードにはコピーしていないので
他のアプリケーションに貼り付けはできません)
4.
貼り付け範囲を指定してから、
右クリックで貼り付けしてください
5.
できました。


以上の順序を間違えるとコピーできません。
参考:
メニューから拡大縮小コピーの
透明度も指定できます。
拡大縮小・半透明コピーも可能です。



resource_08.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_08.rc

// 拡大縮小コピー

#include "resource_08.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_08.h

// 拡大縮小コピー

#include <stdio.h>
#include <windows.h>
#include "resource_08.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>
    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>
    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);

    // 拡大縮小コピー
    from_elastic_draw(int d_x, int d_y, int d_cx, int d_cy,
                GT_IMG *p_img, int s_x, int s_y, int s_cx, int s_cy, int rate=255, int flag=ID_BLEND);
    template <int dst_bit, int src_bit>
    from_elastic_draw_set_alpha(int d_x, int d_y, int d_cx, int d_cy,
                GT_IMG *p_img, int s_x, int s_y, int s_cx, int s_cy, int rate, int flag);
    template <int dst_bit, int dst_alpha, int src_bit, int src_alpha>
    from_elastic_draw_pixput(int d_x, int d_y, int d_cx, int d_cy,
                GT_IMG *p_img, int s_x, int s_y, int s_cx, int s_cy, int rate, int flag);
    adjust_elastic_draw(int &ix_start, int &iy_start, int &ix_end, int &iy_end,
        int dst_x, int dst_y, int dst_cx, int dst_cy, GT_IMG *p_img, int src_x, int src_y, int src_cx, int src_cy);

    // カラー
    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 ランレングス圧縮

};

//==========================================
//      拡大縮小コピー                      
//==========================================

// 拡大縮小コピー
GT_IMG::from_elastic_draw(int d_x, int d_y, int d_cx, int d_cy,
                GT_IMG *p_img, int s_x, int s_y, int s_cx, int s_cy, int rate, int flag){
    if (!p_img) return -1;
    if (!p_img->m_pbits || !m_pbits) return -1;

    if (rate<0) rate=0;
    if (rate>=255) rate=255;

    switch(m_bit_count){
    case 1:
        switch(p_img->m_bit_count){
        case 1:  from_elastic_draw_set_alpha<1 , 1 >(d_x, d_y, d_cx, d_cy, p_img, s_x, s_y, s_cx, s_cy, rate, flag); break;
        case 4:  from_elastic_draw_set_alpha<1 , 4 >(d_x, d_y, d_cx, d_cy, p_img, s_x, s_y, s_cx, s_cy, rate, flag); break;
        case 8:  from_elastic_draw_set_alpha<1 , 8 >(d_x, d_y, d_cx, d_cy, p_img, s_x, s_y, s_cx, s_cy, rate, flag); break;
        case 16: from_elastic_draw_set_alpha<1 , 16>(d_x, d_y, d_cx, d_cy, p_img, s_x, s_y, s_cx, s_cy, rate, flag); break;
        case 24: from_elastic_draw_set_alpha<1 , 24>(d_x, d_y, d_cx, d_cy, p_img, s_x, s_y, s_cx, s_cy, rate, flag); break;
        case 32: from_elastic_draw_set_alpha<1 , 32>(d_x, d_y, d_cx, d_cy, p_img, s_x, s_y, s_cx, s_cy, rate, flag); break;
        }
        break;
    case 4:
        switch(p_img->m_bit_count){
        case 1:  from_elastic_draw_set_alpha<4 , 1 >(d_x, d_y, d_cx, d_cy, p_img, s_x, s_y, s_cx, s_cy, rate, flag); break;
        case 4:  from_elastic_draw_set_alpha<4 , 4 >(d_x, d_y, d_cx, d_cy, p_img, s_x, s_y, s_cx, s_cy, rate, flag); break;
        case 8:  from_elastic_draw_set_alpha<4 , 8 >(d_x, d_y, d_cx, d_cy, p_img, s_x, s_y, s_cx, s_cy, rate, flag); break;
        case 16: from_elastic_draw_set_alpha<4 , 16>(d_x, d_y, d_cx, d_cy, p_img, s_x, s_y, s_cx, s_cy, rate, flag); break;
        case 24: from_elastic_draw_set_alpha<4 , 24>(d_x, d_y, d_cx, d_cy, p_img, s_x, s_y, s_cx, s_cy, rate, flag); break;
        case 32: from_elastic_draw_set_alpha<4 , 32>(d_x, d_y, d_cx, d_cy, p_img, s_x, s_y, s_cx, s_cy, rate, flag); break;
        }
        break;
    case 8:
        switch(p_img->m_bit_count){
        case 1:  from_elastic_draw_set_alpha<8 , 1 >(d_x, d_y, d_cx, d_cy, p_img, s_x, s_y, s_cx, s_cy, rate, flag); break;
        case 4:  from_elastic_draw_set_alpha<8 , 4 >(d_x, d_y, d_cx, d_cy, p_img, s_x, s_y, s_cx, s_cy, rate, flag); break;
        case 8:  from_elastic_draw_set_alpha<8 , 8 >(d_x, d_y, d_cx, d_cy, p_img, s_x, s_y, s_cx, s_cy, rate, flag); break;
        case 16: from_elastic_draw_set_alpha<8 , 16>(d_x, d_y, d_cx, d_cy, p_img, s_x, s_y, s_cx, s_cy, rate, flag); break;
        case 24: from_elastic_draw_set_alpha<8 , 24>(d_x, d_y, d_cx, d_cy, p_img, s_x, s_y, s_cx, s_cy, rate, flag); break;
        case 32: from_elastic_draw_set_alpha<8 , 32>(d_x, d_y, d_cx, d_cy, p_img, s_x, s_y, s_cx, s_cy, rate, flag); break;
        }
        break;
    case 16:
        switch(p_img->m_bit_count){
        case 1:  from_elastic_draw_set_alpha<16, 1 >(d_x, d_y, d_cx, d_cy, p_img, s_x, s_y, s_cx, s_cy, rate, flag); break;
        case 4:  from_elastic_draw_set_alpha<16, 4 >(d_x, d_y, d_cx, d_cy, p_img, s_x, s_y, s_cx, s_cy, rate, flag); break;
        case 8:  from_elastic_draw_set_alpha<16, 8 >(d_x, d_y, d_cx, d_cy, p_img, s_x, s_y, s_cx, s_cy, rate, flag); break;
        case 16: from_elastic_draw_set_alpha<16, 16>(d_x, d_y, d_cx, d_cy, p_img, s_x, s_y, s_cx, s_cy, rate, flag); break;
        case 24: from_elastic_draw_set_alpha<16, 24>(d_x, d_y, d_cx, d_cy, p_img, s_x, s_y, s_cx, s_cy, rate, flag); break;
        case 32: from_elastic_draw_set_alpha<16, 32>(d_x, d_y, d_cx, d_cy, p_img, s_x, s_y, s_cx, s_cy, rate, flag); break;
        }
        break;
    case 24:
        switch(p_img->m_bit_count){
        case 1:  from_elastic_draw_set_alpha<24, 1 >(d_x, d_y, d_cx, d_cy, p_img, s_x, s_y, s_cx, s_cy, rate, flag); break;
        case 4:  from_elastic_draw_set_alpha<24, 4 >(d_x, d_y, d_cx, d_cy, p_img, s_x, s_y, s_cx, s_cy, rate, flag); break;
        case 8:  from_elastic_draw_set_alpha<24, 8 >(d_x, d_y, d_cx, d_cy, p_img, s_x, s_y, s_cx, s_cy, rate, flag); break;
        case 16: from_elastic_draw_set_alpha<24, 16>(d_x, d_y, d_cx, d_cy, p_img, s_x, s_y, s_cx, s_cy, rate, flag); break;
        case 24: from_elastic_draw_set_alpha<24, 24>(d_x, d_y, d_cx, d_cy, p_img, s_x, s_y, s_cx, s_cy, rate, flag); break;
        case 32: from_elastic_draw_set_alpha<24, 32>(d_x, d_y, d_cx, d_cy, p_img, s_x, s_y, s_cx, s_cy, rate, flag); break;
        }
        break;
    case 32:
        switch(p_img->m_bit_count){
        case 1:  from_elastic_draw_set_alpha<32, 1 >(d_x, d_y, d_cx, d_cy, p_img, s_x, s_y, s_cx, s_cy, rate, flag); break;
        case 4:  from_elastic_draw_set_alpha<32, 4 >(d_x, d_y, d_cx, d_cy, p_img, s_x, s_y, s_cx, s_cy, rate, flag); break;
        case 8:  from_elastic_draw_set_alpha<32, 8 >(d_x, d_y, d_cx, d_cy, p_img, s_x, s_y, s_cx, s_cy, rate, flag); break;
        case 16: from_elastic_draw_set_alpha<32, 16>(d_x, d_y, d_cx, d_cy, p_img, s_x, s_y, s_cx, s_cy, rate, flag); break;
        case 24: from_elastic_draw_set_alpha<32, 24>(d_x, d_y, d_cx, d_cy, p_img, s_x, s_y, s_cx, s_cy, rate, flag); break;
        case 32: from_elastic_draw_set_alpha<32, 32>(d_x, d_y, d_cx, d_cy, p_img, s_x, s_y, s_cx, s_cy, rate, flag); break;
        }
        break;
    }
    return 0;
}
// 拡大縮小コピー(アルファ値設定)
template <int dst_bit, int src_bit>
GT_IMG::from_elastic_draw_set_alpha(int d_x, int d_y, int d_cx, int d_cy,
                GT_IMG *p_img, int s_x, int s_y, int s_cx, int s_cy, int rate, int flag){
    if (is_alpha()){
        if (p_img->is_alpha())
            from_elastic_draw_pixput<dst_bit, 1, src_bit, 1>(d_x, d_y, d_cx, d_cy, p_img, s_x, s_y, s_cx, s_cy, rate, flag);
        else
            from_elastic_draw_pixput<dst_bit, 1, src_bit, 0>(d_x, d_y, d_cx, d_cy, p_img, s_x, s_y, s_cx, s_cy, rate, flag);
    }
    else {
        if (p_img->is_alpha())
            from_elastic_draw_pixput<dst_bit, 0, src_bit, 1>(d_x, d_y, d_cx, d_cy, p_img, s_x, s_y, s_cx, s_cy, rate, flag);
        else
            from_elastic_draw_pixput<dst_bit, 0, src_bit, 0>(d_x, d_y, d_cx, d_cy, p_img, s_x, s_y, s_cx, s_cy, rate, flag);
    }
}
// 拡大縮小コピー位置補正
GT_IMG::adjust_elastic_draw(int &ix_start, int &iy_start, int &ix_end, int &iy_end,
    int dst_x, int dst_y, int dst_cx, int dst_cy, GT_IMG *p_img, int src_x, int src_y, int src_cx, int src_cy){

    int co, tmp;

    //コピー先補正
    if (dst_x<0) ix_start=-dst_x;   else if (dst_x>m_width)  ix_start=dst_x-(m_width-1);
    if (dst_y<0) iy_start=-dst_y;   else if (dst_y>m_height) iy_start=dst_y-(m_height-1);
    if ((dst_x+dst_cx)<0) ix_end=dst_x+1;   else if ((dst_x+dst_cx)>m_width) ix_end=m_width-dst_x;
    if ((dst_y+dst_cy)<0) iy_end=dst_y+1;   else if ((dst_y+dst_cy)>m_height) iy_end=m_height-dst_y;

    //コピー元補正
    int abs_dst_cx = abs(dst_cx);
    int abs_dst_cy = abs(dst_cy);

    // ix_start 補正
    co=src_x+ix_start*src_cx/abs_dst_cx;
    if (co<0 || co>=p_img->m_width){
        if (src_cx>0){
            if (co<0) tmp =-src_x;
            if (co>=p_img->m_width) return -1;
        }
        else {
            if (co<0) return -1;
            if (co>=p_img->m_width) tmp=p_img->m_width-1-src_x;
        }
        ix_start=tmp*abs_dst_cx/src_cx;
        if ((tmp*abs_dst_cx)%src_cx) ix_start++;
    }

    // ix_end 補正
    co=src_x+(ix_end-1)*src_cx/abs_dst_cx;
    if (co<0 || co>=p_img->m_width){
        if (src_cx>0){
            if (co<0) return -1;
            if (co>=p_img->m_width) tmp=p_img->m_width-src_x;
        }
        else {
            if (co<0) tmp=-src_x-1;
            if (co>=p_img->m_width) return -1;
        }
        tmp = tmp * abs_dst_cx;
        ix_end=abs(tmp/abs(src_cx));
        if (tmp%abs(src_cx)) ix_end++;
    }

    // iy_start 補正
    co=src_y+iy_start*src_cy/abs_dst_cy;
    if (co<0 || co>=p_img->m_height){
        if (src_cy>0){
            if (co<0) tmp =-src_y;
            if (co>=p_img->m_height) return -1;
        }
        else {
            if (co<0) return -1;
            if (co>=p_img->m_height) tmp=p_img->m_height-1-src_y;
        }
        iy_start=tmp*abs_dst_cy/src_cy;
        if ((tmp*abs_dst_cy)%src_cy) iy_start++;
    }

    // iy_end 補正
    co=src_y+(iy_end-1)*src_cy/abs_dst_cy;
    if (co<0 || co>=p_img->m_height){
        if (src_cy>0){
            if (co<0) return -1;
            if (co>=p_img->m_height) tmp=p_img->m_height-src_y;
        }
        else {
            if (co<0) tmp=-src_y-1;
            if (co>=p_img->m_height) return -1;
        }
        tmp = tmp * abs_dst_cy;
        iy_end=abs(tmp/abs(src_cy));
        if (tmp%abs(src_cy)) iy_end++;
    }

    return 0;
};

// 拡大縮小コピーのインライン・テンプレート
template <int dst_bit, int dst_alpha, int src_bit, int src_alpha>
GT_IMG::from_elastic_draw_pixput(int dst_x, int dst_y, int dst_cx, int dst_cy,
                GT_IMG *p_img, int src_x, int src_y, int src_cx, int src_cy, int rate, int flag){

    PIXEL_ITR<dst_bit, dst_alpha> d_pix;
    PIXEL_ITR<src_bit, src_alpha> s_pix;
    if (rate<0) return -1; 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, mx, my, nx, ny, abs_dst_cx, abs_dst_cy, abs_src_cx, abs_src_cy;
    int ix_start, ix_end, iy_start, iy_end, dst_add_x, dst_add_y, src_add_x, src_add_y;
    double e_x=0, e_y=0;

    if (!dst_cx || !dst_cy || !src_cx || !src_cy) return -1;

    abs_dst_cx=abs(dst_cx);     abs_dst_cy=abs(dst_cy);
    abs_src_cx=abs(src_cx);     abs_src_cy=abs(src_cy);

    ix_start=0;     ix_end=abs_dst_cx;
    iy_start=0;     iy_end=abs_dst_cy;

    src_add_x = (src_cx>=0)? 1: -1;
    src_add_y = (src_cy>=0)? 1: -1;

    dst_add_x = (dst_cx>=0)? 1: -1;
    dst_add_y = (dst_cy>=0)? 1: -1;

    if (adjust_elastic_draw(ix_start, iy_start, ix_end, iy_end,
            dst_x, dst_y, dst_cx, dst_cy, p_img, src_x, src_y, src_cx, src_cy)<0) return -1;

    // 初期値
    my = dst_y+iy_start*dst_add_y;
    ny = src_y+iy_start*src_cy/abs_dst_cy;
    e_y= (iy_start*abs_src_cy)%abs_dst_cy;
    int mx_start = dst_x+ix_start*dst_add_x;
    int nx_start = src_x+ix_start*src_cx/abs_dst_cx;
    int e_x_start = (ix_start*abs_src_cx)%abs_dst_cx;

    // メインループ
    if (rate>=255){
        // 不透明コピー
        for(iy=iy_start;iy<iy_end;iy++){
            mx = mx_start;      nx = nx_start;      e_x= e_x_start;
            d_pix.set_pos(mx, my);

            for(ix=ix_start;ix<ix_end;ix++){
                s_pix.set_pos(nx, ny);
                s_pix.to_draw(d_pix);   // 描画
                d_pix+=dst_add_x;   // インクリメント

                e_x += abs_src_cx;
                while(e_x>=abs_dst_cx) { nx+=src_add_x; e_x-=abs_dst_cx; }
                mx += dst_add_x;
            }
            e_y += abs_src_cy;
            while(e_y>abs_dst_cy) { ny+=src_add_y; e_y-=abs_dst_cy; }
            my+=dst_add_y;
        }
    }
    // 半透明コピー
    else if (flag & ID_NOBLEND) {
        // 半透明コピー(ブレンド無し)
        for(iy=iy_start;iy<iy_end;iy++){
            mx = mx_start;      nx = nx_start;      e_x= e_x_start;
            d_pix.set_pos(mx, my);

            for(ix=ix_start;ix<ix_end;ix++){
                s_pix.set_pos(nx, ny);
                s_pix.to_no_blend_draw(d_pix, rate);    // 描画
                d_pix+=dst_add_x;   // インクリメント

                e_x += abs_src_cx;
                while(e_x>=abs_dst_cx) { nx+=src_add_x; e_x-=abs_dst_cx; }
                mx += dst_add_x;
            }
            e_y += abs_src_cy;
            while(e_y>abs_dst_cy) { ny+=src_add_y; e_y-=abs_dst_cy; }
            my+=dst_add_y;
        }
    }
    else {
        // 半透明コピー(ブレンド有り)
        for(iy=iy_start;iy<iy_end;iy++){
            mx = mx_start;      nx = nx_start;      e_x= e_x_start;
            d_pix.set_pos(mx, my);

            for(ix=ix_start;ix<ix_end;ix++){
                s_pix.set_pos(nx, ny);
                s_pix.to_blend_draw(d_pix, rate);   // 描画
                d_pix+=dst_add_x;   // インクリメント

                e_x += abs_src_cx;
                while(e_x>=abs_dst_cx) { nx+=src_add_x; e_x-=abs_dst_cx; }
                mx += dst_add_x;
            }
            e_y += abs_src_cy;
            while(e_y>abs_dst_cy) { ny+=src_add_y; e_y-=abs_dst_cy; }
            my+=dst_add_y;
        }
    }
    return 0;
};

//==========矩形コピー==========
// 矩形コピー(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>
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())
            return from_draw_pixput<dst_bit, 1, src_bit, 1>(dst_x, dst_y, cx, cy, p_img, src_x, src_y, rate, flag);
        else
            return 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())
            return from_draw_pixput<dst_bit, 0, src_bit, 1>(dst_x, dst_y, cx, cy, p_img, src_x, src_y, rate, flag);
        else
            return from_draw_pixput<dst_bit, 0, src_bit, 0>(dst_x, dst_y, cx, cy, p_img, src_x, src_y, rate, flag);
    }
    return 0;
}

// 矩形コピーのインライン・テンプレート
template <int dst_bit, int dst_alpha, int src_bit, int src_alpha>
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;
    if (rate<0) return -1; 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++; }
        }
    }
    return 0;
};
//==========矩形描画==========
// 矩形塗りつぶしのインライン・テンプレート
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_08.cpp

// 拡大縮小コピー

#include <stdio.h>
#include <windows.h>
#include "resource_08.h"
#include "gt_img_08.h"

GT_DIB gt_dib_1, gt_dib_2, *src_dib=NULL;
POINT gt_dib_1_pos, gt_dib_2_pos;
int dst_cx, dst_cy, src_x, src_y, src_cx, src_cy;
static OPENFILENAME ofn = {0};
static char filename[MAX_PATH];

POINT start_po, mou_po;
RECT paste_rc, copy_rc, select_rc;
int select_rc_valid=0, copy_rc_valid=0;
int rate=255;

dialog(HWND hwnd, char *a_str){
    return MessageBox(hwnd, a_str, TEXT("error"), MB_OK);
}
// 枠線を反転描画する
patblt_rect_frame(HDC hdc, RECT rc){
    RECT rc2, rc3;
    HRGN hrgn, hrgn2, hrgn3;

    rc2.left  = min(rc.left, rc.right);
    rc2.top   = min(rc.top, rc.bottom);
    rc2.right = max(rc.left, rc.right);
    rc2.bottom= max(rc.top, rc.bottom);

    rc3.left  = rc2.left  +1;
    rc3.top   = rc2.top   +1;
    rc3.right = rc2.right -1;
    rc3.bottom= rc2.bottom-1;

    hrgn  = CreateRectRgnIndirect(&rc2);
    hrgn2 = CreateRectRgnIndirect(&rc3);
    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+40;
        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_rc_valid) {
            dialog(hwnd, "コピー元の範囲を指定してください");
            break;
        }
        copy_rc = select_rc;
        if (copy_rc.left<(gt_dib_1.m_width + gt_dib_1_pos.x +10)){
            // 画像1からコピー
                src_dib = &gt_dib_1;
                src_x = copy_rc.left - gt_dib_1_pos.x;
                src_y = copy_rc.top - gt_dib_1_pos.y;
        }
        else {
            // 画像2からコピー
                src_dib = &gt_dib_2;
                src_x = copy_rc.left - gt_dib_2_pos.x;
                src_y = copy_rc.top - gt_dib_2_pos.y;
        }
        select_rc_valid = 0;
        copy_rc_valid=1;
        src_cx = copy_rc.right-copy_rc.left;
        src_cy = copy_rc.bottom-copy_rc.top;
        InvalidateRect(hwnd, NULL, 1);
        break;
    case IDM_PASTE:
        if (!copy_rc_valid) {
            dialog(hwnd, "コピー元を指定してください");
            break;
        }
        if (!select_rc_valid) {
            dialog(hwnd, "コピー先の範囲を指定してください");
            break;
        }
        paste_rc=select_rc;
        select_rc_valid = 0;
        dst_cx = paste_rc.right-paste_rc.left;
        dst_cy = paste_rc.bottom-paste_rc.top;
        if (paste_rc.left<(gt_dib_1.m_width + gt_dib_1_pos.x +10)){
            // 画像1に貼り付け
            gt_dib_1.from_elastic_draw(
                paste_rc.left - gt_dib_1_pos.x,   paste_rc.top - gt_dib_1_pos.y,
                dst_cx, dst_cy,
                src_dib, src_x, src_y, src_cx, src_cy, rate );
        }
        else {
            // 画像2に貼り付け
            gt_dib_2.from_elastic_draw(
                paste_rc.left - gt_dib_2_pos.x,   paste_rc.top  - gt_dib_2_pos.y,
                dst_cx, dst_cy,
                src_dib, src_x, src_y, src_cx, src_cy, 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_rc_valid) patblt_rect_frame(hdc, select_rc);
        if (copy_rc_valid) patblt_rect_frame(hdc, copy_rc);
        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=40;
        gt_dib_2_pos.x= 250;
        gt_dib_2_pos.y= 40;
        break;
    case WM_LBUTTONDOWN:
        if (!mou_down){
            hdc=GetDC(hwnd);
            if (select_rc_valid) patblt_rect_frame(hdc, select_rc);
            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_rc.left  = start_po.x;
            select_rc.top   = start_po.y;
            select_rc.right = mou_po.x;
            select_rc.bottom= mou_po.y;

            InvalidateRect(hwnd, NULL, 1);
            select_rc_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_rc);
            mou_down=2;

            GetCursorPos(&mou_po);
            ScreenToClient(hwnd, &mou_po);
            select_rc.left  = start_po.x;
            select_rc.top   = start_po.y;
            select_rc.right = mou_po.x;
            select_rc.bottom= mou_po.y;

            patblt_rect_frame(hdc, select_rc);
            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-07  前へ←  ホームへ  →次へ  007-09(1)