開発環境はVC++6 WindowsXPです。
DIBをjpeg変換してメモリ上に
(ディスクに持たずに)持ちたいと考えています。
GDI+でこういった実装は可能でしょうか。
ヒントでいいので、よろしくお願い致します。
現在、ここまで作成しています。
pBmpはnewなどを入れてません。
FromBITMAPINFO関数だけで動くと考えています。
Save関数で落ちてしまいます。
方向性など間違っていたらご指摘お願い致します。
Bitmap pBmp;
BITMAPINFOHEADER* pvbmpInfoHeader;
BITMAPINFO* pvbmpInfo;
:
(中略)
:
//pvbmpInfoHeaderに画像データが入ってることは
//確認済です
pvbmpInfo = (BITMAPINFO*)pvbmpInfoHeader;
pBmp->FromBITMAPINFO(m_pvbmpInfo, m_pvbmpInfoHeader+1);
CLSID encoderClsid;
WCHAR wszFileName[256];
MultiByteToWideChar(CP_ACP, 0, "C:\\test.jpg", -1, wszFileName, MAX_PATH);
if ( 0 <= GetEncoderClsid(L"image/jpeg",&encoderClsid) ){
//ここで落ちます。
pBmp->Save(wszFileName, &encoderClsid );
}
pBmp->FromBITMAPINFO(m_pvbmpInfo, m_pvbmpInfoHeader+1);
は
pBmp->FromBITMAPINFO(pvbmpInfo, pvbmpInfoHeader+1);
の間違いでした。
>pBmpはnewなどを入れてません。
じゃあ何入れているの?
正しくないポインタでのpBmp->hogeは間違った使い方だよ。
メンバにアクセスしなかったとか不正な処理にならないこともあるけど。
FromBITMAPINFO等に関しては使ったことないしわかりません。
返信ありがとうございます。
>じゃあ何入れているの?
何もいれずに、FromBITMAPINFOでビットマップのアドレスに
ポインタが移動するのかと考えてます。
C言語が正しく理解できてないのと、
FromBITMAPINFO関数に関する情報が探せてないので
詰まってしまってます。
> 何もいれずに、FromBITMAPINFOでビットマップのアドレスに
> ポインタが移動するのかと考えてます。
それはまずあり得ません。
というか、FromBITMAPINFO って static じゃないですか。
http://msdn.microsoft.com/en-us/library/ms536288.aspx
なので、
Bitmap * pBmp = Bitmap::FromBITMAPINFO( ... );
というのが正しい使い方です。
pBmp->FromBITMAPINFO(pvbmpInfo, pvbmpInfoHeader+1);
を
Bitmap * pBmp = Bitmap::FromBITMAPINFO(pvbmpInfo, pvbmpInfoHeader+1);
に修正することで動作いたしました。
ありがとうございます。
Save関数の引数でIStream型が指定できるようになっているのですが、
これはどういったものを指すのでしょうか。
下記に載せさせて頂いた他言語のサンプルだと
そういった型が存在していて、データを取得できるようなのですが、
VC++でcinやstreambufなど幾つか型を使用してみても
ビルドエラーになります。
IStreamとはどういった型を指すのか、
ヒントでもいいのでよろしくお願い致します。
Delphiのサンプル
http://blog.livedoor.jp/junki560/archives/22845646.html
.NETのサンプル
http://kait-field.spaces.live.com/Blog/cns!B90E9B4A3C4DFD66!401.entry
IStreamの派生クラスを自分で作れば
メモリにデータを保存するとか自由にできるってことだよ。
C++のcinやstreambufなどはこういった用途には使えない。
IStreamの派生クラスじゃないから。
C++標準ライブラリにあるオブジェクトでこの手のものに使えるものは無い。
.NETやCOMで使えるように作ったライブラリじゃないから。
CreateStreamOnHGlobalで
GlobalAllocによるメモリ用のIStreamのインスタンスが作れる。
面倒なので自作せずにこれで大抵済ませるね。
一旦メモリ置けば暗号化してファイル保存とか好き勝手できるから。
google検索してもMSDNの.NETのが見つかり
C++とは微妙に違うから不便だな。
ファイルを対象とするなら、IShellFolder::BindToObject でも IStream を取得できますね。
CreateStreamOnHGlobalを試させて頂きました。
うまく実装できてないからなのか、取得した中身が
予想したものを違うものが入っています。
BOOL CTestGDIDlg::CreateOnHGlobal(IStream** ppIStream)
{
HRESULT hr;
if(ppIStream == NULL)
return false;
HGLOBAL h = ::GlobalAlloc(GMEM_MOVEABLE, 100000);
hr = ::CreateStreamOnHGlobal(h,TRUE,ppIStream);
if(SUCCEEDED(hr) && *ppIStream)
return true;
*ppIStream = NULL;
return false;
}
上記の関数で作ったIStreamは
Save関数で落ちなくはなったのですが、
その後の処理で、
BYTE b[100];
ULONG ul;
pIStream->Read(b, 100, &ul);
と呼んでも変数bの中は
173 186 13 240 173 186 13 ・・・
と同じ数値が連続してあるだけでした。
Read関数は
Read(コピーされた情報が入る配列、
コピーするバイト数、
実際にコピーされたバイト数)
と解釈しております。
CreateOnHGlobal関数の実装が間違っていますでしょうか。
よろしくお願い致します。
IStream::Readなんてしないでメモリ直接見ればいいんじゃないの。
GlobalLock参照。
pIStream->Read(b, 100, &ul);
ulに読めたバイト数が入っているんだけど。
俺はCImage::Loadで使ったことしかないので推測だけど
先頭にIStream::SeekしてからIStream::Readするんじゃないの。
ところでSeekで相対移動0で現在位置を調べないと
データのサイズが判らないってことだろうか。
>IStream::Readなんてしないでメモリ直接見ればいいんじゃないの。
>GlobalLock参照。
これはCopyMemory関数を使うということでしょうか。
下記のHPを参考にしました。
http://oshiete1.goo.ne.jp/qa4892351.html
>先頭にIStream::SeekしてからIStream::Readするんじゃないの。
Seek後にRead関数を呼ぶと正しい値が取得できました。
CreateStreamFromHGlobal に渡した HGLOBAL を GlobalLock すればポインタが取得できる。
今回は HGLOBAL が CreateStreamFromHGlobal のローカル変数なので内部から触れない。
HGLOBAL を外に出すか、GetHGlobalFromStream を使う。
> 内部から触れない。
外部から
# ぐだぐだやorz
> HGLOBAL が CreateStreamFromHGlobal のローカル変数なので内部から触れない。
HGLOBAL が CreateOnHGlobal のローカル変数なので外部から触れない。
レスありがとうございます。
返信遅くなってすいません。
>CreateStreamFromHGlobal に渡した HGLOBAL を GlobalLock すればポインタが取得できる。
わかりやすいご説明、ありがとうございます。
戻り値にポインタが返ってきて、
それを操作する考え方が
なかったのでとてもためになりました。
メモリを操作する(動的配列など)ところは苦手だったのですが、
皆さんのおかげで、便利さがわかったので
今度から使えるように勉強していこうと思います。
ありがとうございました。
ツイート | ![]() |