2008-12-14 17 views
15

Tôi có thể chuyển đổi một bitmap để PNG trong bộ nhớ (nghĩa là không phải bằng văn bản cho một tập tin) chỉ sử dụng nền tảng SDK? (ví dụ: không có libpng, v.v.).Chuyển đổi bitmap để PNG trong bộ nhớ trong C++ (win32)

Tôi cũng muốn để có thể xác định một màu trong suốt (không phải alpha kênh) cho hình ảnh này.

Giải pháp GdiPlus dường như bị giới hạn ở hình ảnh có chiều rộng chia hết cho 4. Bất cứ điều gì khác không thành công trong suốt cuộc gọi đến Save(). Có ai biết lý do cho hạn chế này và làm thế nào/cho dù tôi có thể làm việc xung quanh nó?

Cập nhật: Bounty

tôi bắt đầu một bounty (Tôi thực sự muốn điều này để làm việc). Tôi đã triển khai giải pháp GDI +, nhưng như tôi đã nói, nó chỉ giới hạn ở hình ảnh có chiều rộng quad. Tiền thưởng sẽ chuyển đến bất kỳ ai có thể giải quyết vấn đề chiều rộng này (không thay đổi kích thước hình ảnh) hoặc có thể cung cấp giải pháp thay thế không phải GDI + hoạt động.

+0

để giúp bạn bắt đầu, tôi đã tìm thấy ví dụ để lưu bitmap như png với gdi +: http://dotnet-snippets.de/dns/gdi-speichern-eines-png-SID814.aspx có thể hữu ích –

+0

Giải pháp này làm việc cho tôi, ngay cả với hình ảnh mà chiều rộng không chia hết cho 4. Tôi đang sử dụng Windows Vista và sử dụng Visual C++ 2008. –

+0

Tại sao bạn không muốn sử dụng libpng? Nó có một giấy phép rất dễ dãi. –

Trả lời

14

Tôi đọc và ghi PNG sử dụng libpng và dường như đối phó với mọi thứ tôi ném vào nó (tôi đã sử dụng nó trong các bài kiểm tra đơn vị với những thứ như hình ảnh 257x255 và chúng không gây rắc rối). Tôi tin rằng API là đủ linh hoạt để không bị ràng buộc vào tập tin I/O (hoặc ít nhất là bạn có thể thay đổi hành vi mặc định của nó ví dụ như thấy png_set_write_fn trong phần trên customization)

Trong thực tế tôi luôn luôn sử dụng nó thông qua các bụi nhiều boost::gilPNG IO extension , nhưng không may là phải có char* tên tệp và nếu bạn đào sâu vào các lớp png_writerfile_mgr trong việc triển khai, nó có vẻ khá gắn với FILE* (mặc dù nếu bạn sử dụng Linux, phiên bản sử dụng bộ đệm fmemopen và bộ nhớ trong có thể được nấu chín khá dễ dàng).

+0

+1 cảm ơn. Tôi có thể biết cách sử dụng Boost :: GIL với PNG IO không? Tôi không có đầu mối về việc tích hợp và tận dụng điều đó. – Viet

+1

Boost GIL bao gồm "phần mở rộng IO", bao gồm hỗ trợ đọc và ghi cơ bản cho tệp PNG nhưng không cung cấp đủ móc để đọc/ghi luồng trong bộ nhớ khi áp phích ban đầu được hỏi. Có vẻ là một phần mở rộng IO mới (google một cái gì đó như "tăng GIL mới IO mở rộng" để tìm các bài đăng khác nhau) theo phát triển mà hình như nó sẽ cung cấp cho rất nhiều tính linh hoạt hơn trong lĩnh vực này. – timday

+1

libpng, trong khi một giải pháp tốt, dường như vi phạm ràng buộc của câu hỏi "chỉ sử dụng SDK nền tảng". –

2

Nó có lẽ sẽ là tốt hơn để sử dụng một thư viện thay vì reinventing the wheel mình.

Nhìn vào freeImage

11

Trên trang web này mã cho thấy cách chuyển đổi một bitmap để PNG viết nó vào một tập tin: http://dotnet-snippets.de/dns/gdi-speichern-eines-png-SID814.aspx. Thay vì viết vào một tập tin, phương pháp Save của Bitmap cũng hỗ trợ bằng văn bản cho một IStream (http://msdn.microsoft.com/en-us/library/ms535406%28VS.85%29.aspx). Bạn có thể tạo Luồng được sao lưu theo bộ nhớ bằng chức năng API CreateStreamOnHGlobal. (http://msdn.microsoft.com/en-us/library/aa378980%28VS.85%29.aspx). Thư viện được sử dụng, GDI +, được bao gồm trong Windows từ WindowsXP và hoạt động trong Windows từ Windows98. Tôi chưa bao giờ làm điều gì đó với nó, chỉ googled xung quanh. Có vẻ như bạn có thể sử dụng nó.

+1

Còn vấn đề GDI + tôi đã đề cập trong câu hỏi gốc thì sao? –

5

Tôi đã sử dụng GDI + để tiết kiệm một bitmap như một PNG vào một tập tin. Bạn có lẽ nên kiểm tra thông tin MSDN về GDI + here và đặc biệt chức năng này GdipSaveImageToStream.

Hướng dẫn này here cũng có thể sẽ cung cấp một số trợ giúp.

3

GDI (trường cũ, không cộng) có phương thức GetDIBits có thể được yêu cầu xuất bit sử dụng nén PNG (BITMAPINFOHEADER::biCompression == BI_PNG). Tôi tự hỏi nếu điều này có thể được sử dụng để tạo ra một tập tin PNG? Sử dụng GetDIBits để viết các tập tin bitmap tiêu chuẩn là đủ phức tạp - vì vậy tôi nghi ngờ điều này sẽ càng khó khăn hơn.

+0

Đối với bất kỳ ai có thể nghĩ đến việc thực hiện điều này, hãy xem câu trả lời cho "GetDIBits() không thành công với nén PNG"] (https://stackoverflow.com/a/3101090/2910230) hoặc "[JPEG và PNG Các phần mở rộng cho các chức năng và cấu trúc bitmap cụ thể] (https://msdn.microsoft.com/en-us/library/dd145023 (VS.85) .aspx) "trên MSDN, nó liên kết tới. –

3

Nếu bạn chỉ muốn sử dụng API Windows, WIC là cách để thực hiện việc này và hỗ trợ cả Bitmap và PNG.

+0

Bạn có chắc chắn nó không bị giới hạn chiều rộng lạ như GDI + không? –

+0

Không, không chắc chắn - nhưng WIC chắc chắn hiện đại hơn và được cập nhật hơn GDI + –

6

Lớp CImage (ATL/MFC) hỗ trợ lưu thành định dạng PNG. Giống như giải pháp GDI +, nó cũng hỗ trợ lưu vào luồng. Dưới đây là một số mã tôi sử dụng để lưu nó vào một 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(); 

Tôi không biết nếu bạn muốn sử dụng ATL hoặc MFC, mặc dù.

+1

Than ôi, không có ATL/MFC trong dự án của tôi. –

+0

ok ... có lẽ phần tiết kiệm luồng có thể hữu ích, nó phải tương tự như một phần sử dụng GDI + – djeidot

+0

Điều này đã giúp tôi làm điều gì đó mà tôi đang làm, ít nhất là +1. – Aardvark

16

LodePNG là bộ mã hóa/giải mã PNG không có lib.

Các vấn đề liên quan