2008-12-14 14 views
15

Czy mogę przekonwertować bitmapę na PNG w pamięci (tzn. Bez zapisywania do pliku) za pomocą tylko zestawu SDK platformy? (tzn. brak libpng itp.).Konwertuj mapę bitową na PNG w pamięci w C++ (win32)

Chcę również móc zdefiniować przezroczysty kolor (nie kanał alfa) dla tego obrazu.

Rozwiązanie GdiPlus wydaje się być ograniczone do obrazów o szerokości podzielnej przez 4. Wszystko inne zawiedzie podczas wywołania Save(). Czy ktokolwiek zna przyczynę tego ograniczenia i jak/mogę go obejść?

Aktualizacja: Bounty

Zaczynam bounty (naprawdę chcę to do pracy). Zaimplementowałem rozwiązanie GDI +, ale, jak powiedziałem, jest ono ograniczone do obrazów o szerokości czterech kwadratów. Nagroda trafi do każdego, kto rozwiąże problem z tą szerokością (bez zmiany wymiarów obrazu) lub zaoferuje alternatywne rozwiązanie inne niż GDI +, które działa.

+0

na dobry początek, znalazłem przykład, aby zapisać bitmapę jako png z gdi +: http://dotnet-snippets.de/dns/gdi-speichern-eines-png-SID814.aspx może to przydatne –

+0

To rozwiązanie działa dla mnie, nawet przy obrazach, których szerokość nie jest podzielna przez 4. Jestem w systemie Windows Vista i korzystam z Visual C++ 2008. –

+0

Dlaczego nie chcesz używać biblioteki libpng? Ma bardzo permisywną licencję. –

Odpowiedz

14

Czytam i piszę PNG używając libpng i wydaje się, że mam do czynienia z czymkolwiek, co do nich rzucam (użyłem go w testach jednostkowych z takimi obrazami jak 257x255 i nie sprawiają kłopotów). Wierzę, że API jest na tyle elastyczny, aby nie być związany złożyć/O (lub przynajmniej można przesłonić jego domyślne zachowanie patrz np png_set_write_fn w rozdziale customization)

W praktyce zawsze używać go za pośrednictwem znacznie czystsze boost::gilPNG IO extension , ale niestety to zajmuje char* nazw plików i jeśli zagłębisz się w te klasy png_writer i file_mgr w swojej implementacji, wydaje się być całkiem związane z FILE* (chociaż jeśli byłeś w Linuksie, wersja z użyciem fmemopen i buforów w pamięci mogła być dość łatwo ugotowana).

+0

+1 dzięki. Czy mogę wiedzieć, jak używać Boost :: GIL z PNG IO? Nie mam pojęcia o integracji i korzystaniu z tego. – Viet

+1

Funkcja Boost GIL zawiera rozszerzenie "IO", które obecnie obsługuje podstawowe operacje odczytu i zapisu do plików PNG, ale nie zapewnia wystarczającej liczby haczyków do odczytu/zapisu w strumieniach pamięci, o co pytał oryginalny plakat. Wydaje się, że istnieje nowe rozszerzenie IO (coś w rodzaju google "boost GIL new IO extension", aby znaleźć różne wpisy) w fazie rozwoju, które wygląda na to, że zapewni większą elastyczność w tej dziedzinie. – timday

+1

libpng, podczas gdy dobre rozwiązanie, wydaje się naruszać ograniczenie pytania dotyczące "używania tylko zestawu SDK platformy". –

2

Prawdopodobnie lepiej byłoby użyć biblioteki zamiast samodzielnie wymyślać koło.

Spójrz na freeImage

11

Na tej stronie kod pokazuje, w jaki sposób przekonwertować bitmapę do PNG pisanie do pliku: http://dotnet-snippets.de/dns/gdi-speichern-eines-png-SID814.aspx. Zamiast zapisywać do pliku, metoda Bitmap Save obsługuje również zapisywanie do IStream (http://msdn.microsoft.com/en-us/library/ms535406%28VS.85%29.aspx). Możesz utworzyć Strumień zarchiwizowany w pamięci przy użyciu funkcji API CreateStreamOnHGlobal. (http://msdn.microsoft.com/en-us/library/aa378980%28VS.85%29.aspx). Używana biblioteka GDI + jest zawarta w systemie Windows od wersji Windows XP i działa w systemie Windows od Windows98. Nigdy z nim nie robiłem, tylko goograłem. Wygląda na to, że możesz tego użyć.

+1

Co z problemem GDI +, o którym wspomniałem w pierwotnym pytaniu? –

5

Użyłem GDI + do zapisania bitmapy jako pliku PNG do pliku. Powinieneś prawdopodobnie sprawdzić informacje MSDN o GDI + here, aw szczególności tej funkcji GdipSaveImageToStream.

Ten samouczek: here prawdopodobnie zapewni również pomoc.

3

GDI's (old school, non-plus) ma metodę GetDIBits, którą można poprosić o wydrukowanie bitów za pomocą kompresji PNG (BITMAPINFOHEADER::biCompression == BI_PNG). Zastanawiam się, czy można to wykorzystać do utworzenia pliku PNG? Używanie do zapisywania standardowych plików bitmapowych jest dość skomplikowane - więc podejrzewam, że byłoby to jeszcze trudniejsze.

+0

Dla każdego, kto może pomyśleć o zrobieniu tej trasy, zobacz [odpowiedź na "GetDIBits() nie działa z kompresją PNG"] (https://stackoverflow.com/a/3101090/2910230) lub "[JPEG i PNG Rozszerzenia dla konkretnych funkcji i struktur bitmapowych (https://msdn.microsoft.com/en-us/library/dd145023 (VS.85) .aspx) "w witrynie MSDN, do której prowadzi łącze. –

3

Jeśli chcesz korzystać tylko z interfejsów API systemu Windows, to jest to możliwe za pomocą WIC i obsługuje zarówno mapy bitowe, jak i PNG.

+0

Czy jesteś pewien, że nie ma takiego samego dziwnego ograniczenia szerokości jak GDI +? –

+0

Nie, nie jestem pewien - ale WIC jest zdecydowanie bardziej nowoczesny i aktualizowany niż GDI + –

6

Klasy CImage (ATL/MFC) obsługuje zapisywanie do formatu PNG. Podobnie jak rozwiązanie GDI +, obsługuje także zapisywanie do strumienia. Oto niektóre kodu używam go zapisać do 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(); 

nie wiem, gdyby chcesz użyć ATL lub MFC, choć.

+1

Niestety, w moim projekcie nie ma ATL/MFC. –

+0

ok ... może część do zapisywania strumieniowego może być przydatna, powinna być podobna do tej używającej GDI + – djeidot

+0

Pomogło mi to w pracy nad którą pracowałem, +1 przynajmniej za to. – Aardvark

Powiązane problemy