mirror of
https://github.com/wxWidgets/wxWidgets.git
synced 2026-09-22 22:24:56 +08:00
Add support for working with PNG "Description" text chunk
Add wxIMAGE_OPTION_PNG_DESCRIPTION which is filled with the contents of the (first) "Description" chunk from the PNG file when loading it and saved into such (iTXt) chunk when saving. Fixes #25556. Closes #25565.
This commit is contained in:
committed by
Vadim Zeitlin
parent
d3da0e8ea2
commit
4c2ffb0c5b
@@ -27,6 +27,7 @@
|
||||
#define wxIMAGE_OPTION_PNG_COMPRESSION_MEM_LEVEL wxT("PngZM")
|
||||
#define wxIMAGE_OPTION_PNG_COMPRESSION_STRATEGY wxT("PngZS")
|
||||
#define wxIMAGE_OPTION_PNG_COMPRESSION_BUFFER_SIZE wxT("PngZB")
|
||||
#define wxIMAGE_OPTION_PNG_DESCRIPTION wxT("PngDescription")
|
||||
|
||||
enum
|
||||
{
|
||||
|
||||
@@ -148,6 +148,7 @@ enum wxImagePNGType
|
||||
#define wxIMAGE_OPTION_PNG_COMPRESSION_MEM_LEVEL wxString("PngZM")
|
||||
#define wxIMAGE_OPTION_PNG_COMPRESSION_STRATEGY wxString("PngZS")
|
||||
#define wxIMAGE_OPTION_PNG_COMPRESSION_BUFFER_SIZE wxString("PngZB")
|
||||
#define wxIMAGE_OPTION_PNG_DESCRIPTION wxString("PngDescription")
|
||||
|
||||
#define wxIMAGE_OPTION_TIFF_BITSPERSAMPLE wxString("BitsPerSample")
|
||||
#define wxIMAGE_OPTION_TIFF_SAMPLESPERPIXEL wxString("SamplesPerPixel")
|
||||
@@ -1322,6 +1323,16 @@ public:
|
||||
its own comment. If there is only a comment in the first frame of
|
||||
a GIF it will not be repeated in other frames.
|
||||
|
||||
Options specific to wxPNGHandler:
|
||||
@li @c wxIMAGE_OPTION_PNG_DESCRIPTION: The contents of this option
|
||||
will be converted to an uncompressed iTXt chunk with the
|
||||
key: "Description", and written to the PNG file upon saving.
|
||||
Contents of tXTt and iTXt chunks with the key: "Description" are
|
||||
also automatically retrieved upon loading a PNG file, and stored
|
||||
in this option. If multiple chunks with this key are present,
|
||||
only one is retrieved.
|
||||
@since 3.3.1
|
||||
|
||||
@param name
|
||||
The name of the option, case-insensitive.
|
||||
@return
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#define wxIMAGE_OPTION_PNG_COMPRESSION_MEM_LEVEL wxT("PngZM")
|
||||
#define wxIMAGE_OPTION_PNG_COMPRESSION_STRATEGY wxT("PngZS")
|
||||
#define wxIMAGE_OPTION_PNG_COMPRESSION_BUFFER_SIZE wxT("PngZB")
|
||||
#define wxIMAGE_OPTION_PNG_DESCRIPTION wxT("PngDescription")
|
||||
|
||||
/* These are already in interface/wx/image.h
|
||||
They were likely put there as a stopgap, but they've been there long enough
|
||||
|
||||
+55
-1
@@ -37,6 +37,8 @@
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#define wxIMAGE_OPTION_PNG_DESCRIPTION_KEY "Description"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// local functions
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -189,7 +191,7 @@ PNGLINKAGEMODE wx_PNG_warning(png_structp png_ptr, png_const_charp message)
|
||||
wxPNGInfoStruct *info = png_ptr ? WX_PNG_INFO(png_ptr) : nullptr;
|
||||
if ( !info || info->verbose )
|
||||
{
|
||||
wxLogWarning( wxString::FromAscii(message) );
|
||||
wxLogWarning( wxString::FromUTF8(message) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -342,6 +344,40 @@ wxPNGImageData::DoLoadPNGFile(wxImage* image, wxPNGInfoStruct& wxinfo)
|
||||
return;
|
||||
|
||||
png_read_image( png_ptr, lines );
|
||||
|
||||
// load "Description" text chunk
|
||||
png_textp text_ptr;
|
||||
const int num_comments = png_get_text( png_ptr, info_ptr, &text_ptr, nullptr );
|
||||
for (int i = 0; i < num_comments; ++i)
|
||||
{
|
||||
const wxString& key = wxString::From8BitData(text_ptr[i].key);
|
||||
if (key == wxIMAGE_OPTION_PNG_DESCRIPTION_KEY)
|
||||
{
|
||||
wxString description;
|
||||
switch (text_ptr[i].compression)
|
||||
{
|
||||
case PNG_TEXT_COMPRESSION_zTXt:
|
||||
case PNG_TEXT_COMPRESSION_NONE:
|
||||
// tEXt chunk: uses Latin-1 encoding.
|
||||
description = wxString::From8BitData(text_ptr[i].text);
|
||||
break;
|
||||
|
||||
case PNG_ITXT_COMPRESSION_zTXt:
|
||||
case PNG_ITXT_COMPRESSION_NONE:
|
||||
// iTXt chunk: uses UTF-8 encoding.
|
||||
description = wxString::FromUTF8(text_ptr[i].text);
|
||||
break;
|
||||
|
||||
default:
|
||||
// Invalid type, should we report it? Probably not worth it.
|
||||
break;
|
||||
}
|
||||
|
||||
if (!description.empty())
|
||||
image->SetOption(wxIMAGE_OPTION_PNG_DESCRIPTION, description);
|
||||
}
|
||||
}
|
||||
|
||||
png_read_end( png_ptr, info_ptr );
|
||||
|
||||
#if wxUSE_PALETTE
|
||||
@@ -737,6 +773,24 @@ bool wxPNGHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbos
|
||||
png_set_pHYs( png_ptr, info_ptr, resX, resY, PNG_RESOLUTION_METER );
|
||||
|
||||
png_set_sBIT( png_ptr, info_ptr, &sig_bit );
|
||||
|
||||
// save "Description" text chunk
|
||||
if (image->HasOption(wxIMAGE_OPTION_PNG_DESCRIPTION))
|
||||
{
|
||||
const wxString& description = image->GetOption(wxIMAGE_OPTION_PNG_DESCRIPTION);
|
||||
|
||||
png_text text;
|
||||
text.key = const_cast<char*>(wxIMAGE_OPTION_PNG_DESCRIPTION_KEY);
|
||||
text.lang = nullptr;
|
||||
text.lang_key = nullptr;
|
||||
text.compression = PNG_ITXT_COMPRESSION_NONE;
|
||||
const auto& buf = description.utf8_str();
|
||||
text.text = const_cast<char*>(buf.data());
|
||||
text.itxt_length = buf.length();
|
||||
text.text_length = 0;
|
||||
png_set_text( png_ptr, info_ptr, &text, 1 );
|
||||
}
|
||||
|
||||
png_write_info( png_ptr, info_ptr );
|
||||
png_set_shift( png_ptr, &sig_bit );
|
||||
png_set_packing( png_ptr );
|
||||
|
||||
@@ -1069,6 +1069,34 @@ TEST_CASE_METHOD(ImageHandlersInit, "wxImage::SavePNG", "[image]")
|
||||
|
||||
}
|
||||
|
||||
static void TestPNGDescription(const wxString& description)
|
||||
{
|
||||
wxImage image("horse.png");
|
||||
|
||||
image.SetOption(wxIMAGE_OPTION_PNG_DESCRIPTION, description);
|
||||
wxMemoryOutputStream memOut;
|
||||
REQUIRE(image.SaveFile(memOut, wxBITMAP_TYPE_PNG));
|
||||
|
||||
wxMemoryInputStream memIn(memOut);
|
||||
REQUIRE(image.LoadFile(memIn));
|
||||
|
||||
CHECK(image.GetOption(wxIMAGE_OPTION_PNG_DESCRIPTION) == description);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(ImageHandlersInit, "wxImage::PNGDescription", "[image]")
|
||||
{
|
||||
// Test writing a description and reading it back.
|
||||
TestPNGDescription("Providing the PNG a pneumatic puma as a present");
|
||||
|
||||
// Test writing and reading a description again but with non-ASCII characters.
|
||||
TestPNGDescription("Тестирование 테스트 一 二 三");
|
||||
|
||||
// Test writing and reading a description again but with a long description.
|
||||
TestPNGDescription(wxString(wxT('a'), 256)
|
||||
+ wxString(wxT('b'), 256)
|
||||
+ wxString(wxT('c'), 256));
|
||||
}
|
||||
|
||||
#if wxUSE_LIBTIFF
|
||||
static void TestTIFFImage(const wxString& option, int value,
|
||||
const wxImage *compareImage = nullptr)
|
||||
|
||||
Reference in New Issue
Block a user