项目中有个场景,vb.net需要调用C++处理后的图片。
原来的处理方案是,C++处理图片后,保存图片到磁盘上,VB.NET再从磁盘上进行读取。
现在想对这个方案进行优化。vb端先新建内存映射文件,再调用C++对图片进行处理,处理后的结果写入vb建好的内存映射文件,然后vb端再读取内存映射文件。这样处理就可以不用在磁盘上进行读写操作了,节约了IO资源。
内存映射文件包含虚拟内存中文件的内容。利用文件与内存之间的映射,应用程序(包括多个进程)可以通过直接在内存中进行读写来修改文件。
内存映射文件可以分为两种类型:
①持久内存映射文件:
持久文件是与磁盘上的源文件关联的内存映射文件。在最后一个进程使用完此文件后,数据将保存到磁盘上的源文件中。这些内存映射文件适合用来处理非常大的源文件。
②非持久内存映射文件:
非持久文件是未与磁盘上的源文件关联的内存映射文件。当最后一个进程使用完此文件后,数据将丢失,并且垃圾回收功能将回收此文件。这些文件适用于为进程间通信(IPC)创建共享内存。
我仅仅是想进行进程之间的通信,所以选用了第二种,非持久化内存映射文件。
首先vb端先分配内存空间
Imports System.IO Imports System.IO.Compression Imports System.IO.MemoryMappedFiles Imports System.Threading
Dim mmf As MemoryMappedFile = MemoryMappedFile.CreateNew("img_1", 1024 * 1024)
然后调用c++编译好的命令行可执行文件
Dim p As New System.Diagnostics.Process p.StartInfo.FileName = "D:\dev\workspaces\outputForMMF\answerSheet.exe" p.StartInfo.Arguments = imgName & " " & xmlName p.StartInfo.UseShellExecute = False p.StartInfo.CreateNoWindow = True p.Start() p.WaitForExit()
char *mmfName = "img_1"; //需要将char转为LPCWSTR WCHAR wszClassName[20] = {0}; memset(wszClassName,0,sizeof(wszClassName)); MultiByteToWideChar(CP_ACP,0,mmfName,strlen(mmfName)+1,wszClassName,sizeof(wszClassName)/sizeof(wszClassName[0])); //打开共享的文件对象。 HANDLE m_hMapFile = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, wszClassName); //获得映射视图 char* mmfm_base_address = (char*)MapViewOfFile(m_hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, mmfSize); DWORD error_code; if(mmfm_base_address == NULL){ error_code = GetLastError(); if(error_code != SUCCESS){ cout<<"error code "<<error_code<<endl; } }else{ //由于C++中对图片的处理使用的是openCV,图片的格式是iplImage。需要将iplImage转为bmp,再存入内存映射文件,这样vb端才能解析出来。 //Iplimage *temp;存放的是处理好的图片结果,是全局变量 //以下的部分,是把iplimage转为bmp //FILE *fpw; //变量定义 BITMAPFILEHEADER strHead; BITMAPINFOHEADER strInfo; //初始化头文件。用0来填充内存区域 SecureZeroMemory(&strHead, sizeof(strHead)); SecureZeroMemory(&strInfo, sizeof(strInfo)); //初始化灰度图调色板 RGBQUAD *strPla = (RGBQUAD *)malloc(256*sizeof(RGBQUAD));//调色板的大小为1024字节 for (int i1 = 0; i1 < 256; i1++ ){ strPla[i1].rgbRed = strPla[i1].rgbGreen = strPla[i1].rgbBlue = i1; strPla[i1].rgbReserved = 0; } //写bitmapFileHeader strHead.bfType = 0x4d42;//写入字符"BM" strHead.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 1024 + (temp->width + 3)/4*4 * temp->height; strHead.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 1024; //写bitmapInfoHeader strInfo.biSize = sizeof(strInfo); strInfo.biHeight = temp->height; strInfo.biWidth = temp->width; strInfo.biPlanes = 1; strInfo.biBitCount = 8; strInfo.biCompression = BI_RGB; /*//保存bmp图片 if((fpw=fopen("M://abc.bmp","wb"))==NULL){ cout<<"create the bmp file error!"<<endl; return NULL; } fwrite(&strHead,1,sizeof(strHead),fpw); fwrite(&strInfo,1,sizeof(strInfo),fpw); fwrite(strPla,1,1024,fpw); BYTE *imagedata = NULL; imagedata = (BYTE*)malloc((testBitmap->width + 3)/4*4 * testBitmap->height); for (int k1 = 0; k1 < testBitmap->height; ++k1){ for (int k2 = 0; k2 < testBitmap->width; ++k2){ if (getPixelByTemp(testBitmap, k2 , k1)){ //黑 (*(imagedata + (testBitmap->height - k1 - 1) * ((testBitmap->width + 3)/4*4) + k2)) = 0; }else{ //白 (*(imagedata + (testBitmap->height - k1 - 1) * ((testBitmap->width + 3)/4*4) + k2)) = 255; } } } fwrite(imagedata,1,(testBitmap->width + 3)/4*4 * testBitmap->height,fpw); fclose(fpw); */ CopyMemory(mmfm_base_address, &strHead,sizeof(strHead)); char *imgData = temp->imageData; char *data = NULL; if (temp->nChannels == 3){ data = (char*)malloc((temp->width + 3)/4*4 * temp->height); for(int i=0;i<temp->height;i++) for(int j=0;j<(temp->width + 3)/4*4;j++) data[i * ((temp->width + 3)/4*4) + j] = temp->imageData[3*((temp->height - i - 1) * ((temp->width + 3)/4*4) + j)]; CopyMemory(mmfm_base_address + sizeof(strHead), &strInfo,sizeof(strInfo)); CopyMemory(mmfm_base_address + sizeof(strHead) + sizeof(strInfo), strPla, 1024); CopyMemory(mmfm_base_address + sizeof(strHead) + sizeof(strInfo) + 1024, data, (temp->width + 3)/4*4 * temp->height); }else if (temp->nChannels == 1){ strInfo.biHeight = -strInfo.biHeight; CopyMemory(mmfm_base_address + sizeof(strHead), &strInfo,sizeof(strInfo)); CopyMemory(mmfm_base_address + sizeof(strHead) + sizeof(strInfo), strPla, 1024); CopyMemory(mmfm_base_address + sizeof(strHead) + sizeof(strInfo) + 1024, imgData, (temp->width + 3)/4*4 * temp->height); //for(int i=0;i<temp->height;i++) for(int j=0;j<(temp->width + 3)/4*4;j++) //data[i * ((temp->width + 3)/4*4) + j] = temp->imageData[((temp->height - i - 1) * ((temp->width + 3)/4*4) + j)]; }else{ return false; } /*fwrite(data,1,(testBitmap->width + 3)/4*4 * testBitmap->height,fpw); fclose(fpw);*/ /*FILE *fpw2; if((fpw2=fopen("M://abc2.bmp","wb"))==NULL){ cout<<"create the bmp2 file error!"<<endl; return NULL; } fwrite(mmfm_base_address,1,((testBitmap->width + 3)/4*4 * testBitmap->height + + sizeof(strHead) + sizeof(strInfo) + 1024),fpw2); fclose(fpw2);*/ //卸载映射 UnmapViewOfFile(mmfm_base_address); //关闭内存映射文件 CloseHandle(m_hMapFile); }
Using mmf As MemoryMappedFile = MemoryMappedFile.OpenExisting("img_1") Using Stream As MemoryMappedViewStream = mmf.CreateViewStream() Dim reader As BinaryReader = New BinaryReader(Stream) Dim bytes As Byte() = reader.ReadBytes(1024 * 1024) 'byte()转为bitmap Dim newBitmap As Bitmap = Bitmap.FromStream(New MemoryStream(bytes)) newBitmap.Save("M:\" & mappingName & ".bmp") End Using End Using mmf.Dispose()