First, I've read the a few questions regarding this issue, the most helpful being: https://stackoverflow.com/questions/27463876/passing-bitmap-from-c-sharp-to-c
I was unable to get the provided solutions to work as I kept getting an AccessViolationException
.
What I'm attempting to do is pass bitmap data to an unmanaged c++ dll. To do this I created a struct which holds a pointer to the image data as well as its length. I'm using a struct as I plan on passing in multiple images (in a single call) to the unmanaged API.
What I implemented works but I have a feeling there is probably some serious drawbacks so I'm curious as to what those drawbacks could be.
My current solution uses a generic pointer to hold the image data. This of course would be a drawback as I lose type safety. Anyway here is the relevant code.
C++ dll
raw_image.h
struct raw_image
{
void* data;
int size;
};
alignment.cpp (exports)
ALIGNMENT_API void submit( raw_image& img )
{
cv::Mat mat = cv::imdecode( cv::_InputArray(
static_cast<uchar*>( img.data ), img.size ), cv::IMREAD_COLOR );
cv::imshow( "image", mat );
cv::waitKey( );
cv::destroyWindow( "image" );
}
C# dll
RawImage.cs
[StructLayout( LayoutKind.Sequential )]
internal unsafe struct RawImage
{
internal void* ImageData;
internal int Size;
}
Aligner.cs (import)
[DllImport( "alignment-vc141-mtd-x64.dll", CallingConvention =
CallingConvention.Cdecl )]
static extern void submit( RawImage img );
And this is where I pass the image to the unmanaged API.
using( var bitmap = new Bitmap( "AlignmentCenter.jpg" ) )
using( var stream = new MemoryStream( ) )
{
bitmap.Save( stream, ImageFormat.Jpeg );
var source = stream.ToArray( );
fixed( void* ptr = source )
{
var raw = new RawImage
{
ImageData = ptr,
Size = source.Length
};
submit( raw );
}
}
Is what I'm doing unsafe? Am I copying more than I should?
One last thing, I know about EmguCv
and I've used it in the past but I won't be using it here.
c++/cli
wrapper for the native API and let it do the hard lifting with pointers and calling the native function so that you can keep your C# code clean. \$\endgroup\$C++/CLI
for this, but ended up just usingpinvoke
for its simplicity. I'm not very familiar withC++/CLI
. That being said, at the end of the day, ifC++/CLI
is the better option than I'll write a wrapper around the unmanageddll
. \$\endgroup\$pinvoke
because with it you can useC#
more naturally without the native stuff and you can work with the native stuff without workarounds inside theC++/CLI
wrapper because it can more naturally communicate with native code. \$\endgroup\$Bitmap
in to theMemoryStream
. I was curious if this was necessary, or if I should use theBitmap
'sscan0
property, and locking theBitmap
's pixels and then passing anIntPtr
to the unmanaged API.. \$\endgroup\$