デバイスに依存しないビットマップであるDIBを、MFCっぽく使えるようなCDibクラスを作ってみました。 このページに書いてあるのは、自分の為の備忘録みたいなものですが。
構成:まずCDibがあります。その他にCDib08やCDib24といった、特定の色数専用のクラスがあります。
CDibだけで使えますが、汎用的に作ってあるため 効率が悪い面があります。
CDibnnというクラスはCDibを継承し、その色数に特化して効率よくしたものです。
また、CDib08Toneという、パレットを自動的に用意するクラスも作ってみました。
なお、自分で使う部分以外はあまり使い込んでいないので、ポカがあるかもしれません…。 何かバグを見つけたら教えて下さい。
メソッド名・引数 | 解説 | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
指定された属性のCDibを生成して返す。 パレットを使用しない場合(16bit色以上など)ではパレットの指定はNULL。 返されたCDib*は、deleteで削除する。 |
|||||||||||||||
|
指定されたCDibと同一属性のCDibを生成して返す。画像データはコピーされない。 返されたCDib*は、deleteで削除する。 |
|||||||||||||||
|
指定されたCBitmapと同一属性のCDibを生成して返す。画像データはコピーされない。 パレットを使用しない場合(16bit色以上など)ではパレットの指定はNULL。 返されたCDib*は、deleteで削除する。 |
|||||||||||||||
|
指定された属性で初期化を行う。通常はCreateの内部で呼ばれる。 | |||||||||||||||
|
指定された属性で初期化を行う。通常はCreateの内部で呼ばれる。 色数が異なるCDibを引数に指定した場合、動作不定。 |
メソッド名・引数 | 解説 | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
ファイルから読み込んで、CDibを生成して返す。 返されたCDib*は、deleteで削除する。 |
||||||||||||
|
ファイルから読み込んで、CDibを生成して返す。 fpの現在の位置からDataLenバイト読み込んでビットマップと見なす。DataLen=0の場合はデータを全て読み込む。 返されたCDib*は、deleteで削除する。 |
||||||||||||
|
指定されたデータをビットマップファイルデータと見なし、CDibを生成して返す。 返されたCDib*は、deleteで削除する。 |
||||||||||||
|
指定されたファイルに保存する。 | ||||||||||||
|
指定されたファイルに保存する。 |
なぜLoadがstaticでCDib*を返すようになっているかというと、 ファイルの中を見てみるまで色数が分からない、すなわち どのCDibnnを使えばいいのか 判断できないからです。
メソッド名・引数 | 解説 | |||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
内部で保持しているビットマップ(CBitmap)を返す。 | |||||||||
|
内部で保持しているパレット(CPalette)を返す。 pPal=NULLの時は内部で保持しているパレットを返す。 pPal≠NULLの時はpPalにパレットを転送する。 |
|||||||||
|
パレット(CPalette)を生成して返す。 pPal=NULLの時はnewで作ったパレットを返す。 pPal≠NULLの時はpPalにパレットを転送する。 |
|||||||||
|
ビットマップサイズ(ドット単位)を返す。 | |||||||||
|
ビットマップの横幅(ドット単位)を返す。 | |||||||||
|
ビットマップの高さ(ドット単位)を返す。 | |||||||||
|
色数(bit単位)を返す。 |
他に欲しい情報があったら、メソッドを追加して下さい。
デバイスコンテキストを介さずに、直接画像データを操作します。
CDibの中で色コードを扱うCOLORNOという型を定義してあります。
実体はただのDWORDですが。
色コードは、COLORNOの内の色数分(例:4bit色のときは下4bit)だけ使うようにして下さい。
座標体系は 素直に左上が(0,0)です。
メソッド名・引数 | 解説 | |||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
指定位置の色コードを返す。 座標が範囲外のときは0を返す。 |
左記メソッド名の末尾に0を付けたメソッドも用意してあります。これは、範囲チェックを行いません(その分だけ動作が速いが、下手に範囲外になってしまうと どうなることやら)。 | ||||||||||||||||||
|
指定位置の色をCOLORREFで返す。 座標が範囲外のときは色コード0のCOLORREFを返す。 |
|||||||||||||||||||
|
指定位置に色コードをセットする。 座標が範囲外のときはFALSEを返す。 |
|||||||||||||||||||
|
指定位置にCOLORREFに該当する色コードをセットする。 座標が範囲外のときはFALSEを返す。 |
|||||||||||||||||||
|
指定された色コードで指定された範囲を塗りつぶす。 座標を省略した場合は左上となる。 範囲を省略した場合はビットマップ全体となる。 |
|||||||||||||||||||
|
指定された範囲をコピーする。(同一色数・同一パレットが前提) 転送元DIBに透明色が指定されている場合は、透過処理も行う。 転送元座標を省略した場合は、転送元DIBの左上となる。 転送範囲を省略した場合は、転送元DIB全体となる。 |
|||||||||||||||||||
|
指定された範囲をコピーする。(色数等の前提は無し) 転送元DIBに透明色が指定されている場合は、透過処理も行う。 転送元座標を省略した場合は、転送元DIBの左上となる。 転送範囲を省略した場合は、転送元DIB全体となる。 |
ここでの透過処理は、転送元DIBを1ドットずつ透明色かどうかチェックし 透明色でなければ転送している。
メソッド名・引数 | 解説 | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
|
指定された色コードに割り当てられているCOLORREFを返す。 8bit色以下では、CDib生成時にパレットが無いと正常な値を返しません。 16bit色以上では、CDibnnを使っていない場合は正常な値を返しません。 |
||||||||||
|
指定された色に該当する色コードを返す。 8bit色以下では、CDib生成時のパレットの中から最も近い色を探して返します。 16bit色以上では、CDibnnを使っていない場合は正常な値を返しません。 constが付いていないのは、例えばクラス内部に色の配列を保持して随時書き換えるような実装を考えてのことです。今は使ってないけど…。 |
||||||||||
|
透明色を色コードでセットする。 | 「色コード」と「色」の間には、関連性は無い。 透過処理はCOLORNOかCOLORREFのいずれかで行うが、後から指定された方で処理を行う。 SetTranslateColorで指定した色コードはGetTranslateColorrefでは取得できない。 ここで指定された透過色は、CopyFromやBitBltで使用される。 |
|||||||||
|
透明色を色でセットする。 | ||||||||||
|
色コード指定時の透明色を返す。 | ||||||||||
|
色指定時の透明色を返す。 |
メソッド名・引数 | 解説 | |||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
デバイスコンテキストを利用して、指定位置にCOLORREFの色をセットする。 座標が範囲外のときはFALSEを返す。 |
|||||||||||||||||||||
|
デバイスコンテキストを利用して、指定されたビットマップをコピーする。 転送元座標を省略した場合は、転送元ビットマップの左上となる。 転送範囲を省略した場合は、転送元ビットマップ全体となる。 |
|||||||||||||||||||||
|
デバイスコンテキストにビットマップの指定範囲を描画する。 ラスタオペレーションに(オリジナルの)T_SRCCOPYを指定すると、透過処理を行う。 |
|||||||||||||||||||||
|
デバイスコンテキストにビットマップ全体を描画する。 ラスタオペレーションに(オリジナルの)T_SRCCOPYを指定すると、透過処理を行う。 |
ここでの透過処理は、指定された透明色のマスク(1bit色DIB)を用意し、 ラスタオペレーションのSRCAND・NOTSRCCOPY・SRCPAINTを使って実現している。
#include "dib.h" class CDibSampleDoc : public CDocument { 〜 public: CDib* GetDIB()const { return m_pDib; } 〜 private: CDib *m_pDib; };DibSampleDoc.cpp:
///////////////////////////////////////////////////////////////////////////// // CDibSampleDoc クラスの構築/消滅 CDibSampleDoc::CDibSampleDoc() { // TODO: この位置に1回だけ構築用のコードを追加してください。 m_pDib=NULL; } CDibSampleDoc::~CDibSampleDoc() { delete m_pDib; } BOOL CDibSampleDoc::OnNewDocument() { if (!CDocument::OnNewDocument()) return FALSE; // TODO: この位置に再初期化処理を追加してください。 // (SDI ドキュメントはこのドキュメントを再利用します。) delete m_pDib;m_pDib=NULL; return TRUE; } ///////////////////////////////////////////////////////////////////////////// // CDibSampleDoc シリアライゼーション void CDibSampleDoc::Serialize(CArchive& ar) { if (ar.IsStoring()) { // TODO: この位置に保存用のコードを追加してください。 if(m_pDib) m_pDib->Save(ar.GetFile()); } else { // TODO: この位置に読み込み用のコードを追加してください。 m_pDib=CDib::Load(ar.GetFile()); } }DibSampleView.cpp
void CDibSampleView::OnDraw(CDC* pDC) { CDibSampleDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); // TODO: この場所にネイティブ データ用の描画コードを追加します。 CDib *pDib=pDoc->GetDIB(); if(pDib){ //デバイスコンテキストに描画 pDib->BitBlt(pDC,0,0,SRCCOPY); //同じサイズ・同じ属性のDIBをもう1つ作成 CDib *dp=CDib::Create(m_pDib->GetSize(),m_pDib); //DIBの画像データをコピー dp->CopyFrom(CPoint(0,0),m_pDib,CPoint(0,0),m_pDib->GetSize()); //左上の位置の色を透明色として設定 COLORNO n=m_pDib->GetColor(CPoint(0,0)); dp->SetTranslateColor(n); //左半分だけ透明色で塗り潰し dp->Fill(n,CPoint(0,0),CSize(pDib->GetWidth()/2,0)); //1つめのDIBの下に、透明色ありで描画 int dy=pDib->GetHeight(); dp->BitBlt(pDC,0,dy+16,T_SRCCOPY); delete dp; } }
8bit色DIBの場合、パレットが必要です。でも一般的な色で使う場合は
いちいちパレットを用意するのが面倒なので、
赤8段階・緑8段階・青4段階の合計256色で扱えるクラスを CDib08クラスから派生して作ってみました。
このクラスの利点は、色コードとCOLORREFの関係が計算によって出せるので
GetColorrefが高速になることです。
CDibnnはCDib::Create()の中で選択して返すように作ってありますが、
CDib08Toneは特殊なので そうしていません。newで作る必要があります。
それ以外の使い方はCDibと同じです。
#include "dib08tone.h" 〜 void CDibSampleView::OnDraw(CDC* pDC) { CDibSampleDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); // TODO: この場所にネイティブ データ用の描画コードを追加します。 CDib *pDib=new CDib08Tone(CSize(16,16)); COLORNO n=0; for(int y=0;y<16;y++){ for(int x=0;x<16;x++) pDib->SetColor0(CPoint(x,y),n++); } pDib->BitBlt(pDC,8,8,SRCCOPY); delete pDib; }