在 C++ (win32) 中将位图转换为内存中的 PNG

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/366768/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 14:59:30  来源:igfitidea点击:

Convert bitmap to PNG in-memory in C++ (win32)

c++winapipng

提问by Assaf Lavie

Can I convert a bitmap to PNG in memory (i.e. without writing to a file) using only the Platform SDK? (i.e. no libpng, etc.).

我可以仅使用 Platform SDK 将位图转换为内存中的 PNG(即不写入文件)吗?(即没有 libpng 等)。

I also want to be able to define a transparent color (not alpha channel) for this image.

我还希望能够为此图像定义透明颜色(不是 alpha 通道)。

The GdiPlus solution seems to be limited to images of width divisible by 4. Anything else fails during the call to Save(). Does anyone know the reason for this limitation and how/whether I can work around it?

GdiPlus 解决方案似乎仅限于宽度可被 4 整除的图像。在调用 Save() 期间,其他任何事情都失败了。有谁知道这个限制的原因以及我如何/是否可以解决它?

Update: Bounty

更新:赏金

I'm starting a bounty (I really want this to work). I implemented the GDI+ solution, but as I said, it's limited to images with quad width. The bounty will go to anyone who can solve this width issue (without changing the image dimensions), or can offer an alternative non-GDI+ solution that works.

我开始赏金(我真的希望它起作用)。我实现了 GDI+ 解决方案,但正如我所说,它仅限于四边形宽度的图像。任何人都可以解决这个宽度问题(不改变图像尺寸),或者可以提供替代的非 GDI+ 解决方案。

采纳答案by timday

I read and write PNGs using libpngand it seems to deal with everthing I throw at it (I've used it in unit-tests with things like 257x255 images and they cause no trouble). I believe the APIis flexible enough to not be tied to file I/O (or at least you can override its default behaviour e.g see png_set_write_fnin section on customization)

我使用libpng读取和写入 PNG ,它似乎可以处理我扔给它的所有内容(我已经在单元测试中使用它来处理 257x255 图像之类的东西,它们不会造成任何问题)。我相信API足够灵活,不会绑定到文件 I/O(或者至少您可以覆盖其默认行为,例如参见自定义png_set_write_fn部分)

In practice I always use it via the much cleaner boost::gilPNG IO extension, but unfortunately that takes char*filenames and if you dig into it the png_writerand file_mgrclasses in its implementation it seem pretty tied to FILE*(although if you were on Linux a version using fmemopen and in-memory buffers could probably be cooked up quite easily).

在实践中,我总是通过更干净的boost::gil PNG IO 扩展来使用它,但不幸的是,它需要char*文件名,如果你深入研究它的实现png_writerfile_mgr类,它似乎与它非常相关FILE*(尽管如果你在 Linux 上使用的版本fmemopen 和内存中的缓冲区可能很容易制作)。

回答by Johan Kotlinski

LodePNG(GitHub) is a lib-less PNG encoder/decoder.

LodePNG( GitHub) 是一个无库的 PNG 编码器/解码器。

回答by Johannes Schaub - litb

On this site the code shows how convert a bitmap to PNG writing it to a file: http://dotnet-snippets.de/dns/gdi-speichern-eines-png-SID814.aspx. Instead of writing to a file, the Savemethod of Bitmap also supports writing to a IStream(http://msdn.microsoft.com/en-us/library/ms535406%28VS.85%29.aspx). You can create a Stream backed up by memory using the CreateStreamOnHGlobalAPI function. (http://msdn.microsoft.com/en-us/library/aa378980%28VS.85%29.aspx). The used library, GDI+, is included in Windows up from WindowsXP, and works in Windows up from Windows98. I've never done something with it, just googled around. Looks like you can use that, though.

在此站点上,代码显示了如何将位图转换为 PNG 并将其写入文件:http: //dotnet-snippets.de/dns/gdi-speichern-eines-png-SID814.aspx。除了写入文件,SaveBitmap的方法还支持写入IStream( http://msdn.microsoft.com/en-us/library/ms535406%28VS.85%29.aspx)。您可以使用CreateStreamOnHGlobalAPI 函数创建由内存备份的 Stream 。( http://msdn.microsoft.com/en-us/library/aa378980%28VS.85%29.aspx)。使用的库 GDI+ 包含在 Windows XP 及以上的 Windows 中,并在 Windows 98 及以上的 Windows 中工作。我从来没有用它做过什么,只是在谷歌上搜索。不过,看起来你可以使用它。

回答by djeidot

The CImage class (ATL/MFC) supports saving into PNG format. Like the GDI+ solution, it also supports saving to a stream. Here's some code I use to save it to a CByteArray:

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();

I don't know if you'd want to use ATL or MFC, though.

不过,我不知道您是否想使用 ATL 或 MFC。

回答by Twotymz

I've used GDI+ for saving a bitmap as a PNG to a file. You should probably check out the MSDN info about GDI+ hereand in particular this function GdipSaveImageToStream.

我使用 GDI+ 将位图作为 PNG 保存到文件中。您可能应该在此处查看有关 GDI+ 的 MSDN 信息,尤其是此函数GdipSaveImageToStream

This tutorial herewill probably provide some help as well.

本教程在这里可能会提供一些帮助为好。

回答by Aardvark

GDI's (old school, non-plus) has a GetDIBitsmethod that can be asked to output bits using PNG compression (BITMAPINFOHEADER::biCompression== BI_PNG). I wonder if this could be used to create a PNG file? Using GetDIBitsto write standard bitmap files is complicated enough - so i suspect this would be even more difficult.

GDI(老派,非加)有一种GetDIBits方法可以要求使用 PNG 压缩(BITMAPINFOHEADER::biCompression== BI_PNG)输出位。我想知道这是否可以用来创建一个 PNG 文件?用GetDIBits写标准位图文件是够复杂的-所以我怀疑这将是更加困难。

回答by Ana Betts

If you want to only use Windows APIs, WICis the way to accomplish this, and it supports both Bitmaps and PNGs.

如果您只想使用 Windows API,WIC是实现此目的的方法,它同时支持位图和 PNG。

回答by DShook

It would probably be better to use a library instead of reinventing the wheel yourself.

使用库而不是自己重新发明轮子可能会更好。

Look into freeImage

查看freeImage