我收到了一个用于测试的.dll文件,这个.dll包括了以后将用于处理硬件实时图像的功能。
对于这个简单的.dll文件,我可以打开一张图片(加载到内存中),获取宽度和高度,并获取需要转换成图片的像素。加载、获取宽度和获取高度都没问题,但是获取像素并将其转换为Bitmap或Image是一个问题。
我收到的C++示例源代码:
ApiFunc->OpenImageFile(this->OpenPictureDialog1->FileName.c_str());
ApiFunc->AllocMemory();
w = ApiFunc->GetImageWidth();
h = ApiFunc->GetImageHeight();
Image1->Width = w;
Image1->Height = h;
unsigned char* ptr = ApiFunc->GetImagePixels();
COLORREF pixel;
int r,g,b;
for(int y=0; y<w; y++)
{
for(int x=0; x<h; x++)
{
r = (int)*(ptr+3*x);
g = (int)*(ptr+3*x+1);
b = (int)*(ptr+3*x+2);
Image1->Canvas->Pixels[y][x] = RGB(r,g,b);
}
ptr += 3*h;
}
在ApiFunc中,可以找到这个:
void __fastcall TAPIFunc::LoadDll(HINSTANCE m_hMain)
{
//some others above
GET_IMAGE_PIXELS = (func_GET_IMAGE_PIXELS )GetProcAddress( m_hMain, "GET_IMAGE_PIXELS");
//some others below
}
unsigned char* __fastcall TAPIFunc::GetImagePixels(void)
{
return GET_IMAGE_PIXELS();
}
目前我尝试过的是将byte[]作为返回参数,但这会抛出MarshalDirectiveException异常。
[DllImport("ImageTest.dll")]
public static extern IntPtr GET_IMAGE_PIXELS();
private void OpenImage(string filename)
{
OPEN_IMAGE_FILE(filename);
ALLOC_MEMORY();
int width = GET_IMAGE_WIDTH(); //=800
int height = GET_IMAGE_HEIGHT(); //=600
IntPtr buffer = GET_IMAGE_PIXELS();
int size = width * height * 3;//not sure what the size must be, I think this is one of the issues, just following logic of one answer below.
//but source: https://dev59.com/gmbWa4cB1Zd3GeqPZrd9#16300450
byte[] bitmapImageArray = new byte[size];
Marshal.Copy(buffer, bitmapImageArray, 0, size);
Bitmap bitmap = new Bitmap(width, height, PixelFormat.Format24bppRgb);
BitmapData bmData = bitmap.LockBits(new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, bitmap.PixelFormat);
IntPtr pNative = bmData.Scan0;
Marshal.Copy(imageData, 0, pNative,size);
bitmap.UnlockBits(bmData);
bitmap.Save(Environment.CurrentDirectory + @"\result.bmp");
using (var ms = new MemoryStream(bitmapImageArray))
{
//both throw exception: Parameter is not valid
Bitmap bmp = new Bitmap(ms);
Image bitmapImage = Image.FromStream(ms);
}
}
答案来源:
答案1,使用bitmap.LockBits方法 答案2和3,使用memoryStream
为了确保我有一个有效的图像进行测试,我在Photoshop中保存了一张图片,并选择了该选项:
丑陋的测试图像:
很美吧? :)
还尝试使用for循环,一直运行到崩溃。在另一张图片上运行到count = 1441777,在相同维度的另一张图片上运行到count = 1527793。
int count = 0;
for (int i = 0; i < width * height * 4; i++)
{
count++;
bitmapImageArray[i] = Marshal.ReadByte(buffer, i);
}