伸縮モード変更

概要:綺麗に画像を拡大・縮小する

画像を拡大または縮小させると、汚くなってしまいます。
それは標準の拡大・縮小アルゴリズムに問題があるからです。
今回はそのアルゴリズムを変更して、綺麗に拡大・縮小させる方法を解説します。

■画像を読み込む

「BMPをDDBとして読み込む」のプログラムを流用しています。
読み込む画像ファイルだけ変更しました。

HBITMAP hBitmap;
static HDC hMemDC;
static BITMAP bmp;

case WM_CREATE:
    //ビットマップを読み込む
    hBitmap=(HBITMAP)LoadImage(0,"Parrots.bmp",IMAGE_BITMAP,0,0,LR_LOADFROMFILE);
    if(hBitmap==NULL){
        MessageBox(hWnd,"ビットマップがありません",NULL,MB_OK);
        return 0;
    }
    //メモリデバイスコンテキストの作成
    hMemDC=CreateCompatibleDC(NULL);
    SelectObject(hMemDC,hBitmap);
    //ビットマップの情報を取得
    GetObject(hBitmap,sizeof(BITMAP),&bmp);
    //ビットマップ削除
    DeleteObject(hBitmap);
    return 0;
case WM_DESTROY:
    DeleteDC(hMemDC);
    PostQuitMessage(0);
    return 0;

■伸縮モードの変更

拡大・縮小のアルゴリズムの事を伸縮モードと言います。
伸縮モードは SetStretchBltMode 関数で変更します。

int SetStretchBltMode(
  HDC hdc,       // デバイスコンテキストのハンドル
  int iStretchMode  // ビットマップの伸縮モード
);


hdc には伸縮モードを変更するデバイスコンテキストのハンドルを指定します。
コピー元なのか?コピー先なのか?という疑問があるかと思いますが、
コピー先のハンドルを指定して下さい

iStretchMode には伸縮モードを指定します。
その一覧と詳細はヘルプをご覧頂くとして、よく使うのは以下の三つです。

BLACKONWHITE 標準設定。低画質だが高速。拡大または等倍だけならこのままで
COLORONCOLOR 実用的な画質で高速。縮小が必要な時に使おう
HALFTONE 高画質だが低速。ビューワーなどで使おう

ヘルプには BLACKONWHITE はモノクロ画像用で、
COLORONCOLOR はカラー画像用とありますが、それは間違いです。
BLACKONWHITE でモノクロ画像を拡大・縮小させると汚くなってしまいます。
モノクロでも COLORONCOLOR を使う必要があるのです。

ところで、拡大と縮小、どちらが汚くなり易いのでしょうか?
答えは縮小です。
拡大は実用的な画質を保ちます。
従って、拡大だけなら標準設定( BLACKONWHITE )のままでも大きな問題にはならないはずです。

また、処理速度の低下は実際に拡大・縮小した時に発生します。
等倍ならどのモードでも高速に動作します。

BLACKONWHITE と COLORONCOLOR の処理速度は同程度です。
HALFTONE は他と比べると低速なので、バランスの良い COLORONCOLOR を使う機会が多いでしょう。

HALFTONE は高画質だが低速という特徴があるので、
ゲームなどには不向きであり、ビューワーなどで使います。
また、HALFTONE を設定した場合はブラシのずれを防止するために SetBrushOrgEx 関数を呼び出さなければなりません。

BOOL SetBrushOrgEx(
  HDC hdc,     // デバイスコンテキストのハンドル
  int nXOrg,     // 新しい原点の x 座標
  int nYOrg,     // 新しい原点の y 座標
  LPPOINT lppt  // 以前の原点の座標
);


nXOrg , nYOrg には新しいブラシの原点を指定します。通常 (0,0) を指定します。
lppt には以前のブラシの原点の座標が格納されます。不要な場合は NULL を指定して下さい。

HDC hdc;
PAINTSTRUCT ps;

case WM_PAINT:
    hdc=BeginPaint(hWnd,&ps);
    //伸縮モード変更
    SetStretchBltMode(hdc,COLORONCOLOR);
    //SetStretchBltMode(hdc,HALFTONE);
    //SetBrushOrgEx(hdc,0,0,NULL);
    //表画面へ転送
    StretchBlt(hdc,0,0,(int)(bmp.bmWidth*0.66),(int)(bmp.bmHeight*0.66),
        hMemDC,0,0,bmp.bmWidth,bmp.bmHeight,SRCCOPY);
    StretchBlt(hdc,bmp.bmWidth,0,(int)(bmp.bmWidth*1.33),(int)(bmp.bmHeight*1.33),
        hMemDC,0,0,bmp.bmWidth,bmp.bmHeight,SRCCOPY);
    EndPaint(hWnd,&ps);
    return 0;

■現在の伸縮モードを取得

今回は実装しませんでしたが、現在の伸縮モードを取得するには GetStretchBltMode 関数を使います。

int GetStretchBltMode(
  HDC hdc  // デバイスコンテキストのハンドル
);


戻り値が現在の伸縮モードです。

■実行結果

以下に様々な実行結果を示します。
BLACKONWHITE と COLORONCOLOR の差は縮小画像で、
COLORONCOLOR と HALFTONE の差は拡大画像で分かると思います。

また、モノクロ画像で BLACKONWHITE モードの時の縮小画像は汚くなっているのも分かります。

余談ですが、HALFTONE を自ら実装すると時間がかかりすぎて使い物にならなくなります。
ハードレベルでサポートされているのか、神の如き最適化が成されているのかは定かではありませんが、
凄いですね、凄すぎです。



原画像


伸縮モード:BLACKONWHITE


伸縮モード:BLACKONWHITE


伸縮モード:COLORONCOLOR


伸縮モード:HALFTONE

★☆ ソースファイル表示 ☆★


戻る / ホーム