我可以仅使用 Platform SDK 将位图转换为内存中的 PNG(即不写入文件)吗? (即没有 libpng 等)。
我还希望能够为该图像定义透明颜色(不是 Alpha 通道)。
GdiPlus 解决方案似乎仅限于宽度可被 4 整除的图像。在调用 Save() 期间,任何其他操作都会失败。有谁知道这个限制的原因以及我如何/是否可以解决它?
更新
我实现了 GDI+ 解决方案,但正如我所说,它仅限于四边形宽度的图像。我正在寻求在不改变图像尺寸的情况下解决这个宽度问题,或者寻找可行的替代非 GDI+ 解决方案。
我使用 libpng 读取和写入 PNG,它似乎可以处理我扔给它的所有内容(我在单元测试中使用了它,比如 257x255 图像,它们不会造成任何麻烦)。 我相信 API 足够灵活,不会与文件 I/O 绑定(或者至少您可以覆盖其默认行为,例如参见
png_set_write_fn
中的 定制部分)
在实践中,我总是通过更干净的 boost::gil PNG IO 扩展 使用它,但不幸的是,这需要
char*
文件名,如果你深入研究它的实现中的 png_writer
和 file_mgr
类看起来与 FILE*
非常相关(尽管如果你使用的是 Linux,使用 fmemopen 和内存缓冲区的版本可能很容易就可以完成)。
在此站点上,代码显示了如何将位图转换为 PNG 并将其写入文件:http://dotnet-snippets.de/dns/gdi-speichern-eines-png-SID814.aspx。 Bitmap 的
Save
方法还支持写入 IStream
(http://msdn.microsoft.com/en-us/library/ms535406%28VS.85%29.aspx),而不是写入文件。 )。您可以使用 CreateStreamOnHGlobal
API 函数创建由内存备份的 Stream。 (http://msdn.microsoft.com/en-us/library/aa378980%28VS.85%29.aspx)。使用的库 GDI+ 包含在从 WindowsXP 开始的 Windows 中,并且可以在从 Windows98 开始的 Windows 中运行。我从来没有用它做过什么,只是用谷歌搜索了一下。不过,看起来你可以使用它。
CImage类(ATL/MFC)支持保存为PNG格式。与 GDI+ 解决方案一样,它也支持保存到流。这是我用来将其保存到 CByteArray 的一些代码:
CByteArray baPicture;
IStream *pStream = NULL;
if (CreateStreamOnHGlobal(NULL, TRUE, &pStream) == S_OK)
{
if (image.Save(pStream, Gdiplus::ImageFormatPNG) == S_OK)
{
ULARGE_INTEGER ulnSize;
LARGE_INTEGER lnOffset;
lnOffset.QuadPart = 0;
if (pStream->Seek(lnOffset, STREAM_SEEK_END, &ulnSize) == S_OK)
{
if (pStream->Seek(lnOffset, STREAM_SEEK_SET, NULL) == S_OK)
{
baPicture.SetSize(ulnSize.QuadPart);
ULONG ulBytesRead;
pStream->Read(baPicture.GetData(), ulnSize.QuadPart, &ulBytesRead);
}
}
}
}
pStream->Release();
不过我不知道你想使用 ATL 还是 MFC。
我使用 GDI+ 将位图作为 PNG 保存到文件中。 您可能应该查看有关 GDI+ 的 MSDN 信息here,特别是这个函数GdipSaveImageToStream。
本教程这里可能也会提供一些帮助。
GDI(老派,非加)有一个
GetDIBits
方法,可以要求使用 PNG 压缩输出位(BITMAPINFOHEADER::biCompression
== BI_PNG
)。我想知道这是否可以用来创建 PNG 文件?使用 GetDIBits
编写标准位图文件已经足够复杂了 - 所以我怀疑这会更加困难。
如果您只想使用 Windows API,WIC 是实现此目的的方法,它支持位图和 PNG。
使用库可能比自己重新发明轮子更好。