2008-12-14 35 views
15

¿Puedo convertir un mapa de bits a PNG en la memoria (es decir, sin escribir en un archivo) utilizando solo Platform SDK? (es decir, no libpng, etc.).Convertir bitmap a PNG en la memoria en C++ (win32)

También quiero ser capaz de definir un color transparente (no un canal alfa) para esta imagen.

La solución GdiPlus parece estar limitada a imágenes de ancho divisible por 4. Cualquier otra cosa falla durante la llamada a Save(). ¿Alguien sabe el motivo de esta limitación y cómo y si puedo evitarlo?

Actualización: Bounty

estoy empezando una recompensa (que realmente quiero que esto funcione). Implementé la solución GDI +, pero como dije, está limitada a imágenes con ancho cuádruple. La recompensa irá a cualquiera que pueda resolver este problema de ancho (sin cambiar las dimensiones de la imagen), o puede ofrecer una solución alternativa que no sea GDI + que funcione.

+0

para empezar, encontré un ejemplo para guardar un mapa de bits como png con gdi +: http://dotnet-snippets.de/dns/gdi-speichern-eines-png-SID814.aspx quizás sea útil –

+0

Esta solución funciona para mí, incluso con imágenes donde el ancho no es divisible por 4. Estoy en Windows Vista y uso de Visual C++ 2008. –

+0

¿Por qué no quieres usar libpng? Tiene una licencia muy permisiva. –

Respuesta

14

Leo y escribo PNG usando libpng y parece tratar con todo lo que le tiro (lo he usado en pruebas unitarias con cosas como 257x255 imágenes y no causan problemas). Creo que el API es lo suficientemente flexible como para no estar atado a presentar de E/S (o al menos se puede anular su comportamiento predeterminado por ejemplo, ver png_set_write_fn en la sección de customization)

En la práctica siempre lo uso a través de la mucho más limpio boost::gilPNG IO extension , pero desafortunadamente toma los nombres de archivo char* y si profundiza en las clases png_writer y file_mgr en su implementación, parece bastante relacionado con FILE* (aunque si estuviera en Linux, una versión que utiliza búferes fmemopen y in-memory probablemente podría prepararse con bastante facilidad))

+0

+1 gracias. ¿Puedo saber cómo usar Boost :: GIL con PNG IO? No tengo ni idea sobre la integración y el uso de eso. – Viet

+1

Boost GIL incluye una "extensión IO" que actualmente incluye soporte para lectura básica y escritura en archivos PNG, pero no proporciona suficientes ganchos para leer/escribir secuencias en memoria como preguntaba el póster original. Parece que hay una nueva extensión de IO (google algo así como "impulsar GIL nueva extensión de IO" para encontrar varias publicaciones) en desarrollo, que parece que le dará mucha más flexibilidad en esta área. – timday

+1

libpng, si bien es una buena solución, parece violar la restricción de la pregunta de "usar solo Platform SDK". –

2

Probablemente sería mejor utilizar una biblioteca en lugar de reinventar la rueda usted mismo.

Mira en freeImage

11

En este sitio el código muestra cómo convertir un mapa de bits a PNG escribirlo en un archivo: http://dotnet-snippets.de/dns/gdi-speichern-eines-png-SID814.aspx. En lugar de escribir en un archivo, el método Save de Bitmap también admite escribir en IStream (http://msdn.microsoft.com/en-us/library/ms535406%28VS.85%29.aspx). Puede crear un flujo respaldado por memoria usando la función de API CreateStreamOnHGlobal. (http://msdn.microsoft.com/en-us/library/aa378980%28VS.85%29.aspx). La biblioteca utilizada, GDI +, está incluida en Windows desde Windows XP, y funciona en Windows desde Windows98. Nunca he hecho algo con eso, solo busqué en Google. Parece que puedes usar eso, sin embargo.

+1

¿Qué pasa con el problema GDI + que mencioné en la pregunta original? –

5

He usado GDI + para guardar un mapa de bits como PNG en un archivo. Probablemente debería consultar la información de MSDN sobre GDI + here y, en particular, esta función GdipSaveImageToStream.

Este tutorial here probablemente también proporcione algo de ayuda.

3

GDI (old school, non-plus) tiene un método GetDIBits que se puede pedir a los bits de salida mediante compresión PNG (BITMAPINFOHEADER::biCompression == BI_PNG). Me pregunto si esto podría usarse para crear un archivo PNG. Usar GetDIBits para escribir archivos de mapa de bits estándar es lo suficientemente complicado, así que sospecho que esto sería aún más difícil.

+0

Para cualquiera que esté pensando en realizar esta ruta, consulte la [respuesta a "GetDIBits() está fallando con la compresión PNG"] (https://stackoverflow.com/a/3101090/2910230) o "[JPEG y PNG Extensiones para funciones y estructuras de mapa de bits específicas] (https://msdn.microsoft.com/en-us/library/dd145023 (VS.85) .aspx) "en MSDN, con el que se vincula. –

3

Si solo desea utilizar las API de Windows, WIC es la manera de lograr esto, y es compatible tanto con mapas de bits como con archivos PNG.

+0

¿Estás seguro de que no sufre la misma limitación de ancho extraño que GDI +? –

+0

No, no estoy seguro, pero WIC es definitivamente más moderno y está actualizado que GDI + –

6

La clase CImage (ATL/MFC) admite el guardado en formato PNG. Al igual que la solución GDI +, también admite guardar en una transmisión. Aquí hay un código que utilizo para guardarlo en un 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(); 

No sé si lo desea utilizar ATL o MFC, sin embargo.

+1

Por desgracia, no hay ATL/MFC en mi proyecto. –

+0

ok ... tal vez la parte de guardar en secuencia podría ser útil, debería ser similar a la que usa GDI + – djeidot

+0

Esto me ayudó para algo en lo que estaba trabajando, +1 al menos. – Aardvark

16

LodePNG es un codificador/decodificador PNG libre de lib.