使用GDI +加载JPG和PNG资源的CGdiPlusBitmap类
2017-06-13 19:11
946 查看
翻译来源:https://www.codeproject.com/Articles/3537/Loading-JPG-PNG-resources-using-GDI
作者:Joe Woodbury
GDI +无法加载存储为资源的JPG或PNG图像,使用此类就可以加载资源了。
同样效果的文章:GDI+从资源文件中加载图片
下载demo,S2015打开stdafx.h请加上
一个类,以方便从资源使用GDI +加载JPG和PNG文件
下载演示项目 - 121 Kb
下载源 - 1 Kb
最近我需要显示一些JPG和PNG文件。我有一个旧版的LeadTools和这两种格式的开源库,但希望我的可执行文件尽可能的小。所以我决定给GDI
+一个尝试。我很快发现GDI +设计不好,非常古怪,但它对我的目的很好,直到我发现我的恐惧,GDI +无法加载存储为资源的JPG或PNG图像!
像我相信,其他开发人员面临这个问题,我不相信文档,试图
经过一些测试和几个错误,主要是由于可怕的GDI +文档,我想出了工作代码。休息一晚后,我决定将代码封装在一个简单的类中,以确保内存被释放。其结果是两类:
在讨论代码本身之前,有一个需要解决的GDI +的警告。使用JPG,某些TIFF和其他格式,原始图像信息必须始终可用。换句话说,如果您打开位图
在进行任何GDI +调用之前,需要初始化GDI +。我建议将以下数据成员添加到派生自
在
在
我创建了两个类,基类是非常简单的封装
我不会干扰
+对象,以防开发人员不想声明
本
我发现代码自作聪明,虽然知道返回值的
该演示是具有ANSI和UNICODE构建的Visual Studio .NET 2003项目。它允许您加载重新采样的JPG或PNG资源(好奇的是,我在瓦胡岛,夏威夷拍摄了两张照片,同时拍摄了多媒体产品的内容,一个是莱湾,另一个是从威基基观看的夕阳。
)
我不是一个GDI +专家,也不是一个大粉丝,即使我发现GDI +偶尔非常有用。请不要问我有关的问题。
我被问到为什么我没有使用
2004年4月22日
另外,在修复这个bug的时候,我意识到我没有在失败时清除全局内存。这导致代码正在重新排列。
2004年6月15日
如果
2004年9月3日
添加了一个GDI +初始化部分。
修复了示例应用程序中图像负载故障时的潜在内存泄漏。
作者:Joe Woodbury
GDI +无法加载存储为资源的JPG或PNG图像,使用此类就可以加载资源了。
同样效果的文章:GDI+从资源文件中加载图片
下载demo,S2015打开stdafx.h请加上
#ifndef WINVER // Allow use of features specific to Windows 95 and Windows NT 4 or later. #define WINVER 0x0501 // Change this to the appropriate value to target Windows 98 and Windows 2000 or later. #endif #ifndef _WIN32_WINNT // Allow use of features specific to Windows NT 4 or later. #define _WIN32_WINNT 0x0501 // Change this to the appropriate value to target Windows 98 and Windows 2000 or later. #endif #pragma warning(disable:4996)
一个类,以方便从资源使用GDI +加载JPG和PNG文件
下载演示项目 - 121 Kb
下载源 - 1 Kb
介绍
最近我需要显示一些JPG和PNG文件。我有一个旧版的LeadTools和这两种格式的开源库,但希望我的可执行文件尽可能的小。所以我决定给GDI+一个尝试。我很快发现GDI +设计不好,非常古怪,但它对我的目的很好,直到我发现我的恐惧,GDI +无法加载存储为资源的JPG或PNG图像!
像我相信,其他开发人员面临这个问题,我不相信文档,试图
Bitmap::FromResource无济于事。在浏览可用的Bitmap方法的同时,我碰到过
Bitmap::FromStream。
经过一些测试和几个错误,主要是由于可怕的GDI +文档,我想出了工作代码。休息一晚后,我决定将代码封装在一个简单的类中,以确保内存被释放。其结果是两类:
CGdiPlusBitmap和
CGdiPlusBitmapResource。
Gotcha
在讨论代码本身之前,有一个需要解决的GDI +的警告。使用JPG,某些TIFF和其他格式,原始图像信息必须始终可用。换句话说,如果您打开位图Bitmap::FromFile,则在图像打开时您不能删除或以其他方式更改该文件。同样的限制适用于
CGdiPlusBitmapResource。(我的测试发现,PNG和BMP文件似乎没有遵循这一概括,虽然我不知道这是标准行为还是与我的文件只是一个侥幸。)
GDI +初始化
在进行任何GDI +调用之前,需要初始化GDI +。我建议将以下数据成员添加到派生自CWinApp:
ULONG_PTR m_gdiplusToken;
在
InitInstance(),添加以下调用:
Gdiplus::GdiplusStartupInput gdiplusStartupInput; Gdiplus::GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL);
在
ExitInstance(),添加以下内容:
Gdiplus::GdiplusShutdown(m_gdiplusToken);
类
我创建了两个类,基类是非常简单的封装 Bitmap和封装全局内存的派生类。我想,如果我有耐心和愿望,我可以延长这个类,但我没有必要这样做。(如果你好奇为什么我不是简单地从ATL类派生出来的
CImage,那是因为代码被用在一个没有使用MFC或ATL的程序中,但代码很简单,很容易被修改为使用
CImage作为基类。)
我不会干扰
CGdiPlusBitmap 类,除非说它有一个公共的数据成员
Bitmap* m_pBitmap。(在类中,我使用
Gdiplus命名空间来开发GDI
+对象,以防开发人员不想声明
using namespace Gdiplus;。)
本
CGdiPlusBitmapResource类有几个构造函数和几个重载
Load功能。重载功能简单地允许像我一样的惰性程序员不需要键入
MAKEINTRESOURCE。主
Load函数将资源名称和类型作为字符串,并且是类的关键。本代码全部如下:
inline bool CGdiPlusBitmapResource::Load(LPCTSTR pName, LPCTSTR pType, HMODULE hInst) { Empty(); HRSRC hResource = ::FindResource(hInst, pName, pType); if (!hResource) return false; DWORD imageSize = ::SizeofResource(hInst, hResource); if (!imageSize) return false; const void* pResourceData = ::LockResource(::LoadResource(hInst, hResource)); if (!pResourceData) return false; m_hBuffer = ::GlobalAlloc(GMEM_MOVEABLE, imageSize); if (m_hBuffer) { void* pBuffer = ::GlobalLock(m_hBuffer); if (pBuffer) { CopyMemory(pBuffer, pResourceData, imageSize); IStream* pStream = NULL; if (::CreateStreamOnHGlobal(m_hBuffer, FALSE, &pStream) == S_OK) { m_pBitmap = Gdiplus::Bitmap::FromStream(pStream); pStream->Release(); if (m_pBitmap) { if (m_pBitmap->GetLastStatus() == Gdiplus::Ok) return true; delete m_pBitmap; m_pBitmap = NULL; } } m_pBitmap = NULL; ::GlobalUnlock(m_hBuffer); } ::GlobalFree(m_hBuffer); m_hBuffer = NULL; } return false; }
我发现代码自作聪明,虽然知道返回值的
::LoadResource是一个
HGLOBAL可能会发现明显的双重复制使用
CopyMemory混乱。简而言之,
CreateStreamOnHGlobal需要使用标志
HGLOBAL分配的句柄。通过
GlobalAlloc
使用
GMEM_MOVEABLE
标志
演示
该演示是具有ANSI和UNICODE构建的Visual Studio .NET 2003项目。它允许您加载重新采样的JPG或PNG资源(好奇的是,我在瓦胡岛,夏威夷拍摄了两张照片,同时拍摄了多媒体产品的内容,一个是莱湾,另一个是从威基基观看的夕阳。)
CGdiPlusBitmapResource* pBitmap = new CGdiPlusBitmapResource; if (pBitmap->Load(_T("IDB_BAY"), _T("PNG")))
//如果资源ID没有双引号,直接Load(IDB_BAY,_T("PNG"));这里我找了很久才知道原因在这里 { CClientDC dc(this); Gdiplus::Graphics graphics(dc); graphics.DrawImage(*pBitmap, 0, 0); } else { AfxMessageBox("Failure loading image"); } delete pBitmap;
GDI +免责声明
我不是一个GDI +专家,也不是一个大粉丝,即使我发现GDI +偶尔非常有用。请不要问我有关的问题。
为什么不是图片?
我被问到为什么我没有使用IPicture。答案是三重的 首先,
IPicture不支持PNG图像。其次,
IPicture几乎只是一个图像加载程序,比标准的GDI位图调用功能更多。第三,
IPicture立即对图像数据进行解码。JPG和GIF图像将使用比这个类更多的内存。
更新
2004年4月22日CreateStreamOnHGlobal现在使用
FALSE第二个参数,因为
Bitmap要求保存至少JPG图像的内存,我决定在谨慎的一边。有趣的是,我的测试显示这个标志经常被忽略,但是我收到的报告说,这并不总是这样,在技术上是错误的。
另外,在修复这个bug的时候,我意识到我没有在失败时清除全局内存。这导致代码正在重新排列。
2004年6月15日
如果
Gdiplus::Bitmap::FromStream失败,我补充说,我认为是多余的,但更正确的代码在处理
m_pBitmap。(不幸的是,关于是否在失败时始终返回NULL的情况下,文档中没有提到这个主题。)
2004年9月3日
添加了一个GDI +初始化部分。
修复了示例应用程序中图像负载故障时的潜在内存泄漏。
相关文章推荐
- C#中使用FreeImage库加载Bmp、JPG、PNG、PCX、TGA、PSD等25种格式的图像(源码)。
- 数字图像处理 CImage类的使用与封装(jpg png gif tif bmp等格式图像的加载、数据读写、保存等功能)
- [WM C++]从资源文件中加载显示png/jpg图片
- MFC使用自定义资源加载PNG
- 从资源中加载jpg, png到GDI+ Image
- vc加载PNG以及JPG等图片资源并绘制图片
- C#中使用FreeImage库加载Bmp、JPG、PNG、PCX、TGA、PSD等25种格式的图像(源码)。
- [WM C++]从资源文件中加载显示png/jpg图片
- 从资源中加载jpg, png到GDI+ Image, bmp InvalidParameter问题
- MFC使用自定义资源加载PNG
- MFC使用自定义资源加载PNG
- VC.NET从资源中加载图片(jpg,png)并显示
- 从资源中加载jpg, png到GDI+ Image
- MFC使用自定义资源加载PNG
- MFC使用自定义资源加载PNG
- c++使用std_image.c来加载jpg,png,gif等格式图片
- 使用系统imgdecmp库解码JPG,GIF,PNG,BMP图片
- 在Wince 中使用IXRResourceDictionary加载全局资源App.xaml
- 使用ClassLoader加载包内的资源
- 使用CxImage进行图形和格式转换(CBitmap to jpg or png or gif or bmp)