画像を拡大または縮小させると、汚くなってしまいます。
それは標準の拡大・縮小アルゴリズムに問題があるからです。
今回はそのアルゴリズムを変更して、綺麗に拡大・縮小させる方法を解説します。
■画像を読み込む
「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 を自ら実装すると時間がかかりすぎて使い物にならなくなります。
ハードレベルでサポートされているのか、神の如き最適化が成されているのかは定かではありませんが、
凄いですね、凄すぎです。

原画像
.jpg)
伸縮モード:BLACKONWHITE

伸縮モード:BLACKONWHITE

伸縮モード:COLORONCOLOR

伸縮モード:HALFTONE
★☆ ソースファイル表示 ☆★