CBitmapのコピーをするには – プログラミング – Home

CBitmapのコピーをするには
 
通知
すべてクリア

[解決済] CBitmapのコピーをするには

固定ページ 1 / 2

shogo
 shogo
(@shogo)
ゲスト
結合: 20年前
投稿: 31
Topic starter  

おはようございます,shogoと申します.

開発環境はWinXP,VC7,MFCです.

あるクラスにあるCBitmapを関数の呼び出し側のCBitmapにコピーしたいので,
CBitmapを返す関数CBitmap GetBitmap(void)を以下のように定義したのですが,
(やりたいことは,CBitmap mBitmap = GetBitmap();という感じでコピーして,
この受け取ったCBitmapを表示したい.)
CBitmap CXXX::GetBitmap(void)
{
return bitmap;
}
「class 'CBitmap':コピーコンストラクタが使用できないか,
'explicit'として宣言されています.」
というエラーが出ます.

このエラーの意味と,これの対処方法を教えていただけないでしょうか?

よろしくお願いします.


引用未解決
トピックタグ
dairygoods
 dairygoods
(@dairygoods)
ゲスト
結合: 23年前
投稿: 1421
 

コピーコンストラクタが定義されていないため、
コピーできないという意味です。

実際、ビットマップをコピーする必要はあるのでしょうか?
(たとえば、同じ元絵を複製して加工したいなど)


返信引用
shogo
 shogo
(@shogo)
ゲスト
結合: 20年前
投稿: 31
Topic starter  

shogoです.

> 実際、ビットマップをコピーする必要はあるのでしょうか?
とのことですが,必要があるとは思っているんですが.
やりたいことは,「同じ元絵を複製して加工」に近いことです.

よろしくお願いします.


返信引用
dairygoods
 dairygoods
(@dairygoods)
ゲスト
結合: 23年前
投稿: 1421
 

でしたら、必要になるたびにロードする方法はいかがでしょう。

void CXXX::GetBitmap(CBitmap& bitmap)
{
bitmap.LoadBitmap(...);
}


返信引用
shogo
 shogo
(@shogo)
ゲスト
結合: 20年前
投稿: 31
Topic starter  

shogoです.

dairygoodsさん,
CBitmapはファイルから読み込んで作っているのではなく,
動的に自分で作っています(動画の1フレームをキャプチャして).
ですから,
bitmap.LoadBitmap(...);
は使えないと思います.


返信引用
dairygoods
 dairygoods
(@dairygoods)
ゲスト
結合: 23年前
投稿: 1421
 

では、
GetBitmapBitでビット情報を取得し、
CreateBitmapで新しいビットマップを作るという方法はどうでしょう。


返信引用
Ban
 Ban
(@ban)
Prominent Member
結合: 5年前
投稿: 776
 

新しい CBitmap を DC にマッピングして BitBlt するとか、
割と普通な気がします。

# リソースのコピーは通常重いから、わざと noncopyable なんですよね。


返信引用
shogo
 shogo
(@shogo)
ゲスト
結合: 20年前
投稿: 31
Topic starter  

dairygoodsさん,Banさん,レスありがとうございます.

> リソースのコピーは通常重いから
とのことですので,
例えば,
GetCDC(CDC* pDC) {
pDC->SelectObject(&bitmap); //CBitmap bitmap;
}
といったような関数を作ってやれば,よいのでしょうか?

よろしくお願いいたします.


返信引用
Ban
 Ban
(@ban)
Prominent Member
結合: 5年前
投稿: 776
 

> この受け取ったCBitmapを表示したい.

だけで、特に変更などしないならこれでいいのでは?

const CBitmap& CXXX::GetBitmap(void)
{
return bitmap;
}
const CBitmap& mBitmap = GetgetBitmap();
// 後はこの mBitmap を表示する

もし、ディープコピーしたいのであれば、例えばこんな感じ?

void // エラーチェックはご随意に
CXXX::GetBitmap(CBitmap& dst)
{
// 作業用にコンパチブル辺りの DC を確保(もしくはクラスメンバに保持しておく)
// DC に dst を SelectObject
// DC に bitmap を BitBlt
// DC から dst を切り離し
}
で、
GetBitmap(mBitmap); // mBitmap を作成して渡し、内容を複製してもらう。

# 後は、CBitmap を継承して、上記処理を
# public なコピーコンストラクタとして書けば、
# 複製可能ビットマップクラスも作れる...かも?


返信引用
shogo
 shogo
(@shogo)
ゲスト
結合: 20年前
投稿: 31
Topic starter  

shogoです.

> const CBitmap& CXXX::GetBitmap(void)
> {
> return bitmap;
> }
> const CBitmap& mBitmap = GetgetBitmap();
> // 後はこの mBitmap を表示する
こちらの場合,CXXXの方でフレームキャプチャしなおしたら,
呼び出した側のビットマップ(ここでいうmBitmap)
も変わるように思えるのですが,そういうことはないですか?
(OnDrawが呼ばれると,表示が変わるということです.)

ちょっと具体的に,目標を言いますと,
キャプチャしたら(bitmapにフレームキャプチャ),
mBitmapの方の表示は常に変えるのではなくて,
こちらが指示をしたらmBitmapの方を変更という形にしたいと思っています.
(bitmapにキャプチャするごとに,mBitmapも変化しては困る.)

よろしくお願いします.


返信引用
Ban
 Ban
(@ban)
Prominent Member
結合: 5年前
投稿: 776
 

> こちらの場合,CXXXの方でフレームキャプチャしなおしたら,
> 呼び出した側のビットマップ(ここでいうmBitmap)
> も変わるように思えるのですが,そういうことはないですか?

CXXX が情報を保持しつづけないのであれば、(勿論)変わります。
上の記述からすると CXXX は画像のキャプチャが責務のようですが、
CXXX という名前からはそこまで察することは出来ませんでしたので...。
メンバのビットマップは更新されるんですね。

もっとも、OnDraw との関連性は分かりませんので、それが
> (OnDrawが呼ばれると,表示が変わるということです.)
に繋がるかどうかは、shogo さんの構成によるかと思います。

GetBitmap で取れる参照を常にそのまま OnDraw の中で BitBlt
していると OnDraw の度に更新されてしまうでしょうし、
更新制御なりしていればそうならないように使うことも可能です。

>(bitmapにキャプチャするごとに,mBitmapも変化しては困る.)

私の先の例だと、mBitmap が const CBitmap& になっていたので
誤解させてしまったようですが、更新されたくないのであれば、
取得した CBitmap の参照をそのまま保持/表示するのではなく、
更新時に、表示用DC にマッピングした mBitmap にでも BitBlt
するようにすればいいのではないかと思います。

もしくは、下記のように明示的に Bitmap に複製しておいても構いませんが。

>> void // エラーチェックはご随意に
>> CXXX::GetBitmap(CBitmap& dst)
-- snip --
>> GetBitmap(mBitmap); // mBitmap
>> を作成して渡し、内容を複製してもらう。

いずれにしても、Bitmap から Bitmap に手軽に転送するのは
DC に割り付けて BitBlt だと思います。
前者と後者の違いは呼び元と呼び先のどちらがコピーを行うかだけで、
作業用の DC が必要ない(描画用の DC をそのまま利用可能)分、
前者の方が若干いいのではないかとは思います。


返信引用
shogo
 shogo
(@shogo)
ゲスト
結合: 20年前
投稿: 31
Topic starter  

shogoです.

> DC に割り付けて BitBlt だと思います。
の方法のほうがよさそうということはわかりますが,
考えた方法があっているか,よくわかりません.

私は,以下のように考えました.
まず,呼び出される側CXXXの方で,次の関数を定義する.
CBitmap* CXXX::GetCDC(CDC* pDC) {
return pDC->SelectObject(&bitmap); //CBitmap bitmap;
}
呼び出し側は,なんかの関数内で,
CDC* pDC = GetDC();
CDC dc;
dc.CreateCompatibleDC(pDC);
CBitmap *pOld = GetDC(&dc); //コピー関数
pDC->BitBlt(0,0,320,240,&dc,0,0,SRCCOPY);
dc.SelectObject(pOld);
とする,と考えました.
(CDC dc;はメンバ変数にしておく?)

いかかでしょう?こういうことでしょうか?
よろしくお願いいたします.


返信引用
Ban
 Ban
(@ban)
Prominent Member
結合: 5年前
投稿: 776
 

shogo さんの元のコードが GetBitmap でしたので、
それを踏襲して CXXX からは CBitmap を返し、
> pDC->SelectObject(&bitmap); //CBitmap bitmap;
に相当する処理をクライアント側で...という方向で書いていましたが、
コピー処理自体は shogo さんの認識された方法とほぼ一緒です。

# コピー禁止のオブジェクトはポインタか参照でアクセスするのが一般的な
# セオリーですが、Bitmap の場合は、DC へのマッピングでも
# 同種のことが実現可能なので、shogo さんの方法も有効だと思います。

当初の目的通り CBitmap が欲しいのであれば、それを割り当ててから
BitBlt すればいいでしょうし、そのいずれかを保存しておけば、
CXXX::bitmap が更新されても、OnDraw で表示が更新されてしまう
ことはないはずです。


返信引用
shogo
 shogo
(@shogo)
ゲスト
結合: 20年前
投稿: 31
Topic starter  

dairygoodsさん,Banさん,ありがとうございました.

まとめとしましては,
CBitmapのコピーは重いため,あまり推奨された方法ではなく,
表示だけの問題であれば,
CBitmapをDCにマッピングしてBitBltするなどの処置をしたほうがよい.

私の考えた方法は以下の通りです.
まず,呼び出される側CXXXの方で,次の関数を定義する.
CBitmap* CXXX::GetDC(CDC* pDC) {
return pDC->SelectObject(&bitmap); //CBitmap bitmap;
}
呼び出し側は,なんかの関数内で,
CDC* pDC = GetDC();
CDC dc;
dc.CreateCompatibleDC(pDC);
CBitmap *pOld = GetDC(&dc); //定義した関数
pDC->BitBlt(0,0,320,240,&dc,0,0,SRCCOPY);
dc.SelectObject(pOld);
(CDC dc;はメンバ変数にしておく?)
というようにすれば表示可能.


返信引用
やすい
 やすい
(@やすい)
ゲスト
結合: 20年前
投稿: 2
 

私もクリップボードからHBITMAPを取り出す為に以下の様な関数を作りました。

HBITMAP CopyHBITMAP(const HBITMAP bmp )
{
HBITMAP srcBmp ;
DIBSECTION sec ={0,};
void* data = 0 ;
CDC* pDC = AfxGetMainWnd()->GetDC() ;
// この時点ではパレットは不明
::GetObject(bmp,sizeof(DIBSECTION),&sec) ;
BITMAPINFO* pInfo = (BITMAPINFO*) ::GlobalAlloc( GPTR ,
sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 256 ) ;
if( sec.dsBmih.biSize == sizeof(BITMAPINFOHEADER) &&
sec.dsBm.bmWidth == sec.dsBmih.biWidth &&
sec.dsBm.bmHeight == sec.dsBmih.biHeight )
{
memcpy(pInfo,&sec.dsBmih,sizeof(BITMAPINFOHEADER) ) ;
pInfo->bmiHeader.biCompression = 0 ;

//作る時にはパレットは空
VERIFY( srcBmp = CreateDIBSection(pDC->GetSafeHdc(),pInfo,
sec.dsBmih.biBitCount > 8 ? DIB_RGB_COLORS : DIB_PAL_COLORS,
&data,0,0) ) ; }
else
{
pInfo->bmiHeader.biPlanes = sec.dsBm.bmPlanes ;
pInfo->bmiHeader.biBitCount = sec.dsBm.bmBitsPixel ;
pInfo->bmiHeader.biWidth = sec.dsBm.bmWidth ;
pInfo->bmiHeader.biHeight = sec.dsBm.bmHeight ;
pInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER) ;
int pal_size = sec.dsBm.bmBitsPixel > 8 ? 0 : ( 1 <<
sec.dsBm.bmBitsPixel ) ;
pInfo->bmiHeader.biSizeImage = sizeof(BITMAPINFOHEADER) +
pal_size + sec.dsBm.bmWidthBytes * sec.dsBm.bmHeight ;

//作る時にはパレットは空
VERIFY( srcBmp = ::CreateDIBitmap(pDC->GetSafeHdc(),
(BITMAPINFOHEADER*)pInfo,CBM_INIT,&data,pInfo,
sec.dsBm.bmBitsPixel > 8 ? DIB_RGB_COLORS : DIB_PAL_COLORS) );
}
VERIFY(::GetDIBits(pDC->GetSafeHdc(),bmp,0,sec.dsBm.bmHeight,data,pInfo,
sec.dsBm.bmBitsPixel > 8 ? DIB_RGB_COLORS : DIB_PAL_COLORS)) ;
// ここでパレットを取得できるが、secBmpにセットする方法が見つかりません。
::GlobalFree(pInfo) ;
AfxGetMainWnd()->ReleaseDC(pDC) ;
return srcBmp ;
}
フルカラーはきちんと取り込めるのですが、パレットの内容が取り込めません。
ソースの中でpInfoにパレットを取得できるのですが、それをHBITMAPにセットする
方法が分りません。どのような方法が考えられるでしょうか。

あとbiCompressionが16bitカラーの場合、3になってしまいますが、それではきちんと
表示されないので、0に変えてしまっているのですが、問題になるケースがあるのでしょうか。


返信引用
固定ページ 1 / 2

返信する

投稿者名

投稿者メールアドレス

タイトル *

プレビュー 0リビジョン 保存しました
共有:
タイトルとURLをコピーしました