テレビ画面などを拡大すると、表示されている映像が細かい色の粒子で構成されている事がわかります。拡大すると単色の集合でしかない画像も離れてみると自然な画像に見える。今回は、このような効果をビットマップをRGB3原色に分解し分離して配置する事で試してみる事にしました。
RGBの分解
24ビットフルカラーDIB(BMP)のピクセル列は、ピクセルの色をRGB3原色の成分として保持しています。今回は、BMP画像を読み込んだら各ピクセルの3原色を「1ピクセルずつ」配置し縦横2倍に拡大した画像を生成しましょう。具体的には、拡大した2×2の4ピクセルのうち右下に緑、左上に青、右上に赤成分を配置します。
左下は、常に黒。ここに、元の色や元の色の輝度などを置いてみたのですが、どうも不自然なので黒にしてしまいます。
プログラムとしては、まずBMPから24ビットフルカラーDIBを作成します。続いてこのDIBのピクセル列から上記の方法で1ピクセルを4倍に拡大した32ビットフルカラーDIBを作るresize()関数を定義してBMP読み込みの後で呼び出しましょう。
BMP読み込み関数readBMP()を呼び出した段階で、既にビットマップの大きさがdwWidth, dwHeight, dwLengthに、またピクセル列がlpBMPに入っているので、まず大きさを元に32ビットDIB用のバッファを確保し元画像のピクセル列を退避してから、lpBMPのポインタを処理後のピクセル列に設定します。あとは、元画像の各ピクセルからRGB成分を取得して、書き込んで行くだけですね。
void resize() {
LPBYTE lpWrk=GlobalAlloc(GPTR,dwLength*dwHeight);
DWORD i,j;
BYTE r,g,b;
CopyMemory(lpWrk,lpBMP,dwLength*dwHeight);
if (lpDIB!=NULL)
GlobalFree(lpDIB);
lpDIB=GlobalAlloc(GPTR,sizeof(BITMAPINFO)+dwWidth*dwHeight*4*4);
lpInfo=(LPBITMAPINFO)lpDIB;
lpBMP=lpDIB+sizeof(BITMAPINFO);
lpInfo->bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
lpInfo->bmiHeader.biWidth=dwWidth*2;
lpInfo->bmiHeader.biHeight=dwHeight*2;
lpInfo->bmiHeader.biBitCount=32;
lpInfo->bmiHeader.biPlanes=1;
lpInfo->bmiHeader.biCompression=BI_RGB;
for (i=0;i<dwHeight;i++)
for (j=0;j<dwWidth;j++) {
b=lpWrk[j*3+i*dwLength];
g=lpWrk[j*3+i*dwLength+1];
r=lpWrk[j*3+i*dwLength+2];
lpBMP[(j*2+1)*4+(i*2)*dwWidth*2*4+1]=g;
lpBMP[(j*2)*4+(i*2+1)*dwWidth*2*4]=b;
lpBMP[(j*2+1)*4+(i*2+1)*dwWidth*2*4+2]=r;
}
dwWidth=dwWidth*2;
dwHeight=dwHeight*2;
GlobalFree(lpWrk);
}
プログラム
実行したら、24ビットフルカラーBMPをドロップしてみてください。RGBの成分を個別に配置して2倍(面積4倍)に拡大した画像を表示します。1ピクセル欠けているのでかなり暗くなりますが、「色」は元画像と同じに見えますね。でも、この画像をコピーしてドット絵でぃたやペイントなどで拡大してみると、RGBの単色ピクセルが並んでいるだけなのがわかるでしょう。