From 7a10e465ca4f5dacd1b59b4fb4d8318b8ccb0b0b Mon Sep 17 00:00:00 2001 From: Dimitri Schoolwerth Date: Fri, 19 Aug 2011 01:08:36 +0000 Subject: [PATCH 01/12] Improved saving of TIFF monochrome images. When reducing an RGB image to black and white any non-black pixel was treated as white resulting in mostly white images. Set the threshold to 127 instead to improve the looks of saved monochrome TIFF images. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@68777 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- src/common/imagtiff.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/imagtiff.cpp b/src/common/imagtiff.cpp index 59b7fb9b43..a10940d63c 100644 --- a/src/common/imagtiff.cpp +++ b/src/common/imagtiff.cpp @@ -658,7 +658,7 @@ bool wxTIFFHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbo uint8 reverse = 0; for ( int bp = 0; bp < 8; bp++ ) { - if ( ptr[column*24 + bp*3] > 0 ) + if ( ptr[column*24 + bp*3] > 127 ) { // check only red as this is sufficient reverse = (uint8)(reverse | 128 >> bp); From 6f54591185514725f14721bb873926602f5d42ee Mon Sep 17 00:00:00 2001 From: Dimitri Schoolwerth Date: Fri, 19 Aug 2011 01:13:16 +0000 Subject: [PATCH 02/12] improved wxImage documentation. moved description of wxIMAGE_OPTION_GIF_COMMENT from wxImage::GetOptionInt documentation to wxImage::GetOption because the value of the GIF option is a string, not int. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@68779 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- interface/wx/image.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/interface/wx/image.h b/interface/wx/image.h index cdeba80f58..a6cf2769cf 100644 --- a/interface/wx/image.h +++ b/interface/wx/image.h @@ -1084,10 +1084,16 @@ public: /** Gets a user-defined string-valued option. - Currently the only defined string option is + Generic options: @li @c wxIMAGE_OPTION_FILENAME: The name of the file from which the image was loaded. + Options specific to wxGIFHandler: + @li @c wxIMAGE_OPTION_GIF_COMMENT: The comment text that is read from + or written to the GIF file. In an animated GIF each frame can have + its own comment. If there is only a comment in the first frame of + a GIF it will not be repeated in other frames. + @param name The name of the option, case-insensitive. @return @@ -1162,12 +1168,6 @@ public: the resulting PNG file. Use this option if your application produces images with small size variation. - Options specific to wxGIFHandler: - @li @c wxIMAGE_OPTION_GIF_COMMENT: The comment text that is read from - or written to the GIF file. In an animated GIF each frame can have - its own comment. If there is only a comment in the first frame of - a GIF it will not be repeated in other frames. - @param name The name of the option, case-insensitive. @return From d65172db909ddd431a9f303949dadc57f6ac16fb Mon Sep 17 00:00:00 2001 From: Dimitri Schoolwerth Date: Fri, 19 Aug 2011 01:19:21 +0000 Subject: [PATCH 03/12] Renamed the options specific to the TIFF handler. The loading/saving options that are specific for TIFF were in the form of wxIMAGE_OPTION_ while all other non-generic options use the form wxIMAGE_OPTION__. Renamed the TIFF options to the form wxIMAGE_OPTION_TIFF_ and kept the old names for backwards compatibility. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@68780 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- include/wx/imagtiff.h | 14 ++++++++++---- src/common/imagtiff.cpp | 12 ++++++------ 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/include/wx/imagtiff.h b/include/wx/imagtiff.h index 3021a61e4a..19d1cf1c73 100644 --- a/include/wx/imagtiff.h +++ b/include/wx/imagtiff.h @@ -22,10 +22,16 @@ #include "wx/versioninfo.h" // defines for wxImage::SetOption -#define wxIMAGE_OPTION_BITSPERSAMPLE wxString(wxT("BitsPerSample")) -#define wxIMAGE_OPTION_SAMPLESPERPIXEL wxString(wxT("SamplesPerPixel")) -#define wxIMAGE_OPTION_COMPRESSION wxString(wxT("Compression")) -#define wxIMAGE_OPTION_IMAGEDESCRIPTOR wxString(wxT("ImageDescriptor")) +#define wxIMAGE_OPTION_TIFF_BITSPERSAMPLE wxString(wxT("BitsPerSample")) +#define wxIMAGE_OPTION_TIFF_SAMPLESPERPIXEL wxString(wxT("SamplesPerPixel")) +#define wxIMAGE_OPTION_TIFF_COMPRESSION wxString(wxT("Compression")) +#define wxIMAGE_OPTION_TIFF_IMAGEDESCRIPTOR wxString(wxT("ImageDescriptor")) + +// for backwards compatibility +#define wxIMAGE_OPTION_BITSPERSAMPLE wxIMAGE_OPTION_TIFF_BITSPERSAMPLE +#define wxIMAGE_OPTION_SAMPLESPERPIXEL wxIMAGE_OPTION_TIFF_SAMPLESPERPIXEL +#define wxIMAGE_OPTION_COMPRESSION wxIMAGE_OPTION_TIFF_COMPRESSION +#define wxIMAGE_OPTION_IMAGEDESCRIPTOR wxIMAGE_OPTION_TIFF_IMAGEDESCRIPTOR class WXDLLIMPEXP_CORE wxTIFFHandler: public wxImageHandler { diff --git a/src/common/imagtiff.cpp b/src/common/imagtiff.cpp index a10940d63c..80e9cb3d91 100644 --- a/src/common/imagtiff.cpp +++ b/src/common/imagtiff.cpp @@ -444,17 +444,17 @@ bool wxTIFFHandler::LoadFile( wxImage *image, wxInputStream& stream, bool verbos */ if ( TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &spp) ) { - image->SetOption(wxIMAGE_OPTION_SAMPLESPERPIXEL, spp); + image->SetOption(wxIMAGE_OPTION_TIFF_SAMPLESPERPIXEL, spp); } if ( TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &bpp) ) { - image->SetOption(wxIMAGE_OPTION_BITSPERSAMPLE, bpp); + image->SetOption(wxIMAGE_OPTION_TIFF_BITSPERSAMPLE, bpp); } if ( TIFFGetFieldDefaulted(tif, TIFFTAG_COMPRESSION, &compression) ) { - image->SetOption(wxIMAGE_OPTION_COMPRESSION, compression); + image->SetOption(wxIMAGE_OPTION_TIFF_COMPRESSION, compression); } // Set the resolution unit. @@ -587,15 +587,15 @@ bool wxTIFFHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbo } - int spp = image->GetOptionInt(wxIMAGE_OPTION_SAMPLESPERPIXEL); + int spp = image->GetOptionInt(wxIMAGE_OPTION_TIFF_SAMPLESPERPIXEL); if ( !spp ) spp = 3; - int bpp = image->GetOptionInt(wxIMAGE_OPTION_BITSPERSAMPLE); + int bpp = image->GetOptionInt(wxIMAGE_OPTION_TIFF_BITSPERSAMPLE); if ( !bpp ) bpp = 8; - int compression = image->GetOptionInt(wxIMAGE_OPTION_COMPRESSION); + int compression = image->GetOptionInt(wxIMAGE_OPTION_TIFF_COMPRESSION); if ( !compression ) { // we can't use COMPRESSION_LZW because current version of libtiff From 096c930c169aec8a027a065163cf78e3e46b224c Mon Sep 17 00:00:00 2001 From: Dimitri Schoolwerth Date: Fri, 19 Aug 2011 01:31:07 +0000 Subject: [PATCH 04/12] No code changes. Renamed variable bpp (bits per pixel) in TIFF handler to what it actually represents: bps (bits per sample). git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@68781 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- src/common/imagtiff.cpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/common/imagtiff.cpp b/src/common/imagtiff.cpp index 80e9cb3d91..3d8c102821 100644 --- a/src/common/imagtiff.cpp +++ b/src/common/imagtiff.cpp @@ -437,7 +437,7 @@ bool wxTIFFHandler::LoadFile( wxImage *image, wxInputStream& stream, bool verbos } - uint16 spp, bpp, compression; + uint16 spp, bps, compression; /* Read some baseline TIFF tags which helps when re-saving a TIFF to be similar to the original image. @@ -447,9 +447,9 @@ bool wxTIFFHandler::LoadFile( wxImage *image, wxInputStream& stream, bool verbos image->SetOption(wxIMAGE_OPTION_TIFF_SAMPLESPERPIXEL, spp); } - if ( TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &bpp) ) + if ( TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &bps) ) { - image->SetOption(wxIMAGE_OPTION_TIFF_BITSPERSAMPLE, bpp); + image->SetOption(wxIMAGE_OPTION_TIFF_BITSPERSAMPLE, bps); } if ( TIFFGetFieldDefaulted(tif, TIFFTAG_COMPRESSION, &compression) ) @@ -591,9 +591,9 @@ bool wxTIFFHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbo if ( !spp ) spp = 3; - int bpp = image->GetOptionInt(wxIMAGE_OPTION_TIFF_BITSPERSAMPLE); - if ( !bpp ) - bpp = 8; + int bps = image->GetOptionInt(wxIMAGE_OPTION_TIFF_BITSPERSAMPLE); + if ( !bps ) + bps = 8; int compression = image->GetOptionInt(wxIMAGE_OPTION_TIFF_COMPRESSION); if ( !compression ) @@ -606,20 +606,20 @@ bool wxTIFFHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbo } TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, spp); - TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bpp); - TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, spp*bpp == 1 ? PHOTOMETRIC_MINISBLACK + TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bps); + TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, spp*bps == 1 ? PHOTOMETRIC_MINISBLACK : PHOTOMETRIC_RGB); TIFFSetField(tif, TIFFTAG_COMPRESSION, compression); - // scanlinesize if determined by spp and bpp - tsize_t linebytes = (tsize_t)image->GetWidth() * spp * bpp / 8; + // scanlinesize if determined by spp and bps + tsize_t linebytes = (tsize_t)image->GetWidth() * spp * bps / 8; - if ( (image->GetWidth() % 8 > 0) && (spp * bpp < 8) ) + if ( (image->GetWidth() % 8 > 0) && (spp * bps < 8) ) linebytes+=1; unsigned char *buf; - if (TIFFScanlineSize(tif) > linebytes || (spp * bpp < 24)) + if (TIFFScanlineSize(tif) > linebytes || (spp * bps < 24)) { buf = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(tif)); if (!buf) @@ -646,7 +646,7 @@ bool wxTIFFHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbo { if ( buf ) { - if ( spp * bpp > 1 ) + if ( spp * bps > 1 ) { // color image memcpy(buf, ptr, image->GetWidth()); From 0e11090ef6cd6cf68a7ee521feb126006a70e368 Mon Sep 17 00:00:00 2001 From: Dimitri Schoolwerth Date: Fri, 19 Aug 2011 02:00:25 +0000 Subject: [PATCH 05/12] Fixed crash when saving as a monochrome TIFF image with incomplete options set. When setting only wxIMAGE_OPTION_TIFF_BITSPERSAMPLE to 1 the used samples per pixel (wxIMAGE_OPTION_TIFF_SAMPLESPERPIXEL) would still be set to 3. This is invalid and confuses libtiff, resulting in a crash ("possible heap corruption" during _TIFFfree using WinXP+MSVC8). Set the used samples per pixel to 1 explicitly in cases where only bits per sample is set to 1. Added a unit test to check for this problem (and verify the bits per sample from the saved image is indeed 1). git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@68782 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- src/common/imagtiff.cpp | 8 ++++++++ tests/image/image.cpp | 29 +++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/src/common/imagtiff.cpp b/src/common/imagtiff.cpp index 3d8c102821..b3209d39f9 100644 --- a/src/common/imagtiff.cpp +++ b/src/common/imagtiff.cpp @@ -593,7 +593,15 @@ bool wxTIFFHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbo int bps = image->GetOptionInt(wxIMAGE_OPTION_TIFF_BITSPERSAMPLE); if ( !bps ) + { bps = 8; + } + else if (bps == 1) + { + // One bit per sample combined with 3 samples per pixel is + // not allowed and crashes libtiff. + spp = 1; + } int compression = image->GetOptionInt(wxIMAGE_OPTION_TIFF_COMPRESSION); if ( !compression ) diff --git a/tests/image/image.cpp b/tests/image/image.cpp index 22384f5e1f..010bc1d278 100644 --- a/tests/image/image.cpp +++ b/tests/image/image.cpp @@ -73,6 +73,7 @@ private: CPPUNIT_TEST( CompareLoadedImage ); CPPUNIT_TEST( CompareSavedImage ); CPPUNIT_TEST( SavePNG ); + CPPUNIT_TEST( SaveTIFF ); CPPUNIT_TEST( SaveAnimatedGIF ); CPPUNIT_TEST( ReadCorruptedTGA ); CPPUNIT_TEST( GIFComment ); @@ -87,6 +88,7 @@ private: void CompareLoadedImage(); void CompareSavedImage(); void SavePNG(); + void SaveTIFF(); void SaveAnimatedGIF(); void ReadCorruptedTGA(); void GIFComment(); @@ -1088,6 +1090,33 @@ void ImageTestCase::SavePNG() } +static void TestTIFFImage(const wxString& option, int value) +{ + wxImage image("horse.png"); + + wxMemoryOutputStream memOut; + image.SetOption(option, value); + + CPPUNIT_ASSERT(image.SaveFile(memOut, wxBITMAP_TYPE_TIF)); + + wxMemoryInputStream memIn(memOut); + CPPUNIT_ASSERT(memIn.IsOk()); + + wxImage savedImage(memIn); + CPPUNIT_ASSERT(savedImage.IsOk()); + + WX_ASSERT_EQUAL_MESSAGE(("While checking for option %s", option), + true, savedImage.HasOption(option)); + + WX_ASSERT_EQUAL_MESSAGE(("While testing for %s", option), + value, savedImage.GetOptionInt(option)); +} + +void ImageTestCase::SaveTIFF() +{ + TestTIFFImage(wxIMAGE_OPTION_TIFF_BITSPERSAMPLE, 1); +} + void ImageTestCase::SaveAnimatedGIF() { #if wxUSE_PALETTE From 7f77b25ea8cad399e71bfce5514df6294cce1f45 Mon Sep 17 00:00:00 2001 From: Dimitri Schoolwerth Date: Fri, 19 Aug 2011 02:27:11 +0000 Subject: [PATCH 06/12] Changed TIFF handler's monochrome conversion to look at the green channel instead of red. It's common when reducing a coloured image to greyscale or black and white to give the green channel more significance. Since we're only looking at a single channel use the green one instead of red. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@68783 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- src/common/imagtiff.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/common/imagtiff.cpp b/src/common/imagtiff.cpp index b3209d39f9..e852fc00f0 100644 --- a/src/common/imagtiff.cpp +++ b/src/common/imagtiff.cpp @@ -666,9 +666,9 @@ bool wxTIFFHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbo uint8 reverse = 0; for ( int bp = 0; bp < 8; bp++ ) { - if ( ptr[column*24 + bp*3] > 127 ) + if ( ptr[column*24 + bp*3 + 1] > 127 ) { - // check only red as this is sufficient + // check only green as this is sufficient reverse = (uint8)(reverse | 128 >> bp); } } From 8e28cc4701896761cd2c306525be2a31eb622cf4 Mon Sep 17 00:00:00 2001 From: Dimitri Schoolwerth Date: Fri, 19 Aug 2011 02:35:48 +0000 Subject: [PATCH 07/12] Added support for saving greyscale TIFF images. When saving with a samples per pixel value of 1 the TIFF handler still treated the image as RGB, resulting in corrupted images. Handle the greyscale case and added a unit test for it. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@68784 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- src/common/imagtiff.cpp | 7 +++++++ tests/image/image.cpp | 1 + 2 files changed, 8 insertions(+) diff --git a/src/common/imagtiff.cpp b/src/common/imagtiff.cpp index e852fc00f0..d8d449c5cf 100644 --- a/src/common/imagtiff.cpp +++ b/src/common/imagtiff.cpp @@ -659,6 +659,13 @@ bool wxTIFFHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbo // color image memcpy(buf, ptr, image->GetWidth()); } + else if (spp * bps == 8) // greyscale image + { + for ( int column = 0; column < linebytes; column++ ) + { + buf[column] = ptr[column*3 + 1]; + } + } else // black and white image { for ( int column = 0; column < linebytes; column++ ) diff --git a/tests/image/image.cpp b/tests/image/image.cpp index 010bc1d278..9135e433b9 100644 --- a/tests/image/image.cpp +++ b/tests/image/image.cpp @@ -1115,6 +1115,7 @@ static void TestTIFFImage(const wxString& option, int value) void ImageTestCase::SaveTIFF() { TestTIFFImage(wxIMAGE_OPTION_TIFF_BITSPERSAMPLE, 1); + TestTIFFImage(wxIMAGE_OPTION_TIFF_SAMPLESPERPIXEL, 1); } void ImageTestCase::SaveAnimatedGIF() From fc695138b415c96a5b8a5a58086e5c393b4a349e Mon Sep 17 00:00:00 2001 From: Dimitri Schoolwerth Date: Fri, 19 Aug 2011 03:47:40 +0000 Subject: [PATCH 08/12] Added option to TIFF handler for specifying the photometric interpretation. Added option wxIMAGE_OPTION_TIFF_PHOTOMETRIC for reading and writing TIFF images. This is mostly for being able to distinguish between PHOTOMETRIC_MINISBLACK (chocolate flavour) and PHOTOMETRIC_MINISWHITE (vanilla) as currently the flavour used was fixed. It applies to greyscale as well as black and white images. Added unit tests to verify the written photometric value. Also see #13194. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@68785 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- include/wx/imagtiff.h | 1 + src/common/imagtiff.cpp | 41 +++++++++++++++++++++++++++++++++++------ tests/image/image.cpp | 2 ++ 3 files changed, 38 insertions(+), 6 deletions(-) diff --git a/include/wx/imagtiff.h b/include/wx/imagtiff.h index 19d1cf1c73..f1f4f74c6f 100644 --- a/include/wx/imagtiff.h +++ b/include/wx/imagtiff.h @@ -25,6 +25,7 @@ #define wxIMAGE_OPTION_TIFF_BITSPERSAMPLE wxString(wxT("BitsPerSample")) #define wxIMAGE_OPTION_TIFF_SAMPLESPERPIXEL wxString(wxT("SamplesPerPixel")) #define wxIMAGE_OPTION_TIFF_COMPRESSION wxString(wxT("Compression")) +#define wxIMAGE_OPTION_TIFF_PHOTOMETRIC wxString(wxT("Photometric")) #define wxIMAGE_OPTION_TIFF_IMAGEDESCRIPTOR wxString(wxT("ImageDescriptor")) // for backwards compatibility diff --git a/src/common/imagtiff.cpp b/src/common/imagtiff.cpp index d8d449c5cf..e4458e3f98 100644 --- a/src/common/imagtiff.cpp +++ b/src/common/imagtiff.cpp @@ -437,6 +437,8 @@ bool wxTIFFHandler::LoadFile( wxImage *image, wxInputStream& stream, bool verbos } + image->SetOption(wxIMAGE_OPTION_TIFF_PHOTOMETRIC, photometric); + uint16 spp, bps, compression; /* Read some baseline TIFF tags which helps when re-saving a TIFF @@ -603,6 +605,27 @@ bool wxTIFFHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbo spp = 1; } + int photometric = PHOTOMETRIC_RGB; + + if ( image->HasOption(wxIMAGE_OPTION_TIFF_PHOTOMETRIC) ) + { + photometric = image->GetOptionInt(wxIMAGE_OPTION_TIFF_PHOTOMETRIC); + if (photometric == PHOTOMETRIC_MINISWHITE + || photometric == PHOTOMETRIC_MINISBLACK) + { + // either b/w or greyscale + spp = 1; + } + } + else if (spp == 1) + { + photometric = PHOTOMETRIC_MINISBLACK; + } + + const bool isColouredImage = (spp > 1) + && (photometric != PHOTOMETRIC_MINISWHITE) + && (photometric != PHOTOMETRIC_MINISBLACK); + int compression = image->GetOptionInt(wxIMAGE_OPTION_TIFF_COMPRESSION); if ( !compression ) { @@ -615,8 +638,7 @@ bool wxTIFFHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbo TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, spp); TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bps); - TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, spp*bps == 1 ? PHOTOMETRIC_MINISBLACK - : PHOTOMETRIC_RGB); + TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, photometric); TIFFSetField(tif, TIFFTAG_COMPRESSION, compression); // scanlinesize if determined by spp and bps @@ -627,7 +649,7 @@ bool wxTIFFHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbo unsigned char *buf; - if (TIFFScanlineSize(tif) > linebytes || (spp * bps < 24)) + if (TIFFScanlineSize(tif) > linebytes || !isColouredImage) { buf = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(tif)); if (!buf) @@ -649,12 +671,13 @@ bool wxTIFFHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbo TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP,TIFFDefaultStripSize(tif, (uint32) -1)); + const bool minIsWhite = (photometric == PHOTOMETRIC_MINISWHITE); unsigned char *ptr = image->GetData(); for ( int row = 0; row < image->GetHeight(); row++ ) { if ( buf ) { - if ( spp * bps > 1 ) + if (isColouredImage) { // color image memcpy(buf, ptr, image->GetWidth()); @@ -663,7 +686,13 @@ bool wxTIFFHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbo { for ( int column = 0; column < linebytes; column++ ) { - buf[column] = ptr[column*3 + 1]; + uint8 value = ptr[column*3 + 1]; + if (minIsWhite) + { + value = 255 - value; + } + + buf[column] = value; } } else // black and white image @@ -673,7 +702,7 @@ bool wxTIFFHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbo uint8 reverse = 0; for ( int bp = 0; bp < 8; bp++ ) { - if ( ptr[column*24 + bp*3 + 1] > 127 ) + if ( (ptr[column*24 + bp*3 + 1] <=127) == minIsWhite ) { // check only green as this is sufficient reverse = (uint8)(reverse | 128 >> bp); diff --git a/tests/image/image.cpp b/tests/image/image.cpp index 9135e433b9..0350dcbfa9 100644 --- a/tests/image/image.cpp +++ b/tests/image/image.cpp @@ -1116,6 +1116,8 @@ void ImageTestCase::SaveTIFF() { TestTIFFImage(wxIMAGE_OPTION_TIFF_BITSPERSAMPLE, 1); TestTIFFImage(wxIMAGE_OPTION_TIFF_SAMPLESPERPIXEL, 1); + TestTIFFImage(wxIMAGE_OPTION_TIFF_PHOTOMETRIC, 0/*PHOTOMETRIC_MINISWHITE*/); + TestTIFFImage(wxIMAGE_OPTION_TIFF_PHOTOMETRIC, 1/*PHOTOMETRIC_MINISBLACK*/); } void ImageTestCase::SaveAnimatedGIF() From 2453ceee20aab72c214ec26b4757c4ac6d09cfbd Mon Sep 17 00:00:00 2001 From: Dimitri Schoolwerth Date: Fri, 19 Aug 2011 03:50:45 +0000 Subject: [PATCH 09/12] Use a default photometric interpretation value of PHOTOMETRIC_MINISWHITE instead of PHOTOMETRIC_MINISBLACK for greyscale and b/w TIFF images. Closes #13194. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@68786 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- src/common/imagtiff.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/imagtiff.cpp b/src/common/imagtiff.cpp index e4458e3f98..40083e6bab 100644 --- a/src/common/imagtiff.cpp +++ b/src/common/imagtiff.cpp @@ -619,7 +619,7 @@ bool wxTIFFHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbo } else if (spp == 1) { - photometric = PHOTOMETRIC_MINISBLACK; + photometric = PHOTOMETRIC_MINISWHITE; } const bool isColouredImage = (spp > 1) From 659185ff8057016daa5ffd462981df4db112e805 Mon Sep 17 00:00:00 2001 From: Dimitri Schoolwerth Date: Fri, 19 Aug 2011 03:57:06 +0000 Subject: [PATCH 10/12] Documented wxIMAGE_OPTION_TIFF_* options that are currently in use. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@68787 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- interface/wx/image.h | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/interface/wx/image.h b/interface/wx/image.h index a6cf2769cf..7c5dcd6b2f 100644 --- a/interface/wx/image.h +++ b/interface/wx/image.h @@ -1168,6 +1168,39 @@ public: the resulting PNG file. Use this option if your application produces images with small size variation. + Options specific to wxTIFFHandler: + @li @c wxIMAGE_OPTION_TIFF_BITSPERSAMPLE: Number of bits per + sample (channel). Currently values of 1 and 8 are supported. A + value of 1 results in a black and white image. A value of 8 (the + default) can mean greyscale or RGB, depending on the value of + @c wxIMAGE_OPTION_TIFF_SAMPLESPERPIXEL. + @li @c wxIMAGE_OPTION_TIFF_SAMPLESPERPIXEL: Number of samples + (channels) per pixel. Currently values of 1 and 3 are supported. + A value of 1 results in either a greyscale (by default) or black and + white image, depending on the value of + @c wxIMAGE_OPTION_TIFF_BITSPERSAMPLE. A value of 3 (the default) + will result in an RGB image. + @li @c wxIMAGE_OPTION_TIFF_COMPRESSION: Compression type. By default + it is set to 1 (COMPRESSION_NONE). Typical other values are + 5 (COMPRESSION_LZW) and 7 (COMPRESSION_JPEG). See tiff.h for more + options. + @li @c wxIMAGE_OPTION_TIFF_PHOTOMETRIC: Specifies the photometric + interpretation. By default it is set to 2 (PHOTOMETRIC_RGB) for RGB + images and 0 (PHOTOMETRIC_MINISWHITE) for greyscale or black and + white images. It can also be set to 1 (PHOTOMETRIC_MINISBLACK) to + treat the lowest value as black and highest as white. + If you want a greyscale image it is also sufficient to only specify + @c wxIMAGE_OPTION_TIFF_PHOTOMETRIC and set it to either + PHOTOMETRIC_MINISWHITE or PHOTOMETRIC_MINISBLACK. The other values + are taken care of. + + @note + Be careful when combining the options @c wxIMAGE_OPTION_TIFF_SAMPLESPERPIXEL, + @c wxIMAGE_OPTION_TIFF_BITSPERSAMPLE, and @c wxIMAGE_OPTION_TIFF_PHOTOMETRIC. + While some measures are taken to prevent illegal combinations and/or + values, it is still easy to abuse them and come up with invalid + results in the form of either corrupted images or crashes. + @param name The name of the option, case-insensitive. @return From 409fe759e1b605514eabcddfb546dc876b9a9161 Mon Sep 17 00:00:00 2001 From: Dimitri Schoolwerth Date: Fri, 19 Aug 2011 16:10:07 +0000 Subject: [PATCH 11/12] Fixed failing test in ImageTestCase for builds made with makefiles. The recently added BMP images in tests/image/ were not being copied. Added them to test.bkl and regenerated makefiles. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@68791 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- tests/Makefile.in | 16 ++++++++++++++-- tests/makefile.bcc | 6 +++++- tests/makefile.gcc | 8 ++++++-- tests/makefile.vc | 6 +++++- tests/makefile.wat | 6 +++++- tests/test.bkl | 8 ++++++++ 6 files changed, 43 insertions(+), 7 deletions(-) diff --git a/tests/Makefile.in b/tests/Makefile.in index 26ae782b00..396d64ab28 100644 --- a/tests/Makefile.in +++ b/tests/Makefile.in @@ -338,7 +338,7 @@ COND_wxUSE_REGEX_builtin___LIB_REGEX_p = \ ### Targets: ### -all: test$(EXEEXT) $(__test_gui___depname) $(__test_gui_bundle___depname) data fr +all: test$(EXEEXT) $(__test_gui___depname) $(__test_gui_bundle___depname) data data-images fr install: @@ -406,6 +406,18 @@ data: esac; \ done +data-images: + @mkdir -p image + @for f in horse_grey.bmp horse_grey_flipped.bmp horse_rle4.bmp horse_rle4_flipped.bmp horse_rle8.bmp horse_rle8_flipped.bmp; do \ + if test ! -f image/$$f -a ! -d image/$$f ; \ + then x=yep ; \ + else x=`find $(srcdir)/image/$$f -newer image/$$f -print` ; \ + fi; \ + case "$$x" in ?*) \ + cp -pRf $(srcdir)/image/$$f image ;; \ + esac; \ + done + fr: @mkdir -p ./intl/fr @for f in internat.po internat.mo; do \ @@ -925,4 +937,4 @@ failtest: # Include dependency info, if present: @IF_GNU_MAKE@-include ./.deps/*.d -.PHONY: all install uninstall clean distclean test_gui_bundle data fr +.PHONY: all install uninstall clean distclean test_gui_bundle data data-images fr diff --git a/tests/makefile.bcc b/tests/makefile.bcc index 812e939fae..d1c4d4f5b0 100644 --- a/tests/makefile.bcc +++ b/tests/makefile.bcc @@ -421,7 +421,7 @@ $(OBJS): ### Targets: ### -all: $(OBJS)\test.exe $(__test_gui___depname) data fr +all: $(OBJS)\test.exe $(__test_gui___depname) data data-images fr clean: -if exist $(OBJS)\*.obj del $(OBJS)\*.obj @@ -456,6 +456,10 @@ data: if not exist $(OBJS) mkdir $(OBJS) for %f in (horse.ani horse.bmp horse.cur horse.gif horse.ico horse.jpg horse.pcx horse.png horse.pnm horse.tga horse.tif horse.xpm) do if not exist $(OBJS)\%f copy .\%f $(OBJS) +data-images: + if not exist image mkdir image + for %f in (horse_grey.bmp horse_grey_flipped.bmp horse_rle4.bmp horse_rle4_flipped.bmp horse_rle8.bmp horse_rle8_flipped.bmp) do if not exist image\%f copy .\image\%f image + fr: if not exist $(OBJS)\intl\fr mkdir $(OBJS)\intl\fr for %f in (internat.po internat.mo) do if not exist $(OBJS)\intl\fr\%f copy .\intl\fr\%f $(OBJS)\intl\fr diff --git a/tests/makefile.gcc b/tests/makefile.gcc index 49ea23cddd..cdcc61af59 100644 --- a/tests/makefile.gcc +++ b/tests/makefile.gcc @@ -417,7 +417,7 @@ $(OBJS): ### Targets: ### -all: $(OBJS)\test.exe $(__test_gui___depname) data fr +all: $(OBJS)\test.exe $(__test_gui___depname) data data-images fr clean: -if exist $(OBJS)\*.o del $(OBJS)\*.o @@ -437,6 +437,10 @@ data: if not exist $(OBJS) mkdir $(OBJS) for %%f in (horse.ani horse.bmp horse.cur horse.gif horse.ico horse.jpg horse.pcx horse.png horse.pnm horse.tga horse.tif horse.xpm) do if not exist $(OBJS)\%%f copy .\%%f $(OBJS) +data-images: + if not exist image mkdir image + for %%f in (horse_grey.bmp horse_grey_flipped.bmp horse_rle4.bmp horse_rle4_flipped.bmp horse_rle8.bmp horse_rle8_flipped.bmp) do if not exist image\%%f copy .\image\%%f image + fr: if not exist $(OBJS)\intl\fr mkdir $(OBJS)\intl\fr for %%f in (internat.po internat.mo) do if not exist $(OBJS)\intl\fr\%%f copy .\intl\fr\%%f $(OBJS)\intl\fr @@ -933,7 +937,7 @@ $(OBJS)\test_gui_setsize.o: ./window/setsize.cpp $(OBJS)\test_gui_xrctest.o: ./xml/xrctest.cpp $(CXX) -c -o $@ $(TEST_GUI_CXXFLAGS) $(CPPDEPS) $< -.PHONY: all clean data fr +.PHONY: all clean data data-images fr SHELL := $(COMSPEC) diff --git a/tests/makefile.vc b/tests/makefile.vc index 91f4734924..86c782f582 100644 --- a/tests/makefile.vc +++ b/tests/makefile.vc @@ -553,7 +553,7 @@ $(OBJS): ### Targets: ### -all: $(OBJS)\test.exe $(__test_gui___depname) data fr +all: $(OBJS)\test.exe $(__test_gui___depname) data data-images fr clean: -if exist $(OBJS)\*.obj del $(OBJS)\*.obj @@ -582,6 +582,10 @@ data: if not exist $(OBJS) mkdir $(OBJS) for %f in (horse.ani horse.bmp horse.cur horse.gif horse.ico horse.jpg horse.pcx horse.png horse.pnm horse.tga horse.tif horse.xpm) do if not exist $(OBJS)\%f copy .\%f $(OBJS) +data-images: + if not exist image mkdir image + for %f in (horse_grey.bmp horse_grey_flipped.bmp horse_rle4.bmp horse_rle4_flipped.bmp horse_rle8.bmp horse_rle8_flipped.bmp) do if not exist image\%f copy .\image\%f image + fr: if not exist $(OBJS)\intl\fr mkdir $(OBJS)\intl\fr for %f in (internat.po internat.mo) do if not exist $(OBJS)\intl\fr\%f copy .\intl\fr\%f $(OBJS)\intl\fr diff --git a/tests/makefile.wat b/tests/makefile.wat index e566570d79..51549e53ed 100644 --- a/tests/makefile.wat +++ b/tests/makefile.wat @@ -455,7 +455,7 @@ $(OBJS) : ### Targets: ### -all : .SYMBOLIC $(OBJS)\test.exe $(__test_gui___depname) data fr +all : .SYMBOLIC $(OBJS)\test.exe $(__test_gui___depname) data data-images fr clean : .SYMBOLIC -if exist $(OBJS)\*.obj del $(OBJS)\*.obj @@ -496,6 +496,10 @@ data : .SYMBOLIC if not exist $(OBJS) mkdir $(OBJS) for %f in (horse.ani horse.bmp horse.cur horse.gif horse.ico horse.jpg horse.pcx horse.png horse.pnm horse.tga horse.tif horse.xpm) do if not exist $(OBJS)\%f copy .\%f $(OBJS) +data-images : .SYMBOLIC + if not exist image mkdir image + for %f in (horse_grey.bmp horse_grey_flipped.bmp horse_rle4.bmp horse_rle4_flipped.bmp horse_rle8.bmp horse_rle8_flipped.bmp) do if not exist image\%f copy .\image\%f image + fr : .SYMBOLIC if not exist $(OBJS)\intl\fr mkdir $(OBJS)\intl\fr for %f in (internat.po internat.mo) do if not exist $(OBJS)\intl\fr\%f copy .\intl\fr\%f $(OBJS)\intl\fr diff --git a/tests/test.bkl b/tests/test.bkl index 344abee419..ba5bf00ae7 100644 --- a/tests/test.bkl +++ b/tests/test.bkl @@ -230,6 +230,14 @@ horse.pcx horse.png horse.pnm horse.tga horse.tif horse.xpm + + $(SRCDIR)/image + image + horse_grey.bmp horse_grey_flipped.bmp + horse_rle4.bmp horse_rle4_flipped.bmp + horse_rle8.bmp horse_rle8_flipped.bmp + +