画像を拡大または縮小させると、汚くなってしまいます。
それは標準の拡大・縮小アルゴリズムに問題があるからです。
今回はそのアルゴリズムを変更して、綺麗に拡大・縮小させる方法を解説します。
■画像を読み込む
「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
★☆ ソースファイル表示 ☆★