简体   繁体   English

佳能EDSDK MemoryStream图像

[英]Canon EDSDK MemoryStream Image

I've been fighting with the Canon EDSDK for a while now. 我一直在与佳能EDSDK作战。 I can successfully get the library to save a file directly to disk, however, I cannot get a hold of the image byte[] in memory. 我可以成功地获得将文件直接保存到磁盘的库,但是,我无法在内存中保留图像byte []。 Whenever I attempt to Marshal.Copy() the EDSDK Stream to byte[], I always get the following error: 每当我尝试将EDSDK流编组为byte []时,总是会出现以下错误:

AccessViolationException: Attempted to read or write protected memory. AccessViolationException:尝试读取或写入受保护的内存。 This is often an indication that other memory is corrupt. 这通常表明其他内存已损坏。

Below is one of the variations of code that I've used to try and get the stream: 以下是我用来尝试获取流的代码的变体之一:

        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;
        }

Breakpoints reveal (Through the EdsDirectoryItemInfo object) that the image is indeed there, I just don't know why I'd be getting the exception that I am. 断点显示(通过EdsDirectoryItemInfo对象)图像确实存在,我只是不知道为什么我会得到我自己的异常。 I have been toying with the idea of accepting defeat and just read the resultant image from disk that it so readily writes via the CreateFileStream method, but I really ought to just be able to manipulate the image in memory. 我一直在接受接受失败的想法,只是从磁盘读取生成的图像,这样就很容易通过CreateFileStream方法写入该图像,但是我真的应该只能够操作内存中的图像。

Any ideas? 有任何想法吗?

UPDATE: I see this behavior in both versions 2.5 and 2.6. 更新:我在版本2.5和2.6中都看到了此行为。

I just googled for EdsCreateMemoryStream and found a sample in which there's another call to get the pointer from the "memory stream". 我只是在EdsCreateMemoryStream搜索了EdsCreateMemoryStream找到了一个示例,在该示例中还有另一个调用以从“内存流”中获取指针。

IntPtr pointerToBytes;
EDSDKLib.EDSDK.EdsGetPointer(stream, out pointerToBytes);

You can then use pointerToBytes as the source to read from in Marshal.Copy . 然后,可以在Marshal.Copy使用pointerToBytes作为要读取的源。

So I'd guess that what you're currently doing is attempting to copy some large number of bytes starting from the address of some small control structure pointed to by stream , and hence you're reading past the end of that structure. 因此,我想您当前正在做的是尝试从stream指向的一些小型控制结构的地址开始复制大量字节,因此您正在读取该结构的末尾。

Edit: By the way, you're code looks as if someone's told you that you should only have one return statement! 编辑:顺便说一句,您的代码看起来好像有人告诉您只应有一个return语句! That's old advice relating to languages like Fortran and C; 这是与Fortran和C等语言有关的旧建议; it doesn't make sense in modern languages. 在现代语言中这没有意义。 Your code would be clearer (at least in this case) if you immediately returned the error code every time you got a failure: 如果您每次遇到故障都立即返回错误代码,则您的代码将更加清晰(至少在这种情况下):

if ((err = EDSDK.EdsBlahBlah(...)) != EDSDK.EDS_ERR_OK)
    return err;

(Better yet, throw a specific exception class containing the error code and a string explaining what you were trying to do.) (更好的是,抛出一个特定的异常类,其中包含错误代码和说明您要执行的操作的字符串。)

I realize that this is an old post, but this is a complete C# snippet for downloading from a memory stream. 我意识到这是一篇老文章,但这是用于从内存流下载的完整C#代码段。 It may be useful for someone else. 这对其他人可能有用。 The camera needs to be set to EDSDK.EdsSaveTo.Host or EDSDK.EdsSaveTo.Both 摄像机需要设置为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;
        }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM