Passing bitmap from C# to C++ via a struct
up vote
4
down vote
favorite
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# c++ image opencv native-code
New contributor
|
show 1 more comment
up vote
4
down vote
favorite
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# c++ image opencv native-code
New contributor
2
You could create ac++/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.
– t3chb0t
2 days ago
@t3chb0t I originally planned on usingC++/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
.
– WBuck
2 days ago
When not using system functions I find such a wrapper easier to use thanpinvoke
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.
– t3chb0t
2 days ago
What do you mean by "Am I copying more than I should?"?
– Henrik Hansen
2 days ago
@HenrikHansen Currently I'm copying the contents of theBitmap
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..
– WBuck
2 days ago
|
show 1 more comment
up vote
4
down vote
favorite
up vote
4
down vote
favorite
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# c++ image opencv native-code
New contributor
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# c++ image opencv native-code
c# c++ image opencv native-code
New contributor
New contributor
edited 2 days ago
200_success
127k15148411
127k15148411
New contributor
asked 2 days ago
WBuck
1233
1233
New contributor
New contributor
2
You could create ac++/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.
– t3chb0t
2 days ago
@t3chb0t I originally planned on usingC++/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
.
– WBuck
2 days ago
When not using system functions I find such a wrapper easier to use thanpinvoke
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.
– t3chb0t
2 days ago
What do you mean by "Am I copying more than I should?"?
– Henrik Hansen
2 days ago
@HenrikHansen Currently I'm copying the contents of theBitmap
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..
– WBuck
2 days ago
|
show 1 more comment
2
You could create ac++/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.
– t3chb0t
2 days ago
@t3chb0t I originally planned on usingC++/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
.
– WBuck
2 days ago
When not using system functions I find such a wrapper easier to use thanpinvoke
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.
– t3chb0t
2 days ago
What do you mean by "Am I copying more than I should?"?
– Henrik Hansen
2 days ago
@HenrikHansen Currently I'm copying the contents of theBitmap
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..
– WBuck
2 days ago
2
2
You could create a
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.– t3chb0t
2 days ago
You could create a
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.– t3chb0t
2 days ago
@t3chb0t I originally planned on using
C++/CLI
for this, but ended up just using pinvoke
for its simplicity. I'm not very familiar with C++/CLI
. That being said, at the end of the day, if C++/CLI
is the better option than I'll write a wrapper around the unmanaged dll
.– WBuck
2 days ago
@t3chb0t I originally planned on using
C++/CLI
for this, but ended up just using pinvoke
for its simplicity. I'm not very familiar with C++/CLI
. That being said, at the end of the day, if C++/CLI
is the better option than I'll write a wrapper around the unmanaged dll
.– WBuck
2 days ago
When not using system functions I find such a wrapper easier to use than
pinvoke
because with it you can use C#
more naturally without the native stuff and you can work with the native stuff without workarounds inside the C++/CLI
wrapper because it can more naturally communicate with native code.– t3chb0t
2 days ago
When not using system functions I find such a wrapper easier to use than
pinvoke
because with it you can use C#
more naturally without the native stuff and you can work with the native stuff without workarounds inside the C++/CLI
wrapper because it can more naturally communicate with native code.– t3chb0t
2 days ago
What do you mean by "Am I copying more than I should?"?
– Henrik Hansen
2 days ago
What do you mean by "Am I copying more than I should?"?
– Henrik Hansen
2 days ago
@HenrikHansen Currently I'm copying the contents of the
Bitmap
in to the MemoryStream
. I was curious if this was necessary, or if I should use the Bitmap
's scan0
property, and locking the Bitmap
's pixels and then passing an IntPtr
to the unmanaged API..– WBuck
2 days ago
@HenrikHansen Currently I'm copying the contents of the
Bitmap
in to the MemoryStream
. I was curious if this was necessary, or if I should use the Bitmap
's scan0
property, and locking the Bitmap
's pixels and then passing an IntPtr
to the unmanaged API..– WBuck
2 days ago
|
show 1 more comment
2 Answers
2
active
oldest
votes
up vote
3
down vote
accepted
There is not much to review. The only thing I can contribute with is that you don't have to run in unsafe
mode:
If you define the data structure as:
[StructLayout(LayoutKind.Sequential)]
internal struct RawImage
{
internal IntPtr ImageData;
internal int Size;
}
Then you can run the .NET side as:
using (var bitmap = new Bitmap(@"fileName.Jpeg"))
using (var stream = new MemoryStream())
{
bitmap.Save(stream, ImageFormat.Jpeg);
var source = stream.ToArray();
IntPtr handle = IntPtr.Zero;
try
{
handle = Marshal.AllocHGlobal(source.Length);
Marshal.Copy(source, 0, handle, source.Length);
var raw = new RawImage
{
ImageData = handle,
Size = source.Length
};
submit(raw);
}
catch (Exception ex)
{
if (handle != IntPtr.Zero)
{
Marshal.FreeHGlobal(handle);
}
}
}
The above works with the same signature for submit(RawImage img)
.
It's a little more code, but you are not limiting the use of your module.
Yeah I prefer this solution, moreC#
friendly.
– WBuck
2 days ago
add a comment |
up vote
3
down vote
Both your and Henrik's approach can be optimized by replacing stream.ToArray()
with stream.GetBuffer()
. This returns the MemoryStream
's internal buffer array instead of making a copy.
You do have to take into account that the buffer can be larger than the actual data, so use the Length
of the stream, not of the buffer. It's also possible that the data doesn't start at index 0, but that's only the case if you used one of the MemoryStream
constructors that accepts an array, index and count. No problem here, but something to keep in mind if you want to generalize this.
add a comment |
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
3
down vote
accepted
There is not much to review. The only thing I can contribute with is that you don't have to run in unsafe
mode:
If you define the data structure as:
[StructLayout(LayoutKind.Sequential)]
internal struct RawImage
{
internal IntPtr ImageData;
internal int Size;
}
Then you can run the .NET side as:
using (var bitmap = new Bitmap(@"fileName.Jpeg"))
using (var stream = new MemoryStream())
{
bitmap.Save(stream, ImageFormat.Jpeg);
var source = stream.ToArray();
IntPtr handle = IntPtr.Zero;
try
{
handle = Marshal.AllocHGlobal(source.Length);
Marshal.Copy(source, 0, handle, source.Length);
var raw = new RawImage
{
ImageData = handle,
Size = source.Length
};
submit(raw);
}
catch (Exception ex)
{
if (handle != IntPtr.Zero)
{
Marshal.FreeHGlobal(handle);
}
}
}
The above works with the same signature for submit(RawImage img)
.
It's a little more code, but you are not limiting the use of your module.
Yeah I prefer this solution, moreC#
friendly.
– WBuck
2 days ago
add a comment |
up vote
3
down vote
accepted
There is not much to review. The only thing I can contribute with is that you don't have to run in unsafe
mode:
If you define the data structure as:
[StructLayout(LayoutKind.Sequential)]
internal struct RawImage
{
internal IntPtr ImageData;
internal int Size;
}
Then you can run the .NET side as:
using (var bitmap = new Bitmap(@"fileName.Jpeg"))
using (var stream = new MemoryStream())
{
bitmap.Save(stream, ImageFormat.Jpeg);
var source = stream.ToArray();
IntPtr handle = IntPtr.Zero;
try
{
handle = Marshal.AllocHGlobal(source.Length);
Marshal.Copy(source, 0, handle, source.Length);
var raw = new RawImage
{
ImageData = handle,
Size = source.Length
};
submit(raw);
}
catch (Exception ex)
{
if (handle != IntPtr.Zero)
{
Marshal.FreeHGlobal(handle);
}
}
}
The above works with the same signature for submit(RawImage img)
.
It's a little more code, but you are not limiting the use of your module.
Yeah I prefer this solution, moreC#
friendly.
– WBuck
2 days ago
add a comment |
up vote
3
down vote
accepted
up vote
3
down vote
accepted
There is not much to review. The only thing I can contribute with is that you don't have to run in unsafe
mode:
If you define the data structure as:
[StructLayout(LayoutKind.Sequential)]
internal struct RawImage
{
internal IntPtr ImageData;
internal int Size;
}
Then you can run the .NET side as:
using (var bitmap = new Bitmap(@"fileName.Jpeg"))
using (var stream = new MemoryStream())
{
bitmap.Save(stream, ImageFormat.Jpeg);
var source = stream.ToArray();
IntPtr handle = IntPtr.Zero;
try
{
handle = Marshal.AllocHGlobal(source.Length);
Marshal.Copy(source, 0, handle, source.Length);
var raw = new RawImage
{
ImageData = handle,
Size = source.Length
};
submit(raw);
}
catch (Exception ex)
{
if (handle != IntPtr.Zero)
{
Marshal.FreeHGlobal(handle);
}
}
}
The above works with the same signature for submit(RawImage img)
.
It's a little more code, but you are not limiting the use of your module.
There is not much to review. The only thing I can contribute with is that you don't have to run in unsafe
mode:
If you define the data structure as:
[StructLayout(LayoutKind.Sequential)]
internal struct RawImage
{
internal IntPtr ImageData;
internal int Size;
}
Then you can run the .NET side as:
using (var bitmap = new Bitmap(@"fileName.Jpeg"))
using (var stream = new MemoryStream())
{
bitmap.Save(stream, ImageFormat.Jpeg);
var source = stream.ToArray();
IntPtr handle = IntPtr.Zero;
try
{
handle = Marshal.AllocHGlobal(source.Length);
Marshal.Copy(source, 0, handle, source.Length);
var raw = new RawImage
{
ImageData = handle,
Size = source.Length
};
submit(raw);
}
catch (Exception ex)
{
if (handle != IntPtr.Zero)
{
Marshal.FreeHGlobal(handle);
}
}
}
The above works with the same signature for submit(RawImage img)
.
It's a little more code, but you are not limiting the use of your module.
edited 2 days ago
answered 2 days ago
Henrik Hansen
6,1731722
6,1731722
Yeah I prefer this solution, moreC#
friendly.
– WBuck
2 days ago
add a comment |
Yeah I prefer this solution, moreC#
friendly.
– WBuck
2 days ago
Yeah I prefer this solution, more
C#
friendly.– WBuck
2 days ago
Yeah I prefer this solution, more
C#
friendly.– WBuck
2 days ago
add a comment |
up vote
3
down vote
Both your and Henrik's approach can be optimized by replacing stream.ToArray()
with stream.GetBuffer()
. This returns the MemoryStream
's internal buffer array instead of making a copy.
You do have to take into account that the buffer can be larger than the actual data, so use the Length
of the stream, not of the buffer. It's also possible that the data doesn't start at index 0, but that's only the case if you used one of the MemoryStream
constructors that accepts an array, index and count. No problem here, but something to keep in mind if you want to generalize this.
add a comment |
up vote
3
down vote
Both your and Henrik's approach can be optimized by replacing stream.ToArray()
with stream.GetBuffer()
. This returns the MemoryStream
's internal buffer array instead of making a copy.
You do have to take into account that the buffer can be larger than the actual data, so use the Length
of the stream, not of the buffer. It's also possible that the data doesn't start at index 0, but that's only the case if you used one of the MemoryStream
constructors that accepts an array, index and count. No problem here, but something to keep in mind if you want to generalize this.
add a comment |
up vote
3
down vote
up vote
3
down vote
Both your and Henrik's approach can be optimized by replacing stream.ToArray()
with stream.GetBuffer()
. This returns the MemoryStream
's internal buffer array instead of making a copy.
You do have to take into account that the buffer can be larger than the actual data, so use the Length
of the stream, not of the buffer. It's also possible that the data doesn't start at index 0, but that's only the case if you used one of the MemoryStream
constructors that accepts an array, index and count. No problem here, but something to keep in mind if you want to generalize this.
Both your and Henrik's approach can be optimized by replacing stream.ToArray()
with stream.GetBuffer()
. This returns the MemoryStream
's internal buffer array instead of making a copy.
You do have to take into account that the buffer can be larger than the actual data, so use the Length
of the stream, not of the buffer. It's also possible that the data doesn't start at index 0, but that's only the case if you used one of the MemoryStream
constructors that accepts an array, index and count. No problem here, but something to keep in mind if you want to generalize this.
answered yesterday
Pieter Witvoet
4,926723
4,926723
add a comment |
add a comment |
WBuck is a new contributor. Be nice, and check out our Code of Conduct.
WBuck is a new contributor. Be nice, and check out our Code of Conduct.
WBuck is a new contributor. Be nice, and check out our Code of Conduct.
WBuck is a new contributor. Be nice, and check out our Code of Conduct.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f208070%2fpassing-bitmap-from-c-to-c-via-a-struct%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
2
You could create a
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.– t3chb0t
2 days ago
@t3chb0t I originally planned on using
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
.– WBuck
2 days ago
When not using system functions I find such a wrapper easier to use than
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.– t3chb0t
2 days ago
What do you mean by "Am I copying more than I should?"?
– Henrik Hansen
2 days ago
@HenrikHansen Currently I'm copying the contents of the
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..– WBuck
2 days ago