Преобразование растрового изображения в PNG в памяти на С++ (win32)

Можно ли преобразовать растровое изображение в PNG в память (т.е. без записи в файл), используя только Platform SDK? (т.е. нет libpng и т.д.).

Я также хочу иметь возможность определять прозрачный цвет (не альфа-канал) для этого изображения.

Решение GdiPlus, по-видимому, ограничено изображениями, делящимися на 4. Все остальное не работает во время вызова Save(). Кто-нибудь знает причину этого ограничения и как/я могу обойти его?

Обновление: Bounty

Я начинаю щедрость (я действительно хочу, чтобы это сработало). Я реализовал решение GDI +, но, как я уже сказал, он ограничивается изображениями с шириной квадрата. Щедрость будет доступна каждому, кто может решить эту проблему с шириной (без изменения размеров изображения) или может предложить альтернативное не-GDI + решение, которое работает.

Ответы

Ответ 1

Я читаю и пишу PNG с помощью libpng и, похоже, имеет дело со всем, что я бросаю на него (я использовал его в блоке -tests с такими вещами, как 257x255 изображений, и они не вызывают никаких проблем). Я полагаю, что API достаточно гибкий, чтобы не привязываться к файловому вводу/выводу (или, по крайней мере, вы можете переопределить его поведение по умолчанию, например, см. png_set_write_fn в разделе настройка)

На практике я всегда использую его с помощью более чистого boost:: gil Расширение PNG IO, но, к сожалению, он принимает имена файлов char*, и если вы его вставляете в классы png_writer и file_mgr, они, похоже, привязаны к FILE* (хотя, если вы были на Linux версия с использованием fmemopen и буферов в памяти, вероятно, может быть легко подготовлена).

Ответ 2

LodePNG - это кодировщик/декодер PNG без lib.

Ответ 3

На этом сайте код показывает, как преобразовать растровое изображение в PNG, записывая его в файл: http://dotnet-snippets.de/dns/gdi-speichern-eines-png-SID814.aspx. Вместо записи в файл метод Save Bitmap также поддерживает запись в IStream (http://msdn.microsoft.com/en-us/library/ms535406%28VS.85%29.aspx). Вы можете создать поток, поддерживаемый памятью, с помощью функции API CreateStreamOnHGlobal. (http://msdn.microsoft.com/en-us/library/aa378980%28VS.85%29.aspx). Используемая библиотека GDI + включена в Windows от WindowsXP и работает в Windows из Windows98. Я никогда с ним ничего не делал, просто гугл. Похоже, вы можете это использовать.

Ответ 4

Класс 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.

Ответ 5

Я использовал GDI + для сохранения растрового изображения в виде PNG в файл. Вероятно, вы должны проверить информацию MSDN о GDI + здесь и, в частности, эту функцию GdipSaveImageToStream.

Этот учебник здесь, вероятно, также поможет вам.

Ответ 6

GDI (старая школа, не плюс) имеет метод GetDIBits, который может быть запрошен для вывода битов с использованием сжатия PNG (BITMAPINFOHEADER::biCompression == BI_PNG). Интересно, можно ли это использовать для создания PNG файла? Использование GetDIBits для записи стандартных файлов растровых изображений достаточно сложно - поэтому я подозреваю, что это будет еще сложнее.

Ответ 7

Если вы хотите использовать только API Windows, WIC - это способ сделать это, и он поддерживает как растровые изображения, так и PNG.

Ответ 8

Вероятно, лучше было бы использовать библиотеку, а не изобретать колесо самостоятельно.

Посмотрите freeImage