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

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

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

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

Обновление: награда

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


person Community    schedule 14.12.2008    source источник
comment
для начала я нашел пример сохранения растрового изображения как png с помощью gdi +: dotnet-snippets.de/dns/gdi-speichern-eines-png-SID814.aspx может быть полезно   -  person Johannes Schaub - litb    schedule 14.12.2008
comment
Это решение работает у меня даже с изображениями, ширина которых не делится на 4. Я использую Windows Vista и использую Visual C ++ 2008.   -  person Gabriele D'Antona    schedule 11.02.2009
comment
Почему вы не хотите использовать libpng? У него очень разрешительная лицензия.   -  person Adam Rosenfield    schedule 11.02.2009
comment
Делает ли libpng кодирование в памяти? (или просто в файлы?)   -  person Assaf Lavie    schedule 12.02.2009
comment
Вы можете перехватить вывод libpng с помощью png_set_write_fn и делать с ним все, что захотите.   -  person timday    schedule 12.02.2009
comment
Я использовал libpng для кодирования в памяти   -  person Adam Tegen    schedule 13.02.2009
comment
Проблема с четырехкратной шириной, по-видимому, ограничивается более старыми кодеками, которые поставлялись со старыми версиями Windows. Я столкнулся с аналогичными проблемами при использовании XP, но они (в основном) исчезли, когда я обновился до Vista, а затем до Windows 7.   -  person Adrian McCarthy    schedule 01.11.2011


Ответы (8)


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

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

person Community    schedule 11.02.2009
comment
+1 спасибо. Могу я узнать, как использовать Boost :: GIL с PNG IO? Я понятия не имею об интеграции и использовании этого. - person Viet; 26.02.2010
comment
Boost GIL включает расширение ввода-вывода, которое в настоящее время включает поддержку базового чтения и записи в файлы PNG, но не обеспечивает достаточного количества хуков для чтения / записи потоков в памяти, о чем спрашивал исходный плакат. Похоже, что в разработке находится новое расширение ввода-вывода (Google что-то вроде boost GIL new IO extension для поиска различных публикаций), которое, похоже, даст гораздо больше гибкости в этой области. - person timday; 02.03.2010
comment
libpng, хотя и является хорошим решением, похоже, нарушает ограничение вопроса на использование только Platform SDK. - person Adrian McCarthy; 01.11.2011
comment
как мне установить эту библиотеку, пожалуйста? Или мне нужно просто получить исходный код? - person Lucie kulza; 28.03.2014
comment
@Lucie: Я тоже не мог найти версию для Windows; см. мой другой вопрос stackoverflow.com/questions/8669163/. Разработка под Windows сводит меня с ума от подобных вещей, по сравнению с Linux, где вы можете просто apt-get install libpng-dev и приступить к работе в считанные секунды. - person timday; 28.03.2014

LodePNG (GitHub) - это кодировщик / декодер PNG без библиотеки.

person Community    schedule 14.02.2009

На этом сайте код показывает, как преобразовать растровое изображение в 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). Вы можете создать поток с резервной копией в памяти с помощью функции CreateStreamOnHGlobal API. (http://msdn.microsoft.com/en-us/library/aa378980%28VS.85%29.aspx). Используемая библиотека GDI + входит в состав Windows, начиная с WindowsXP, и работает в Windows, начиная с Windows98. Я никогда ничего с этим не делал, просто гуглил. Хотя, похоже, ты можешь это использовать.

person Johannes Schaub - litb    schedule 14.12.2008
comment
Как насчет проблемы GDI +, о которой я упоминал в исходном вопросе? - person Assaf Lavie; 01.11.2011

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

person Community    schedule 12.02.2009
comment
Увы, в моем проекте нет ATL / MFC. - person Assaf Lavie; 12.02.2009
comment
хорошо ... может быть, часть сохранения потока может быть полезна, она должна быть похожа на ту, которая использует GDI + - person djeidot; 12.02.2009
comment
Это помогло мне в том, над чем я работал, по крайней мере +1. - person Aardvark; 12.02.2009
comment
Я почти уверен, что здесь используется libpng - person Adam Tegen; 13.02.2009

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

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

person Twotymz    schedule 14.12.2008

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

person Community    schedule 11.02.2009
comment
Для тех, кто, возможно, думает пойти по этому пути, см. ответ на GetDIBits () с ошибкой сжатия PNG или Расширения JPEG и PNG для определенных функций и структур растровых изображений в MSDN, на который он ссылается. - person Tamir Evan; 11.09.2017

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

person Community    schedule 12.02.2009
comment
Вы уверены, что он не страдает от того же странного ограничения ширины, что и GDI +? - person Assaf Lavie; 12.02.2009
comment
Нет, не уверен, но WIC определенно более современный и актуальный, чем GDI +. - person Ana Betts; 12.02.2009

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

Загляните в freeImage

person DShook    schedule 14.12.2008