用GDI+读入的JPG图如何清除?

kenyou79 2010-11-15 12:14:55
程序功能:对某些参数进行计算,并生成一列JPG图,如1.jpg,2.jpg,3.jpg。然后利用GDI+,将1.jpg读入进来并显示在视图上,点击下一张按钮,依次读入后面的JPG图。
出现的问题:第一次计算时,能够正确生成所要的JPG图,并能将1.jpg读入进来。如果第二次对同样的参数进行计算,理论上程序会生成同样的三张JPG图,并且覆盖原来已有的JPG图。但实际上程序计算完毕,在保存第一张JPG图时出错退出。
问题的原因:因为GDI+读入第一次生成的1.jpg时,该文件被独占,导致第二次保存1.jpg文件时无法替换原有的文件。

现在,我的问题是:如何在每一次计算前,清空视图,也就是取消程序对JPG文件的独占访问?
...全文
284 4 打赏 收藏 转发到动态 举报
写回复
用AI写文章
4 条回复
切换为时间正序
请发表友善的回复…
发表回复
bigowner 2011-04-01
  • 打赏
  • 举报
回复
我也遇到了类似问题 还没解决
kenyou79 2010-11-16
  • 打赏
  • 举报
回复
独占JPG的问题已经解决了,原来加载图片调用的是Image::FromFile,现在改用Image::FromStream,从内存中加载JPG,从而避免了JPG被独占的问题。

但现在有另一个问题:随着JPG图片的不断载入,程序所消耗的内存会逐步递增。

首先描述一下我这个程序的设计思路:这个程序通过计算,首先生成一列JPG图片并保存在某个硬盘路径中,然后程序会读取第一个JPG文件并将它显示在视图里,工具栏有个按钮,点击一下,程序会读取下一个JPG文件,显示在视图中。每次需要显示一个JPG时,会调用名为DrawPicture的函数,这是一个文档类的函数,它通过向视图发送消息,传递JPG图片的路径,并响应视图类的OnUpdate函数,JPG的载入和绘图都是在OnUpdate函数中具体执行的,由于涉及到图片的放大缩小和漫游,因此我用的是双缓冲方法来显示图片。

相关代码如下:

首先在试图的OnInitialUpdate中初始化
void CMy2008BAC35B02View::OnInitialUpdate()
{
// CScrollView::OnInitialUpdate();

// 内存画布的初始化设置
m_memDC.CreateCompatibleDC(NULL); // 准备一个内存DC
CDC * pDC = GetDC();
m_memBitmap.CreateCompatibleBitmap(pDC, 5000, 4000); // 准备一个5000*4000的位图画布
ReleaseDC(pDC);

// 滚动条初始化设置
SetScrollSizes();
}


然后自定义一个消息函数,用来接收菜单传入的图片的地址
// 自定义消息函数,当文档类向本视图发送WM_NOTIFY_DRAW消息时,执行该函数,接收来自对话框的
// 图件完整路径信息,并绘图
LRESULT CMy2008BAC35B02View::OnNotifyDraw(WPARAM wParam, LPARAM lParam)
{
CString *p_strGetPicPathName;
// 将lParam参数转换为指向CString的指针,这个指针指向的CString对象携带了图件完整路径信息
p_strGetPicPathName = (CString*)lParam;
m_strPicPathName = *p_strGetPicPathName; // 完整路径赋值给View的成员变量

CMy2008BAC35B02Doc *pDoc = GetDocument();
pDoc->UpdateAllViews(NULL); // 更新视图,调用视图类的OnUpdate函数
SetScrollSizes(); // 设置滚动条
return 1;
}
其中定义了成员变量
CString p_strGetPicPathName;


然后再定义几个成员变量
Image *image;
IStream *pStream;
HGLOBAL hMem;
并在视图类的构造函数中初始化为NULL。
在OnUpdate中执行具体的绘图
void CMy2008BAC35B02View::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint)
{
CFile file;
if (!file.Open(m_strPicPathName, CFile::modeRead))
{
MessageBox("无法打开结果图件。", "错误", MB_OK|MB_ICONSTOP);
return;
}

DWORD m_nFileLen;
m_nFileLen = file.GetLength();

// 每执行一次OnUpdate,都先清空内存
if (!hMem)
{
::GlobalFree(hMem);
hMem = NULL;
}
// 动态分配内存
// 分配的是固定内存,不是可移动的(GMEM_MOVEABLE),故不必锁定内存
hMem = ::GlobalAlloc(GMEM_FIXED, m_nFileLen);
if (hMem==NULL)
{
MessageBox("内存分配失败。", "错误", MB_OK|MB_ICONSTOP);
return;
}
if (file.Read(hMem, m_nFileLen)!=m_nFileLen)
{
MessageBox("读结果图件失败", "错误", MB_OK|MB_ICONSTOP);
::GlobalFree(hMem);
return;
}
file.Close();
pStream = NULL;
if (CreateStreamOnHGlobal(hMem, FALSE, &pStream)!=S_OK)
{
MessageBox("创建IStream对象失败。", "错误", MB_OK|MB_ICONSTOP);
::GlobalFree(hMem);
return;
}

if (!image)
{
delete image;
image = NULL;
}
image = Image::FromStream(pStream);
pStream->Release();

// 得到图像的宽和高
m_nPicWidth = image->GetWidth();
m_nPicHeight = image->GetHeight();

// 得到当前视图的宽和高
CRect rcClient;
GetClientRect(&rcClient);
m_nClientWidth = rcClient.Width();
m_nClientHeight = rcClient.Height();

// 得到图像缩放后的宽和高
m_nPicZoomedWidth = (int)(m_nPicWidth*m_nScale);
m_nPicZoomedHeight = (int)(m_nPicHeight*m_nScale);

// 求视图中显示图片的原点
m_nClientOriginX = (m_nClientWidth-m_nPicZoomedWidth)/2;
m_nClientOriginY = (m_nClientHeight-m_nPicZoomedHeight)/2;
if (m_nClientOriginX<0)
m_nClientOriginX = 0;
if (m_nClientOriginY<0)
m_nClientOriginY = 0;

// 在内存画布上显示图形
// 将准备的位图画布选入内存DC中成为内存画布
m_pOldBitmap = m_memDC.SelectObject(&m_memBitmap);
m_memDC.FillSolidRect(0, 0, 5000, 4000, RGB(255,255,255)); // 用白色填充整个内存画布
Graphics graphics(m_memDC.GetSafeHdc()); // 内存DC和GDI+的Graphics对象关联
// 设置插值模式改善图像缩放质量
graphics.SetInterpolationMode(InterpolationModeNearestNeighbor);
Rect destinationRc(0, 0, m_nPicZoomedWidth, m_nPicZoomedHeight);
// 在内存画布上显示图像
graphics.DrawImage(image, destinationRc, 0, 0, m_nPicWidth, m_nPicHeight, UnitPixel);
m_memDC.SelectObject(m_pOldBitmap);
Invalidate(); // 提示OnDraw重绘
}

最后在OnDraw中显示图像
void CMy2008BAC35B02View::OnDraw(CDC* pDC)
{
CMy2008BAC35B02Doc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
// 直接绘制内存画布上的位图(双缓冲)
pDC->BitBlt(m_nClientOriginX, m_nClientOriginY, m_nPicZoomedWidth, m_nPicZoomedHeight,
&m_memDC, 0, 0, SRCCOPY);
}


如果按照上面的代码,分配的内存应该都是及时清空了的,因为每一次显示JPG时,都会先清空上一次分配的内存。但实际情况是随着JPG的不断显示,程序耗费的内存越来越多。不过,如果程序最小化了,貌似内存又被瞬间清空了,不知是怎么回事?
hastings 2010-11-15
  • 打赏
  • 举报
回复
delete
xiaohuh421 2010-11-15
  • 打赏
  • 举报
回复
代码?

不知道你用的什么类,你先找下这些类中没有相关功能的函数,或者在析构的时候会自动关闭.

19,468

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 图形处理/算法
社区管理员
  • 图形处理/算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧