[日記]ちょっと公開してみる
mixi日記からこっちをメインに移してみる。
多分マイミクは見たところでイミフだろうけど、気にしない。
最近のmixiはオワタ感が満載なので撤退準備。
それにしても年末にこんな勉強ばかりしている自分は素敵だと思う。
[BMP]ビットマップの編集
編集と呼ぶには程遠いけど
前回 表示した赤塗りつぶしビットマップデータと、以下の画像を重ねてみる。
[作成環境]
・Visual Studi 2008 Standart Edition
・MFC-ダイアログベース
ダイアログクラスに以下のメンバを新に追加
private:
CBitmap m_bmp; // 背景
CBitmap m_img; // 画像(新規追加)
OnInitDialog()
// TODO: 初期化をここに追加します。
// ビットマップ背景データ部分を作成(高さ200px、幅300px)
BYTE *pData = new BYTE[200*300*4];
// 背景データ部分の初期化
for(int i = 0; i < 200*300*4; i += 4)
{
pdata[i] = 0x00; // 青成分
pdata[i+1] = 0x00; // 緑成分
pdata[i+2] = 0xFF; // 赤成分
pdata[i+3] = 0x00; // 未使用(予約領域)
}
// 画像ビットマップのロード
HBITMAP hbmp = (HBITMAP)LoadImage(0,
_T("C:\\sample.bmp"),
IMAGE_BITMAP,
0,
0,
LR_LOADFROMFILE);
// 取得したハンドルからビットマップオブジェクトを作成
m_img.Attach(hbmp);
// BITMAP構造体の取得
BITMAP bm;
m_img.GetBitmap(&bm);
// 高さと幅の取得
int iWidth = bm.bmWidth;
int iHeight = bm.bmHeight;
int size = iWidth * iHeight * 4;
// 画像データ領域バッファ確保
BYTE *pImg = new BYTE[ size ];
// 確保したバッファに画像データを格納
m_img.GetBitmapBits(size, pImg);
// 背景領域に画像データを上書き
int i,j;
for(i = 0; i < iHeight; i++)
{
for(j = 0; < iWidth * 4; j++)
{
pData[j + i * 300 * 4] = pImg[j + i * iWidth * 4];
}
}
// ビットマップの作成
m_bmp.CreateCompatibleBitmap(GetDC(), 300, 200);
// 作成したビットマップに、作成したデータ部分をセット
m_bmp.SetBitmapBits(200*300*4, pData);
delete [] pData;
delete [] pImg;
// Attachした画像はOnDestroy()内とか不要になった時点でDetach
OnPaint()
変更なし
結果
ちょっとした説明
pData[j + i * 300 * 4] = pImg[j + i * iWidth * 4];
前回も少し書いたが、ビットマップデータ部として1次元配列として確保している。
その中で特定の座標(x, y)を取り出すためには
先頭アドレスに (x + y * (幅))のオフセットを与えればよい。
(1ピクセルの表現にRGBQUADで4バイト要するので×4も行っている)
背景と画像では幅が違うので、折り返し位置を正しく表現したいために
今回の方法をとった。
多分もっとよいやり方はあると思う。
あくまで動作を知るためのコードということで。
[BMP]ビットマップの作成
ビットマップを作って表示してみる。
あくまで個人的な動作の確認のためなので、コードは適当。
[作成環境]
・Visual Studi 2008 Standart Edition
・MFC-ダイアログベース
ダイアログクラスに以下のメンバを追加
private:
CBitmap m_bmp; // ビットマップオブジェクト
OnInitDialog()
// TODO: 初期化をここに追加します。
// ビットマップデータ部分を作成(高さ200px、幅300px)
BYTE *pData = new BYTE[200*300*4];
// データ部分の初期化
for(int i = 0; i < 200*300*4; i += 4)
{
pdata[i] = 0x00; // 青成分
pdata[i+1] = 0x00; // 緑成分
pdata[i+2] = 0xFF; // 赤成分
pdata[i+3] = 0x00; // 未使用(予約領域)
}
// ビットマップの作成
m_bmp.CreateCompatibleBitmap(GetDC(), 300, 200);
// 作成したビットマップに、作成したデータ部分をセット
m_bmp.SetBitmapBits(200*300*4, pData);
delete [] pData;
OnPaint()
if(IsIconic())
{
・・・中略
}
else
{
CDialog::OnPaint();
// DC、メモリDC作成
CDC *pDC = GetDC();
CDC dcMem;
dcMem.CreateCompatibleDC(pDC);
// 作成したビットマップオブジェクト選択
CBitmap *old;
old = dcMem.SelectObject(&m_bmp);
// メモリDC→DCへデータコピー(描画)
pDC->BitBlt(0,0,200,300,&dcMem,0,0,SRCCOPY);
// 元のビットマップオブジェクトに戻す
dcMem.SelectObject(old);
// 解放
dcMem.DeleteDC();
ReleaseDC(pDC);
}
上記コードで、ダイアログ上に赤で塗りつぶされた高さ300、幅200
のビットマップデータが表示される。
そのうちちゃんと記事にしたいけど、簡単に。。
ビットマップはBITMAPFILEHEADER、BITMAPINFOHEADERというヘッダ情報と
その後に続くデータ(ピクセル単位の色の情報)をもっている。
データ部は、初期化している部分を見れば多少わかると思うが、
RGB成分のBYTEデータ列で構成されている。
(RGBQUAD構造体というらしく、未使用領域含め4byte。
この未使用領域は4byteアライメントのために用いられるのかと)
なので、ビットマップのデータとして、、
(高さ)×(幅)×(色情報)
が必要となるので、領域確保の際 200*300*4 としている。
確保した領域は、1次元配列となっているが、CreateCompatibleBitmap
で指定した幅と高さにあわせて描画の際にラインが整えられるもよう。
また、いろいろなサイトで調べたところ、ビットマップの原点は
画像左下のようだが、自分の環境では左上が原点となっていた。
何故かは調べていない。
[BMP]ビットマップ表示2
ピクチャコントロールを使用したビットマップ表示
[作成環境]
・Visual Studi 2008 Standart Edition
・MFC-ダイアログベース
表示される結果は前回 と一緒。
①ダイアログエディタで、「Picture Control」をはりつけ、「Type」を「ビットマップ」にする。
②ID名を「IDC_STATIC」から任意のIDに変更する。例)ID_PICT
貼り付けたピクチャコントロールにコントロール変数を追加する。
public:
CStatic m_pict;
OnPaint() 関数を以下のように変更。
void CSampleDlg::OnPaint()
{
if (IsIconic())
{
・・・中略
}
else
{
CDialog::OnPaint();
// ビットマップを読み込み、ハンドルを取得
HBITMAP hbmp = (HBITMAP)LoadImage(0,
_T("C:\\sample.bmp"),
IMAGE_BITMAP,
0,
0,
LR_LOADFROMFILE);
// 取得したハンドルからビットマップオブジェクトを作成
CBitmap *bmp = bmp->FromHandle(hbmp);
// ピクチャコントロールにビットマップオブジェクトを割り当てる
m_pict.SetBitmap(*bmp);
}
}
こっちのやり方の方が簡単だけど、使い分け方はよくわかんね。
多分、ピクチャコントロールでは画像の回転とか色の反転が
できないのではないかとおもふ。