S-JIS[2003-01-05]

ひしだまオリジナル CDibクラス

デバイスに依存しないビットマップであるDIBを、MFCっぽく使えるようなCDibクラスを作ってみました。 このページに書いてあるのは、自分の為の備忘録みたいなものですが。

cdib.lzh(16.9 kBYTE)

構成:まずCDibがあります。その他にCDib08やCDib24といった、特定の色数専用のクラスがあります。
CDibだけで使えますが、汎用的に作ってあるため 効率が悪い面があります。 CDibnnというクラスはCDibを継承し、その色数に特化して効率よくしたものです。
また、CDib08Toneという、パレットを自動的に用意するクラスも作ってみました。

なお、自分で使う部分以外はあまり使い込んでいないので、ポカがあるかもしれません…。 何かバグを見つけたら教えて下さい。


CDib生成・初期化

メソッド名・引数 解説
static CDib* Create(
const CSize&sz,//ビットマップサイズ
WORDBitCount,//色数(bit単位)
CPalette*pPal=NULL//パレット
)
指定された属性のCDibを生成して返す。
パレットを使用しない場合(16bit色以上など)ではパレットの指定はNULL。
返されたCDib*は、deleteで削除する。
static CDib* Create(
const CSize&sz,//ビットマップサイズ
const CDib*pSrc//元となるCDib
)
指定されたCDibと同一属性のCDibを生成して返す。画像データはコピーされない。
返されたCDib*は、deleteで削除する。
static CDib* Create(
const CSize&sz,//ビットマップサイズ
CBitmap*pSrc,//元となるCBitmap
CPalette*pPal=NULL//パレット
)
指定されたCBitmapと同一属性のCDibを生成して返す。画像データはコピーされない。
パレットを使用しない場合(16bit色以上など)ではパレットの指定はNULL。
返されたCDib*は、deleteで削除する。
BOOL Init(
const CSize&sz,//ビットマップサイズ
WORDBitCount,//色数(bit単位)
CPalette*pPal=NULL//パレット
)
指定された属性で初期化を行う。通常はCreateの内部で呼ばれる。
BOOL Init(
const CSize&sz,//ビットマップサイズ
const CDib*pSrc//元となるCDib
)
指定された属性で初期化を行う。通常はCreateの内部で呼ばれる。
色数が異なるCDibを引数に指定した場合、動作不定。

ファイル読み書き

メソッド名・引数 解説
static CDib* Load(
LPCTSTRpName//ファイル名
)
ファイルから読み込んで、CDibを生成して返す。
返されたCDib*は、deleteで削除する。
static CDib* Load(
CFile*fp,//ファイル
UINTDataLen=0//読み込み長
)
ファイルから読み込んで、CDibを生成して返す。
fpの現在の位置からDataLenバイト読み込んでビットマップと見なす。DataLen=0の場合はデータを全て読み込む。
返されたCDib*は、deleteで削除する。
static CDib* Load(
const BYTE*pData,//データの先頭アドレス
UINTDataLen//データの長さ
)
指定されたデータをビットマップファイルデータと見なし、CDibを生成して返す。
返されたCDib*は、deleteで削除する。
BOOL Save(
LPCTSTRpName//ファイル名
)
指定されたファイルに保存する。
BOOL Save(
CFile*fp//ファイル
)
指定されたファイルに保存する。

なぜLoadがstaticでCDib*を返すようになっているかというと、 ファイルの中を見てみるまで色数が分からない、すなわち どのCDibnnを使えばいいのか 判断できないからです。


ビットマップ情報取得

メソッド名・引数 解説
CBitmap* GetBitmap() const
内部で保持しているビットマップ(CBitmap)を返す。
CPalette* GetPalette(
CPalette*pPal=NULL//パレット
)
内部で保持しているパレット(CPalette)を返す。
pPal=NULLの時は内部で保持しているパレットを返す。
pPal≠NULLの時はpPalにパレットを転送する。
CPalette* CreatePalette(
CPalette*pPal=NULL//パレット
) const
パレット(CPalette)を生成して返す。
pPal=NULLの時はnewで作ったパレットを返す。
pPal≠NULLの時はpPalにパレットを転送する。
CSize GetSize() const
ビットマップサイズ(ドット単位)を返す。
int GetWidth() const
ビットマップの横幅(ドット単位)を返す。
int GetHeight() const
ビットマップの高さ(ドット単位)を返す。
WORD GetBitCount() const
色数(bit単位)を返す。

他に欲しい情報があったら、メソッドを追加して下さい。


画像直接操作

デバイスコンテキストを介さずに、直接画像データを操作します。

CDibの中で色コードを扱うCOLORNOという型を定義してあります。 実体はただのDWORDですが。
色コードは、COLORNOの内の色数分(例:4bit色のときは下4bit)だけ使うようにして下さい。

座標体系は 素直に左上が(0,0)です。

メソッド名・引数 解説
COLORNO GetColor(
const CPoint&pt//座標
) const
指定位置の色コードを返す。
座標が範囲外のときは0を返す。
左記メソッド名の末尾に0を付けたメソッドも用意してあります。これは、範囲チェックを行いません(その分だけ動作が速いが、下手に範囲外になってしまうと どうなることやら)。
COLORREF GetPixel(
const CPoint&pt//座標
) const
指定位置の色をCOLORREFで返す。
座標が範囲外のときは色コード0のCOLORREFを返す。
BOOL SetColor(
const CPoint&pt,//座標
COLORNOn//色コード
)
指定位置に色コードをセットする。
座標が範囲外のときはFALSEを返す。
BOOL SetPixel(
const CPoint&pt,//座標
COLORREFc//色
)
指定位置にCOLORREFに該当する色コードをセットする。
座標が範囲外のときはFALSEを返す。
BOOL Fill(
COLORNOn,//色コード
CPointpt=CPoint(0,0),//座標
CSizesz=CSize(0,0)//範囲
)
指定された色コードで指定された範囲を塗りつぶす。
座標を省略した場合は左上となる。
範囲を省略した場合はビットマップ全体となる。
BOOL CopyFrom(
CPointdt,//転送先座標
const CDib*pSrc,//転送元DIB
CPointst=CPoint(0,0),//転送元座標
CSizesz=CSize(0,0)//転送範囲
)
指定された範囲をコピーする。(同一色数・同一パレットが前提)
転送元DIBに透明色が指定されている場合は、透過処理も行う。
転送元座標を省略した場合は、転送元DIBの左上となる。
転送範囲を省略した場合は、転送元DIB全体となる。
BOOL CopyFromDiff(
CPointdt,//転送先座標
const CDib*pSrc,//転送元DIB
CPointst=CPoint(0,0),//転送元座標
CSizesz=CSize(0,0)//転送範囲
)
指定された範囲をコピーする。(色数等の前提は無し)
転送元DIBに透明色が指定されている場合は、透過処理も行う。
転送元座標を省略した場合は、転送元DIBの左上となる。
転送範囲を省略した場合は、転送元DIB全体となる。

ここでの透過処理は、転送元DIBを1ドットずつ透明色かどうかチェックし 透明色でなければ転送している。


色コード関連

メソッド名・引数 解説
COLORREF GetColorref(
COLORNOn//色コード
) const
指定された色コードに割り当てられているCOLORREFを返す。
8bit色以下では、CDib生成時にパレットが無いと正常な値を返しません。
16bit色以上では、CDibnnを使っていない場合は正常な値を返しません。
COLORNO GetColor(
COLORREFc//色
)
指定された色に該当する色コードを返す。
8bit色以下では、CDib生成時のパレットの中から最も近い色を探して返します。
16bit色以上では、CDibnnを使っていない場合は正常な値を返しません。
constが付いていないのは、例えばクラス内部に色の配列を保持して随時書き換えるような実装を考えてのことです。今は使ってないけど…。
void SetTranslateColor(
COLORNOn//色コード
)
透明色を色コードでセットする。 「色コード」と「色」の間には、関連性は無い。
透過処理はCOLORNOかCOLORREFのいずれかで行うが、後から指定された方で処理を行う。 SetTranslateColorで指定した色コードはGetTranslateColorrefでは取得できない。
ここで指定された透過色は、CopyFromBitBltで使用される。
void SetTranslateColor(
COLORREFc//色
)
透明色を色でセットする。
COLORNO GetTranslateColor(
) const
色コード指定時の透明色を返す。
COLORREF GetTranslateColorref(
) const
色指定時の透明色を返す。

デバイスコンテキスト関連操作

メソッド名・引数 解説
BOOL SetPixel(
const CPoint&pt,//座標
COLORREFc,//色
CDC*pDC//デバイスコンテキスト
)
デバイスコンテキストを利用して、指定位置にCOLORREFの色をセットする。
座標が範囲外のときはFALSEを返す。
BOOL CopyFrom(
CPointdt,//転送先座標
CDC*pDC,//デバイスコンテキスト
CBitmap*pSrc,//転送元Bitmap
CPointst=CPoint(0,0),//転送元座標
CSizesz=CSize(0,0)//転送範囲
)
デバイスコンテキストを利用して、指定されたビットマップをコピーする。
転送元座標を省略した場合は、転送元ビットマップの左上となる。
転送範囲を省略した場合は、転送元ビットマップ全体となる。
BOOL BitBlt(
CDC*pDC,//デバイスコンテキスト
intdx,dy,//転送先座標
intcx,cy,//転送範囲
intsx,sy,//転送元座標
DWORDdwRop//ラスタオペレーション
)
デバイスコンテキストにビットマップの指定範囲を描画する。
ラスタオペレーションに(オリジナルの)T_SRCCOPYを指定すると、透過処理を行う。
BOOL BitBlt(
CDC*pDC,//デバイスコンテキスト
intdx,dy,//転送先座標
DWORDdwRop//ラスタオペレーション
)
デバイスコンテキストにビットマップ全体を描画する。
ラスタオペレーションに(オリジナルの)T_SRCCOPYを指定すると、透過処理を行う。

ここでの透過処理は、指定された透明色のマスク(1bit色DIB)を用意し、 ラスタオペレーションのSRCAND・NOTSRCCOPY・SRCPAINTを使って実現している。


サンプル

DibSampleDoc.h:
#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;
	}
}

CDib08Tone

8bit色DIBの場合、パレットが必要です。でも一般的な色で使う場合は いちいちパレットを用意するのが面倒なので、 赤8段階・緑8段階・青4段階の合計256色で扱えるクラスを CDib08クラスから派生して作ってみました。
このクラスの利点は、色コードとCOLORREFの関係が計算によって出せるので GetColorrefが高速になることです。

CDibnnはCDib::Create()の中で選択して返すように作ってありますが、 CDib08Toneは特殊なので そうしていません。newで作る必要があります。
それ以外の使い方はCDibと同じです。

DibSampleView.cpp:
#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;
}

DIBのページへ戻る / VC++ページへ戻る / 技術メモへ戻る / 自作ソフトへ戻る
メールの送信先:ひしだま