问题描述:

项目里一个控件,需要加载本地图片,单张第一次加载的时候可以的,但是重新选择其他图片,会出现图片显示异常的现象。

直接上图,图片部分显示不全了。

问题分析:

一开始怀疑现象是有个图片重复选择后显示是好的,其他某几个图很容易复现,就怀疑是图片问题,查了半天jpg图片完整性,发现图片也没什么区别,后面又查分辨率,在DrawImage()里修改分辨率为偶数了也不行。。。最后只能看代码了,发现是代码里自己清理GLOBAL内存了。其实之前有项目我遇到清理GLOBAL内存导致图片显示不全或者异常的问题。时间太久忘记了。还是记录一下吧。

知识附录:

1, 是Bitmap(RT_BITMAP)类型的图片无法加载, RT_BITMAP是预定义类型, 资源里面没有bmp文件的头, SizeofResource 的返回值要比图片文件少几个字节,因为少了这几个字节, 所以GDI+会返回invalid parameter错误。

2, 从IStream里面创建出来的Image对象会引用到堆里面的GLOBAL内存, 如果GLOBAL内存hBuffer被释放了, 创建的Image的内容就会被破坏,有时只能画出一小部分图片, 有时整个图片有大片的乱码,好像是编码失败的样子, 视当时的内存状况而定。

另外调用Image的Clone也没用,深层次想Clone不是真正的深拷贝,还是依赖那个GLOBAL内存的,如果那个内存被销毁了,Clone的图片也会异常。

只有在销毁或者析构的时候才能清理那个GLOBAL内存,否则会导致显示异常(不是100%出现,而是间歇性出现,但是肯定会出现)。

这是看到的demo,拷贝过来的,可以看看,注意看注释。

​CYourClass::~CYourClass()
{for(IMG_VECTOR::iterator it = m_arImage.begin(); it != m_arImage.end(); it++)delete *it;for(HGLB_VECTOR::iterator it = m_arGlobal.begin(); it != m_arGlobal.end(); it++){::GlobalUnlock(*it);::GlobalFree(*it);}
}void CYourClass::AddImage(HMODULE hInst, UINT nResourceID, LPCTSTR lpType)
{if(lpType == RT_BITMAP){//GDI+ can not load RT_BITMAP resouce, //because they are predefined resource, //they don't contains the image file header.assert(FALSE);return;}HRSRC hResource = ::FindResource(hInst, MAKEINTRESOURCE(nResourceID), lpType);if (!hResource)return;DWORD imageSize = ::SizeofResource(hInst, hResource);if (!imageSize)return;const void* pResourceData = ::LockResource(::LoadResource(hInst, hResource));if (!pResourceData)return;HGLOBAL hBuffer = ::GlobalAlloc(GMEM_FIXED, imageSize);if (NULL == hBuffer)return;void* pBuffer = ::GlobalLock(hBuffer);if (pBuffer){CopyMemory(pBuffer, pResourceData, imageSize);IStream* pStream = NULL;if (::CreateStreamOnHGlobal(hBuffer, FALSE, &pStream) == S_OK){Gdiplus::Image * pImage = Gdiplus::Image::FromStream(pStream);pStream->Release();if (pImage){ if (pImage->GetLastStatus() == Gdiplus::Ok &&pImage->GetWidth() > 0){m_arImage.push_back(pImage);//it seems the image will take usage of the global memory.//so the global memory should be kept until the image destroy.//GDI++此种打开本地文件的方式占用了这片内存,只有在你销毁图片时才能销毁这片    //内存,否则会破坏你的图片,导致显示异常m_arGlobal.push_back(hBuffer);return;}delete pImage;}}::GlobalUnlock(hBuffer);}::GlobalFree(hBuffer);
}​

【windows gdi+】GDI+ Image类加载图片时异常问题处理与分析相关推荐

  1. Windows 2D 绘图 (GDI, GDI+, Direct2D)

    Windows 2D 绘图 GDI GDI 函数 GDI+ GDI 和 GDI+ 的区别 GDI+ 新特性 Direct2D 视觉效果 demo GDI GDI 是 Graphics Device I ...

  2. 使用javax.imageio.ImageIO读取JPEG图片时出现异常java.awt.color.CMMException: General CMM error517

    目录 问题描述 背景 异常 解决 重现 紧急处理 解决方法 第一种:变更JDK版本 第二种:去掉引入的twelvemonkeys图片读取插件 问题描述 背景 由于业务需要,生产环境需要将用户上传的图片 ...

  3. Windows 中GDI、设备描述表和位图

    在Windows中,所有的图形和图像显示操作都是通过GDI(Graphic Device Interface)模块完成,,而GDI的显示都是由设备描述表(Context Device,简称DC)来完成 ...

  4. Win10用Windows照片查看程序打开图片+更改注册表后导致Win10任务栏Adobe PDF阅读器图标显示异常

    Win10用Windows照片查看程序打开图片 解决办法: 参考:https://jingyan.baidu.com/article/455a9950bb20bda166277824.html 上述操 ...

  5. 打开微信另存的 jpg 图片时,提示“Windows 照片查看器无法显示此图片,因为计算机上的可用内存可能不足”

    问题描述: 打开微信另存的 jpg 图片或者通过微信拍照上传的图片时,提示"Windows 照片查看器无法显示此图片,因为计算机上的可用内存可能不足",出现以下信息 解决方案: 目 ...

  6. java生成bmp单色位图,关于GDI+生成单色BMP图片的问题,请高手进!

    用GDI+生成的BMP图片颜色位数一般都是24位,我要怎样生成1位的BMP图片呢? 我在网上找了几种方法,有的方法效果是达到了,但是效率非常低,我是要生成几万张甚至几十万张的,所以要求速度要够快. 不 ...

  7. D2D引擎与GDI\GDI+绘制效果对比

    本例主要是对比D2D和GDI在绘制文字.线条的区别,以及D2D与GDI+在绘制图片时的区别. D2D是基于COM组件开发的,使用前的CoInitialize(NULL)是必须的:另外,GDI+的初始化 ...

  8. GDI/GDI+/D2D/D3D

    原文链接 : 2D Drawing APIs in Windows 在 Windows 7 操作系统中,微软花费了很大的力气构建了一套新的 2D 绘图 API.我们称之为 Direct2D ,隶属于 ...

  9. IntelliJ IDEA 2020.2 发布:支持Java 15、GitHub审查、运行时异常的排查辅助...

    点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 作者 | 局长 来源 | https://www.osc ...

最新文章

  1. Linux 内核同步(二):自旋锁(Spinlock)
  2. Spring Cloud Bus 消息总线介绍
  3. leetcode题目解析(js)--链表
  4. 后端学习 - JavaWeb
  5. 【英语学习】【Level 08】U01 Let's Read L6 Person of the year
  6. 【英语学习】【English L06】U07 Jobs L3 Dr. Allen is a Dentist
  7. 『并发包入坑指北』之向大佬汇报任务
  8. scala数组与java数组对比
  9. iOS 解决导航栏左右 BarButtonItem偏移位置的问题
  10. 敌兵布阵 HDU 1166 线段树
  11. 这40个Python可视化图表案例,强烈建议收藏!
  12. matlab之统计和机器学习工具箱
  13. (2020全新)UGNX二次开发(零基础入门)到提高全套视频教程_NXopen-UG二次开发_新浪博客
  14. linux麒麟镜像,银河麒麟、优麒麟的软件源和镜像站
  15. python冒号_python数组冒号取值操作
  16. PHP实现货币换算的方法
  17. SQL server SSMS图形界面实现(创建表、约束、关系图)
  18. 【RHCE】NFS服务器简介及简单共享目录配置
  19. cmd/bat 批处理文件(干货)
  20. Java中十进制转换为其他进制的方法

热门文章

  1. BNU 34974 MATLAB大法好
  2. hdu 1166 敌兵布阵 树状数组
  3. Golang之channel操作
  4. Window10+Python3.5安装opencv
  5. hiho1249 Xiongnu's Land
  6. 根据先序和中序序列重建二叉树
  7. 感知器python代码
  8. c++学习笔记之静态成员函数
  9. CentOS 6.X 关闭不需要的 TTY 方法
  10. this指针用法详解