1、将存储图片二进制数据Byte数组,转为Image类型
(1)Byte[] 存到 IStream 流中(流类似管道):
IStream* m_pView1 = NULL;
//申请一块全局内存缓冲区
m_hBufView1 = GlobalAlloc(GMEM_MOVEABLE,0);
//将流与内存缓冲区关联
CreateStreamOnHGlobal(m_hBufView1, TRUE, &m_pView1);
//将Byte[]字节数组写入到流,其实存到对应关联的内存
LARGE_INTEGER zero = {0};
ULARGE_INTEGER len = {0};
m_pView1->Seek(zero, STREAM_SEEK_SET, NULL);
m_pView1->Write(字节数组首址,图片数据字节数,NULL);
//获得写入流中数据长度
m_pView1->Seek(zero, STREAM_SEEK_CUR, &len);
DWORD dwlPic1 = len.LowPart;
//重新定位到IStream头
m_pView1->Seek(zero, STREAM_SEEK_SET, NULL);
if(dwlPic1 !=0)
{
//Byte[]转为IStream成功,若Byte[]是new出来的,这时Byte[]所占用内存可以释放
}
(2)将IStream转为Image
Image* imgV1 = Image::FromStream(m_pView1);
/* Image::FromStream(){
new Image(m_pView1,false)
{
//GpImage* nativeImage 为Image成员变量,存储图片数据
//nativeImage进入是野指针,出来时指向存放图片数据的内存
DllExports::GdipLoadImageFromStream(m_pView1,&nativeImage); //将图片保存到Image类中nativeImage变量上
};
} */
//Image::FromStream()静态方法中new了一个Image对象,所以在外部不适用imgV1时,就释放它
(3)释放Image资源
delete imgV1;
/* Image::~Image()
{
DllExports::GdipDisposeImage(nativeImage); //释放nativeImage存储图片数据占用的内存
}*/
(4)IStream不使用,释放内存
if(m_pView1 != NULL)
{
m_pView1->Release();
GlobalFree(m_hBufView1);
m_pView1 = NULL;
}
2、释放Bitmap资源
在GDI+类库中对Bitmap类定义。
Bitmap类继承自Image类,且Bitmap没有定义析构函数,为默认析构函数
(1)创建Bitmap对象
Bitmap bmp(width,height,PixelFormat24bppRGB);
/* 内部 {
GpBitmap *bitmap = NULL; //GpBitmap继承自GpImage,存储图片数据
//创建一块可以存储24位位图格式的内存,取得内存地址bitmap
lastResult = DllExports::GdipCreateBitmapFromScan0(width,
height,
0,
format,
NULL,
&bitmap);
//将存储位图数据的内存地址保存到成员变量 nativeImage 中
SetNativeImage(bitmap); // { this->nativeImage = bitmap }
} */
(2)释放Bitmap对象
这时我们发现对于Image对象,它有析构函数内存释放nativeImage所存储图片的内存,不会造成内存泄露
而Bitmap没有定义析构函数,采用默认析构函数,那Bitmap构造出来的内存无法释放,会造成内存泄露
(当然对于C#、VB对GDI+库有响应的方法释放内存)
这时候我们可以参考父类Image的析构函数显式的释放nativeImage所占用内存空间
DllExports::GdipDisposeImage(nativeImage);
//nativeImage不是public,可以在Image类中定义一个函数GetnativeImage
小结:
由于nativeImage从Image类中继承过来的,在Bitmap构造的时候赋值内存首址
所以析构的时候Bitmap析构没释放,可能会在Image析构中释放,这个也可能不会释放,从而导致使用Bitmap越多,内存占用越大的情况
对于内部申请内存的API或者方法,在外部要记得释放内存