Canon EDSDK MemoryStream イメージ
質問
しばらくCanon EDSDKと格闘してきました。ライブラリを取得してファイルをディスクに直接保存することはできますが、メモリ内のイメージ byte[] を取得できません。EDSDK ストリームを byte[] に Marshal.Copy() しようとすると、常に次のエラーが発生します。
アクセス違反例外:保護されたメモリの読み取りまたは書き込みを試行しました。これは多くの場合、他のメモリが破損していることを示しています。
以下は、ストリームを取得するために使用したコードのバリエーションの 1 つです。
private uint downloadImage(IntPtr directoryItem)
{
uint err = EDSDK.EDS_ERR_OK;
IntPtr stream = IntPtr.Zero;
// Get information of the directory item.
EDSDK.EdsDirectoryItemInfo dirItemInfo;
err = EDSDK.EdsGetDirectoryItemInfo(directoryItem, out dirItemInfo);
// Create a file stream for receiving image.
if (err == EDSDK.EDS_ERR_OK)
{
err = EDSDK.EdsCreateMemoryStream(dirItemInfo.Size, out stream);
}
// Fill the stream with the resulting image
if (err == EDSDK.EDS_ERR_OK)
{
err = EDSDK.EdsDownload(directoryItem, dirItemInfo.Size, stream);
}
// Copy the stream to a byte[] and
if (err == EDSDK.EDS_ERR_OK)
{
byte[] buffer = new byte[dirItemInfo.Size];
GCHandle gcHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
// The following line is where it blows up...
Marshal.Copy(stream, buffer, 0, (int)dirItemInfo.Size);
// ... Image manipulation, show user, whatever
}
return err;
}
ブレークポイントにより、(EdsDirectoryItemInfo オブジェクトを通じて) 画像が実際に存在することが明らかになりますが、なぜ例外が発生するのかわかりません。私は敗北を受け入れて、結果のイメージをディスクから読み取って、CreateFileStream メソッドを介して簡単に書き込むというアイデアを考えてきましたが、実際にはメモリ内のイメージを操作できればよいのです。
何か案は?
アップデート:この動作はバージョン 2.5 と 2.6 の両方で見られます。
解決
ちょうどグーグルで検索したところ EdsCreateMemoryStream
そして サンプルを見つけました ここでは、「メモリ ストリーム」からポインタを取得するための別の呼び出しがあります。
IntPtr pointerToBytes;
EDSDKLib.EDSDK.EdsGetPointer(stream, out pointerToBytes);
その後、使用できます pointerToBytes
読み取るソースとして Marshal.Copy
.
したがって、あなたが現在行っていることは、 が指す小さな制御構造のアドレスから始まる大量のバイトをコピーしようとしていると思います stream
, したがって、その構造の終わりを超えて読んでいることになります。
編集: ちなみに、あなたのコードは、return ステートメントは 1 つだけであるべきだと誰かに言われたかのように見えます。これは、Fortran や C などの言語に関する古いアドバイスです。現代語では意味が通じません。失敗するたびにすぐにエラー コードを返すと、(少なくともこの場合は) コードがより明確になります。
if ((err = EDSDK.EdsBlahBlah(...)) != EDSDK.EDS_ERR_OK)
return err;
(さらに良いのは、エラー コードと、何をしようとしていたかを説明する文字列を含む特定の例外クラスをスローすることです。)
他のヒント
私は、これは古い記事ですが、これは、メモリストリームからダウンロードするための完全なC#スニペットであることを認識しています。それは他の誰かのために有用である可能性があります。カメラはEDSDK.EdsSaveTo.HostまたはEDSDK.EdsSaveTo.Bothに設定する必要があります。
uint error = EDSDK.EDS_ERR_OK;
IntPtr stream = IntPtr.Zero;
EDSDK.EdsDirectoryItemInfo directoryItemInfo;
error = EDSDK.EdsGetDirectoryItemInfo(this.DirectoryItem, out directoryItemInfo);
//create a file stream to accept the image
if (error == EDSDK.EDS_ERR_OK)
{
error = EDSDK.EdsCreateMemoryStream(directoryItemInfo.Size, out stream);
}
//down load image
if (error == EDSDK.EDS_ERR_OK)
{
error = EDSDK.EdsDownload(this.DirectoryItem, directoryItemInfo.Size, stream);
}
//complete download
if (error == EDSDK.EDS_ERR_OK)
{
error = EDSDK.EdsDownloadComplete(this.DirectoryItem);
}
//convert to memory stream
IntPtr pointer; //pointer to image stream
EDSDK.EdsGetPointer(stream, out pointer);
uint length = 0;
EDSDK.EdsGetLength(stream, out length);
byte[] bytes = new byte[length];
//Move from unmanaged to managed code.
Marshal.Copy(pointer, bytes, 0, bytes.Length);
System.IO.MemoryStream memoryStream = new System.IO.MemoryStream(bytes);
Image image = System.Drawing.Image.FromStream(memoryStream);
if (pointer != IntPtr.Zero)
{
EDSDK.EdsRelease(pointer);
pointer = IntPtr.Zero;
}
if (this.DirectoryItem != IntPtr.Zero)
{
EDSDK.EdsRelease(this.DirectoryItem);
this.DirectoryItem = IntPtr.Zero;
}
if (stream != IntPtr.Zero)
{
EDSDK.EdsRelease(stream);
stream = IntPtr.Zero;
}