1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: tests/image/image.cpp
3 // Purpose: Test wxImage
4 // Author: Francesco Montorsi
6 // Copyright: (c) 2009 Francesco Montorsi
7 // Licence: wxWindows licence
8 ///////////////////////////////////////////////////////////////////////////////
10 // ----------------------------------------------------------------------------
12 // ----------------------------------------------------------------------------
25 #include "wx/anidecod.h" // wxImageArray
26 #include "wx/palette.h"
29 #include "wx/mstream.h"
30 #include "wx/zstream.h"
31 #include "wx/wfstream.h"
33 #include "testimage.h"
41 { "horse.ico", wxBITMAP_TYPE_ICO
, 4 },
42 { "horse.xpm", wxBITMAP_TYPE_XPM
, 8 },
43 { "horse.png", wxBITMAP_TYPE_PNG
, 24 },
44 { "horse.ani", wxBITMAP_TYPE_ANI
, 24 },
45 { "horse.bmp", wxBITMAP_TYPE_BMP
, 8 },
46 { "horse.cur", wxBITMAP_TYPE_CUR
, 1 },
47 { "horse.gif", wxBITMAP_TYPE_GIF
, 8 },
48 { "horse.jpg", wxBITMAP_TYPE_JPEG
, 24 },
49 { "horse.pcx", wxBITMAP_TYPE_PCX
, 8 },
50 { "horse.pnm", wxBITMAP_TYPE_PNM
, 24 },
51 { "horse.tga", wxBITMAP_TYPE_TGA
, 8 },
52 { "horse.tif", wxBITMAP_TYPE_TIFF
, 8 }
56 // ----------------------------------------------------------------------------
58 // ----------------------------------------------------------------------------
60 class ImageTestCase
: public CppUnit::TestCase
67 CPPUNIT_TEST_SUITE( ImageTestCase
);
68 CPPUNIT_TEST( LoadFromSocketStream
);
69 CPPUNIT_TEST( LoadFromZipStream
);
70 CPPUNIT_TEST( LoadFromFile
);
71 CPPUNIT_TEST( SizeImage
);
72 CPPUNIT_TEST( CompareLoadedImage
);
73 CPPUNIT_TEST( CompareSavedImage
);
74 CPPUNIT_TEST( SavePNG
);
75 CPPUNIT_TEST( SaveTIFF
);
76 CPPUNIT_TEST( SaveAnimatedGIF
);
77 CPPUNIT_TEST( ReadCorruptedTGA
);
78 CPPUNIT_TEST( GIFComment
);
79 CPPUNIT_TEST( DibPadding
);
80 CPPUNIT_TEST( BMPFlippingAndRLECompression
);
81 CPPUNIT_TEST( ScaleCompare
);
82 CPPUNIT_TEST_SUITE_END();
84 void LoadFromSocketStream();
85 void LoadFromZipStream();
88 void CompareLoadedImage();
89 void CompareSavedImage();
92 void SaveAnimatedGIF();
93 void ReadCorruptedTGA();
96 void BMPFlippingAndRLECompression();
99 DECLARE_NO_COPY_CLASS(ImageTestCase
)
102 CPPUNIT_TEST_SUITE_REGISTRATION( ImageTestCase
);
103 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( ImageTestCase
, "ImageTestCase" );
105 ImageTestCase::ImageTestCase()
107 wxSocketBase::Initialize();
109 // the formats we're going to test:
110 wxImage::AddHandler(new wxICOHandler
);
111 wxImage::AddHandler(new wxXPMHandler
);
112 wxImage::AddHandler(new wxPNGHandler
);
113 wxImage::AddHandler(new wxANIHandler
);
114 wxImage::AddHandler(new wxBMPHandler
);
115 wxImage::AddHandler(new wxCURHandler
);
116 wxImage::AddHandler(new wxGIFHandler
);
117 wxImage::AddHandler(new wxJPEGHandler
);
118 wxImage::AddHandler(new wxPCXHandler
);
119 wxImage::AddHandler(new wxPNMHandler
);
120 wxImage::AddHandler(new wxTGAHandler
);
121 wxImage::AddHandler(new wxTIFFHandler
);
124 ImageTestCase::~ImageTestCase()
126 wxSocketBase::Shutdown();
129 void ImageTestCase::LoadFromFile()
132 for (unsigned int i
=0; i
<WXSIZEOF(g_testfiles
); i
++)
133 CPPUNIT_ASSERT(img
.LoadFile(g_testfiles
[i
].file
));
136 void ImageTestCase::LoadFromSocketStream()
138 if (!IsNetworkAvailable()) // implemented in test.cpp
140 wxLogWarning("No network connectivity; skipping the "
141 "ImageTestCase::LoadFromSocketStream test unit.");
150 { "http://www.wxwidgets.org/logo9.jpg", wxBITMAP_TYPE_JPEG
},
151 { "http://www.wxwidgets.org/favicon.ico", wxBITMAP_TYPE_ICO
}
154 for (unsigned int i
=0; i
<WXSIZEOF(testData
); i
++)
156 wxURL
url(testData
[i
].url
);
157 WX_ASSERT_EQUAL_MESSAGE
159 ("Constructing URL \"%s\" failed.", testData
[i
].url
),
164 wxInputStream
*in_stream
= url
.GetInputStream();
167 ("Opening URL \"%s\" failed.", testData
[i
].url
),
168 in_stream
&& in_stream
->IsOk()
173 // NOTE: it's important to inform wxImage about the type of the image being
174 // loaded otherwise it will try to autodetect the format, but that
175 // requires a seekable stream!
178 ("Loading image from \"%s\" failed.", testData
[i
].url
),
179 img
.LoadFile(*in_stream
, testData
[i
].type
)
186 void ImageTestCase::LoadFromZipStream()
188 for (unsigned int i
=0; i
<WXSIZEOF(g_testfiles
); i
++)
190 switch (g_testfiles
[i
].type
)
192 case wxBITMAP_TYPE_XPM
:
193 case wxBITMAP_TYPE_GIF
:
194 case wxBITMAP_TYPE_PCX
:
195 case wxBITMAP_TYPE_TGA
:
196 case wxBITMAP_TYPE_TIFF
:
197 continue; // skip testing those wxImageHandlers which cannot
198 // load data from non-seekable streams
204 // compress the test file on the fly:
205 wxMemoryOutputStream memOut
;
207 wxFileInputStream
file(g_testfiles
[i
].file
);
208 CPPUNIT_ASSERT(file
.IsOk());
210 wxZlibOutputStream
compressFilter(memOut
, 5, wxZLIB_GZIP
);
211 CPPUNIT_ASSERT(compressFilter
.IsOk());
213 file
.Read(compressFilter
);
214 CPPUNIT_ASSERT(file
.GetLastError() == wxSTREAM_EOF
);
217 // now fetch the compressed memory to wxImage, decompressing it on the fly; this
218 // allows us to test loading images from non-seekable streams other than socket streams
219 wxMemoryInputStream
memIn(memOut
);
220 CPPUNIT_ASSERT(memIn
.IsOk());
221 wxZlibInputStream
decompressFilter(memIn
, wxZLIB_GZIP
);
222 CPPUNIT_ASSERT(decompressFilter
.IsOk());
226 // NOTE: it's important to inform wxImage about the type of the image being
227 // loaded otherwise it will try to autodetect the format, but that
228 // requires a seekable stream!
229 WX_ASSERT_MESSAGE(("Could not load file type '%d' after it was zipped", g_testfiles
[i
].type
),
230 img
.LoadFile(decompressFilter
, g_testfiles
[i
].type
));
234 void ImageTestCase::SizeImage()
236 // Test the wxImage::Size() function which takes a rectangle from source and
237 // places it in a new image at a given position. This test checks, if the
238 // correct areas are chosen, and clipping is done correctly.
241 static const char * xpm_orig
[] = {
242 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
254 // the expected results for all tests:
255 static const char * xpm_l_t
[] = {
256 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
268 static const char * xpm_t
[] = {
269 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
281 static const char * xpm_r_t
[] = {
282 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
294 static const char * xpm_l
[] = {
295 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
307 static const char * xpm_r
[] = {
308 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
320 static const char * xpm_l_b
[] = {
321 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
333 static const char * xpm_b
[] = {
334 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
346 static const char * xpm_r_b
[] = {
347 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
359 static const char * xpm_sm
[] = {
360 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
370 static const char * xpm_gt
[] = {
371 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
385 static const char * xpm_gt_l_t
[] = {
386 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
400 static const char * xpm_gt_l
[] = {
401 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
415 static const char * xpm_gt_l_b
[] = {
416 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
430 static const char * xpm_gt_l_bb
[] = {
431 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
445 static const char * xpm_gt_t
[] = {
446 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
460 static const char * xpm_gt_b
[] = {
461 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
475 static const char * xpm_gt_bb
[] = {
476 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
490 static const char * xpm_gt_r_t
[] = {
491 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
505 static const char * xpm_gt_r
[] = {
506 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
520 static const char * xpm_gt_r_b
[] = {
521 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
535 static const char * xpm_gt_r_bb
[] = {
536 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
550 static const char * xpm_gt_rr_t
[] = {
551 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
565 static const char * xpm_gt_rr
[] = {
566 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
580 static const char * xpm_gt_rr_b
[] = {
581 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
595 static const char * xpm_gt_rr_bb
[] = {
596 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
610 static const char * xpm_sm_ll_tt
[] = {
611 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
621 static const char * xpm_sm_ll_t
[] = {
622 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
632 static const char * xpm_sm_ll
[] = {
633 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
643 static const char * xpm_sm_ll_b
[] = {
644 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
654 static const char * xpm_sm_l_tt
[] = {
655 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
665 static const char * xpm_sm_l_t
[] = {
666 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
676 static const char * xpm_sm_l
[] = {
677 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
687 static const char * xpm_sm_l_b
[] = {
688 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
698 static const char * xpm_sm_tt
[] = {
699 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
709 static const char * xpm_sm_t
[] = {
710 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
720 static const char * xpm_sm_b
[] = {
721 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
731 static const char * xpm_sm_r_tt
[] = {
732 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
742 static const char * xpm_sm_r_t
[] = {
743 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
753 static const char * xpm_sm_r
[] = {
754 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
764 static const char * xpm_sm_r_b
[] = {
765 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
776 // this table defines all tests
779 int w
, h
, dx
, dy
; // first parameters for Size()
780 const char **ref_xpm
; // expected result
783 { 10, 10, 0, 0, xpm_orig
}, // same size, same position
784 { 12, 12, 0, 0, xpm_gt
}, // target larger, same position
785 { 8, 8, 0, 0, xpm_sm
}, // target smaller, same position
786 { 10, 10, -2, -2, xpm_l_t
}, // same size, move left up
787 { 10, 10, -2, 0, xpm_l
}, // same size, move left
788 { 10, 10, -2, 2, xpm_l_b
}, // same size, move left down
789 { 10, 10, 0, -2, xpm_t
}, // same size, move up
790 { 10, 10, 0, 2, xpm_b
}, // same size, move down
791 { 10, 10, 2, -2, xpm_r_t
}, // same size, move right up
792 { 10, 10, 2, 0, xpm_r
}, // same size, move right
793 { 10, 10, 2, 2, xpm_r_b
}, // same size, move right down
794 { 12, 12, -2, -2, xpm_gt_l_t
}, // target larger, move left up
795 { 12, 12, -2, 0, xpm_gt_l
}, // target larger, move left
796 { 12, 12, -2, 2, xpm_gt_l_b
}, // target larger, move left down
797 { 12, 12, -2, 4, xpm_gt_l_bb
}, // target larger, move left down
798 { 12, 12, 0, -2, xpm_gt_t
}, // target larger, move up
799 { 12, 12, 0, 2, xpm_gt_b
}, // target larger, move down
800 { 12, 12, 0, 4, xpm_gt_bb
}, // target larger, move down
801 { 12, 12, 2, -2, xpm_gt_r_t
}, // target larger, move right up
802 { 12, 12, 2, 0, xpm_gt_r
}, // target larger, move right
803 { 12, 12, 2, 2, xpm_gt_r_b
}, // target larger, move right down
804 { 12, 12, 2, 4, xpm_gt_r_bb
}, // target larger, move right down
805 { 12, 12, 4, -2, xpm_gt_rr_t
}, // target larger, move right up
806 { 12, 12, 4, 0, xpm_gt_rr
}, // target larger, move right
807 { 12, 12, 4, 2, xpm_gt_rr_b
}, // target larger, move right down
808 { 12, 12, 4, 4, xpm_gt_rr_bb
}, // target larger, move right down
809 { 8, 8, -4, -4, xpm_sm_ll_tt
}, // target smaller, move left up
810 { 8, 8, -4, -2, xpm_sm_ll_t
}, // target smaller, move left up
811 { 8, 8, -4, 0, xpm_sm_ll
}, // target smaller, move left
812 { 8, 8, -4, 2, xpm_sm_ll_b
}, // target smaller, move left down
813 { 8, 8, -2, -4, xpm_sm_l_tt
}, // target smaller, move left up
814 { 8, 8, -2, -2, xpm_sm_l_t
}, // target smaller, move left up
815 { 8, 8, -2, 0, xpm_sm_l
}, // target smaller, move left
816 { 8, 8, -2, 2, xpm_sm_l_b
}, // target smaller, move left down
817 { 8, 8, 0, -4, xpm_sm_tt
}, // target smaller, move up
818 { 8, 8, 0, -2, xpm_sm_t
}, // target smaller, move up
819 { 8, 8, 0, 2, xpm_sm_b
}, // target smaller, move down
820 { 8, 8, 2, -4, xpm_sm_r_tt
}, // target smaller, move right up
821 { 8, 8, 2, -2, xpm_sm_r_t
}, // target smaller, move right up
822 { 8, 8, 2, 0, xpm_sm_r
}, // target smaller, move right
823 { 8, 8, 2, 2, xpm_sm_r_b
}, // target smaller, move right down
826 const wxImage
src_img(xpm_orig
);
827 for ( unsigned i
= 0; i
< WXSIZEOF(sizeTestData
); i
++ )
829 SizeTestData
& st
= sizeTestData
[i
];
831 actual(src_img
.Size(wxSize(st
.w
, st
.h
), wxPoint(st
.dx
, st
.dy
), 0, 0, 0)),
832 expected(st
.ref_xpm
);
834 // to check results with an image viewer uncomment this:
835 //actual.SaveFile(wxString::Format("imagetest-%02d-actual.png", i), wxBITMAP_TYPE_PNG);
836 //expected.SaveFile(wxString::Format("imagetest-%02d-exp.png", i), wxBITMAP_TYPE_PNG);
838 CPPUNIT_ASSERT_EQUAL( actual
.GetSize().x
, expected
.GetSize().x
);
839 CPPUNIT_ASSERT_EQUAL( actual
.GetSize().y
, expected
.GetSize().y
);
841 WX_ASSERT_EQUAL_MESSAGE
843 ("Resize test #%u: (%d, %d), (%d, %d)", i
, st
.w
, st
.h
, st
.dx
, st
.dy
),
849 void ImageTestCase::CompareLoadedImage()
851 wxImage
expected8("horse.xpm");
852 CPPUNIT_ASSERT( expected8
.IsOk() );
854 wxImage
expected24("horse.png");
855 CPPUNIT_ASSERT( expected24
.IsOk() );
857 for (size_t i
=0; i
<WXSIZEOF(g_testfiles
); i
++)
859 if ( !(g_testfiles
[i
].bitDepth
== 8 || g_testfiles
[i
].bitDepth
== 24)
860 || g_testfiles
[i
].type
== wxBITMAP_TYPE_JPEG
/*skip lossy JPEG*/)
865 wxImage
actual(g_testfiles
[i
].file
);
867 if ( actual
.GetSize() != expected8
.GetSize() )
873 WX_ASSERT_EQUAL_MESSAGE
875 ("Compare test '%s' for loading failed", g_testfiles
[i
].file
),
876 g_testfiles
[i
].bitDepth
== 8 ? expected8
: expected24
,
885 wxIMAGE_HAVE_ALPHA
= (1 << 0),
886 wxIMAGE_HAVE_PALETTE
= (1 << 1)
890 void CompareImage(const wxImageHandler
& handler
, const wxImage
& image
,
891 int properties
= 0, const wxImage
*compareTo
= NULL
)
893 wxBitmapType type
= handler
.GetType();
895 const bool testPalette
= (properties
& wxIMAGE_HAVE_PALETTE
) != 0;
897 This is getting messy and should probably be transformed into a table
898 with image format features before it gets hairier.
901 && ( !(type
== wxBITMAP_TYPE_BMP
902 || type
== wxBITMAP_TYPE_GIF
903 || type
== wxBITMAP_TYPE_ICO
904 || type
== wxBITMAP_TYPE_PNG
)
905 || type
== wxBITMAP_TYPE_XPM
) )
910 const bool testAlpha
= (properties
& wxIMAGE_HAVE_ALPHA
) != 0;
912 && !(type
== wxBITMAP_TYPE_PNG
|| type
== wxBITMAP_TYPE_TGA
913 || type
== wxBITMAP_TYPE_TIFF
) )
915 // don't test images with alpha if this handler doesn't support alpha
919 if (type
== wxBITMAP_TYPE_JPEG
/* skip lossy JPEG */)
924 wxMemoryOutputStream memOut
;
925 if ( !image
.SaveFile(memOut
, type
) )
927 // Unfortunately we can't know if the handler just doesn't support
928 // saving images, or if it failed to save.
932 wxMemoryInputStream
memIn(memOut
);
933 CPPUNIT_ASSERT(memIn
.IsOk());
935 wxImage
actual(memIn
);
936 CPPUNIT_ASSERT(actual
.IsOk());
938 const wxImage
*expected
= compareTo
? compareTo
: &image
;
939 CPPUNIT_ASSERT( actual
.GetSize() == expected
->GetSize() );
941 unsigned bitsPerPixel
= testPalette
? 8 : (testAlpha
? 32 : 24);
942 WX_ASSERT_EQUAL_MESSAGE
944 ("Compare test '%s (%d-bit)' for saving failed",
945 handler
.GetExtension(), bitsPerPixel
),
951 CPPUNIT_ASSERT(actual
.HasPalette()
952 == (testPalette
|| type
== wxBITMAP_TYPE_XPM
));
955 CPPUNIT_ASSERT( actual
.HasAlpha() == testAlpha
);
962 WX_ASSERT_EQUAL_MESSAGE
964 ("Compare alpha test '%s' for saving failed", handler
.GetExtension()),
970 static void SetAlpha(wxImage
*image
)
974 unsigned char *ptr
= image
->GetAlpha();
975 const int width
= image
->GetWidth();
976 const int height
= image
->GetHeight();
977 for (int y
= 0; y
< height
; ++y
)
979 for (int x
= 0; x
< width
; ++x
)
981 ptr
[y
*width
+ x
] = (x
*y
) & wxIMAGE_ALPHA_OPAQUE
;
986 void ImageTestCase::CompareSavedImage()
988 // FIXME-VC6: Pre-declare the loop variables for compatibility with
989 // pre-standard compilers such as MSVC6 that don't implement proper scope
990 // for the variables declared in the for loops.
993 wxImage
expected24("horse.png");
994 CPPUNIT_ASSERT( expected24
.IsOk() );
995 CPPUNIT_ASSERT( !expected24
.HasAlpha() );
997 wxImage expected8
= expected24
.ConvertToGreyscale();
1000 unsigned char greys
[256];
1001 for (i
= 0; i
< 256; ++i
)
1005 wxPalette
palette(256, greys
, greys
, greys
);
1006 expected8
.SetPalette(palette
);
1007 #endif // #if wxUSE_PALETTE
1009 expected8
.SetOption(wxIMAGE_OPTION_BMP_FORMAT
, wxBMP_8BPP_PALETTE
);
1011 // Create an image with alpha based on the loaded image
1012 wxImage
expected32(expected24
);
1014 SetAlpha(&expected32
);
1016 const wxList
& list
= wxImage::GetHandlers();
1017 for ( wxList::compatibility_iterator node
= list
.GetFirst();
1018 node
; node
= node
->GetNext() )
1020 wxImageHandler
*handler
= (wxImageHandler
*) node
->GetData();
1023 CompareImage(*handler
, expected8
, wxIMAGE_HAVE_PALETTE
);
1025 CompareImage(*handler
, expected24
);
1026 CompareImage(*handler
, expected32
, wxIMAGE_HAVE_ALPHA
);
1030 void ImageTestCase::SavePNG()
1032 wxImage
expected24("horse.png");
1033 CPPUNIT_ASSERT( expected24
.IsOk() );
1035 CPPUNIT_ASSERT( !expected24
.HasPalette() );
1036 #endif // #if wxUSE_PALETTE
1038 wxImage expected8
= expected24
.ConvertToGreyscale();
1041 horse.png converted to greyscale should be saved without a palette.
1043 CompareImage(*wxImage::FindHandler(wxBITMAP_TYPE_PNG
), expected8
);
1046 But if we explicitly ask for trying to save with a palette, it should work.
1048 expected8
.SetOption(wxIMAGE_OPTION_PNG_FORMAT
, wxPNG_TYPE_PALETTE
);
1050 CompareImage(*wxImage::FindHandler(wxBITMAP_TYPE_PNG
),
1051 expected8
, wxIMAGE_HAVE_PALETTE
);
1054 CPPUNIT_ASSERT( expected8
.LoadFile("horse.gif") );
1056 CPPUNIT_ASSERT( expected8
.HasPalette() );
1057 #endif // #if wxUSE_PALETTE
1059 CompareImage(*wxImage::FindHandler(wxBITMAP_TYPE_PNG
),
1060 expected8
, wxIMAGE_HAVE_PALETTE
);
1063 Add alpha to the image in such a way that there will still be a maximum
1064 of 256 unique RGBA combinations. This should result in a saved
1065 PNG image still being palettised and having alpha.
1067 expected8
.SetAlpha();
1070 const int width
= expected8
.GetWidth();
1071 const int height
= expected8
.GetHeight();
1072 for (y
= 0; y
< height
; ++y
)
1074 for (x
= 0; x
< width
; ++x
)
1076 expected8
.SetAlpha(x
, y
, expected8
.GetRed(x
, y
));
1080 CompareImage(*wxImage::FindHandler(wxBITMAP_TYPE_PNG
),
1081 expected8
, wxIMAGE_HAVE_ALPHA
|wxIMAGE_HAVE_PALETTE
);
1084 Now change the alpha of the first pixel so that we can't save palettised
1085 anymore because there will be 256+1 entries which is beyond PNGs limit
1088 expected8
.SetAlpha(0, 0, 1);
1090 CompareImage(*wxImage::FindHandler(wxBITMAP_TYPE_PNG
),
1091 expected8
, wxIMAGE_HAVE_ALPHA
);
1094 Even if we explicitly ask for saving palettised it should not be done.
1096 expected8
.SetOption(wxIMAGE_OPTION_PNG_FORMAT
, wxPNG_TYPE_PALETTE
);
1097 CompareImage(*wxImage::FindHandler(wxBITMAP_TYPE_PNG
),
1098 expected8
, wxIMAGE_HAVE_ALPHA
);
1102 static void TestTIFFImage(const wxString
& option
, int value
,
1103 const wxImage
*compareImage
= NULL
)
1108 image
= *compareImage
;
1112 (void) image
.LoadFile("horse.png");
1114 CPPUNIT_ASSERT( image
.IsOk() );
1116 wxMemoryOutputStream memOut
;
1117 image
.SetOption(option
, value
);
1119 CPPUNIT_ASSERT(image
.SaveFile(memOut
, wxBITMAP_TYPE_TIFF
));
1121 wxMemoryInputStream
memIn(memOut
);
1122 CPPUNIT_ASSERT(memIn
.IsOk());
1124 wxImage
savedImage(memIn
);
1125 CPPUNIT_ASSERT(savedImage
.IsOk());
1127 WX_ASSERT_EQUAL_MESSAGE(("While checking for option %s", option
),
1128 true, savedImage
.HasOption(option
));
1130 WX_ASSERT_EQUAL_MESSAGE(("While testing for %s", option
),
1131 value
, savedImage
.GetOptionInt(option
));
1133 WX_ASSERT_EQUAL_MESSAGE(("HasAlpha() not equal"), image
.HasAlpha(), savedImage
.HasAlpha());
1136 void ImageTestCase::SaveTIFF()
1138 TestTIFFImage(wxIMAGE_OPTION_TIFF_BITSPERSAMPLE
, 1);
1139 TestTIFFImage(wxIMAGE_OPTION_TIFF_SAMPLESPERPIXEL
, 1);
1140 TestTIFFImage(wxIMAGE_OPTION_TIFF_PHOTOMETRIC
, 0/*PHOTOMETRIC_MINISWHITE*/);
1141 TestTIFFImage(wxIMAGE_OPTION_TIFF_PHOTOMETRIC
, 1/*PHOTOMETRIC_MINISBLACK*/);
1143 wxImage
alphaImage("horse.png");
1144 CPPUNIT_ASSERT( alphaImage
.IsOk() );
1145 SetAlpha(&alphaImage
);
1148 TestTIFFImage(wxIMAGE_OPTION_TIFF_SAMPLESPERPIXEL
, 4, &alphaImage
);
1151 TestTIFFImage(wxIMAGE_OPTION_TIFF_SAMPLESPERPIXEL
, 2, &alphaImage
);
1154 alphaImage
.SetOption(wxIMAGE_OPTION_TIFF_BITSPERSAMPLE
, 1);
1155 TestTIFFImage(wxIMAGE_OPTION_TIFF_SAMPLESPERPIXEL
, 2, &alphaImage
);
1158 void ImageTestCase::SaveAnimatedGIF()
1161 wxImage
image("horse.gif");
1162 CPPUNIT_ASSERT( image
.IsOk() );
1164 wxImageArray images
;
1167 for (i
= 0; i
< 4-1; ++i
)
1169 images
.Add( images
[i
].Rotate90() );
1171 images
[i
+1].SetPalette(images
[0].GetPalette());
1174 wxMemoryOutputStream memOut
;
1175 CPPUNIT_ASSERT( wxGIFHandler().SaveAnimation(images
, &memOut
) );
1177 wxGIFHandler handler
;
1178 wxMemoryInputStream
memIn(memOut
);
1179 CPPUNIT_ASSERT(memIn
.IsOk());
1180 const int imageCount
= handler
.GetImageCount(memIn
);
1181 CPPUNIT_ASSERT_EQUAL(4, imageCount
);
1183 for (i
= 0; i
< imageCount
; ++i
)
1185 wxFileOffset pos
= memIn
.TellI();
1186 CPPUNIT_ASSERT( handler
.LoadFile(&image
, memIn
, true, i
) );
1189 WX_ASSERT_EQUAL_MESSAGE
1191 ("Compare test for GIF frame number %d failed", i
),
1196 #endif // #if wxUSE_PALETTE
1199 void ImageTestCase::ReadCorruptedTGA()
1201 static unsigned char corruptTGA
[18+1+3] =
1205 10, // RLE compressed image.
1211 1, 0, // Width is 1.
1212 1, 0, // Height is 1.
1213 24, // Bits per pixel.
1216 0xff, // Run length (repeat next pixel 127+1 times).
1217 0xff, 0xff, 0xff // One 24-bit pixel.
1220 wxMemoryInputStream
memIn(corruptTGA
, WXSIZEOF(corruptTGA
));
1221 CPPUNIT_ASSERT(memIn
.IsOk());
1224 CPPUNIT_ASSERT( !tgaImage
.LoadFile(memIn
) );
1228 Instead of repeating a pixel 127+1 times, now tell it there will
1229 follow 127+1 uncompressed pixels (while we only should have 1 in total).
1231 corruptTGA
[18] = 0x7f;
1232 CPPUNIT_ASSERT( !tgaImage
.LoadFile(memIn
) );
1235 static void TestGIFComment(const wxString
& comment
)
1237 wxImage
image("horse.gif");
1239 image
.SetOption(wxIMAGE_OPTION_GIF_COMMENT
, comment
);
1240 wxMemoryOutputStream memOut
;
1241 CPPUNIT_ASSERT(image
.SaveFile(memOut
, wxBITMAP_TYPE_GIF
));
1243 wxMemoryInputStream
memIn(memOut
);
1244 CPPUNIT_ASSERT( image
.LoadFile(memIn
) );
1246 CPPUNIT_ASSERT_EQUAL(comment
,
1247 image
.GetOption(wxIMAGE_OPTION_GIF_COMMENT
));
1250 void ImageTestCase::GIFComment()
1252 // Test reading a comment.
1253 wxImage
image("horse.gif");
1254 CPPUNIT_ASSERT_EQUAL(" Imported from GRADATION image: gray",
1255 image
.GetOption(wxIMAGE_OPTION_GIF_COMMENT
));
1258 // Test writing a comment and reading it back.
1259 TestGIFComment("Giving the GIF a gifted giraffe as a gift");
1262 // Test writing and reading a comment again but with a long comment.
1263 TestGIFComment(wxString(wxT('a'), 256)
1264 + wxString(wxT('b'), 256)
1265 + wxString(wxT('c'), 256));
1268 // Test writing comments in an animated GIF and reading them back.
1269 CPPUNIT_ASSERT( image
.LoadFile("horse.gif") );
1271 wxImageArray images
;
1273 for (i
= 0; i
< 4; ++i
)
1277 images
.Add( images
[i
-1].Rotate90() );
1278 images
[i
].SetPalette(images
[0].GetPalette());
1285 images
[i
].SetOption(wxIMAGE_OPTION_GIF_COMMENT
,
1286 wxString::Format("GIF comment for frame #%d", i
+1));
1291 wxMemoryOutputStream memOut
;
1292 CPPUNIT_ASSERT( wxGIFHandler().SaveAnimation(images
, &memOut
) );
1294 wxGIFHandler handler
;
1295 wxMemoryInputStream
memIn(memOut
);
1296 CPPUNIT_ASSERT(memIn
.IsOk());
1297 const int imageCount
= handler
.GetImageCount(memIn
);
1298 for (i
= 0; i
< imageCount
; ++i
)
1300 wxFileOffset pos
= memIn
.TellI();
1301 CPPUNIT_ASSERT( handler
.LoadFile(&image
, memIn
, true /*verbose?*/, i
) );
1303 CPPUNIT_ASSERT_EQUAL(
1304 wxString::Format("GIF comment for frame #%d", i
+1),
1305 image
.GetOption(wxIMAGE_OPTION_GIF_COMMENT
));
1310 void ImageTestCase::DibPadding()
1313 There used to be an error with calculating the DWORD aligned scan line
1314 pitch for a BMP/ICO resulting in buffer overwrites (with at least MSVC9
1315 Debug this gave a heap corruption assertion when saving the mask of
1316 an ICO). Test for it here.
1318 wxImage
image("horse.gif");
1319 CPPUNIT_ASSERT( image
.IsOk() );
1321 image
= image
.Scale(99, 99);
1323 wxMemoryOutputStream memOut
;
1324 CPPUNIT_ASSERT( image
.SaveFile(memOut
, wxBITMAP_TYPE_ICO
) );
1327 static void CompareBMPImage(const wxString
& file1
, const wxString
& file2
)
1329 wxImage
image1(file1
);
1330 CPPUNIT_ASSERT( image1
.IsOk() );
1332 wxImage
image2(file2
);
1333 CPPUNIT_ASSERT( image2
.IsOk() );
1335 CompareImage(*wxImage::FindHandler(wxBITMAP_TYPE_BMP
), image1
, 0, &image2
);
1338 void ImageTestCase::BMPFlippingAndRLECompression()
1340 CompareBMPImage("image/horse_grey.bmp", "image/horse_grey_flipped.bmp");
1342 CompareBMPImage("image/horse_rle8.bmp", "image/horse_grey.bmp");
1343 CompareBMPImage("image/horse_rle8.bmp", "image/horse_rle8_flipped.bmp");
1345 CompareBMPImage("image/horse_rle4.bmp", "image/horse_rle4_flipped.bmp");
1349 #define ASSERT_IMAGE_EQUAL_TO_FILE(image, file) \
1351 wxImage imageFromFile(file); \
1352 CPPUNIT_ASSERT_MESSAGE( "Failed to load " file, imageFromFile.IsOk() ); \
1353 CPPUNIT_ASSERT_EQUAL( imageFromFile, image ); \
1356 void ImageTestCase::ScaleCompare()
1359 CPPUNIT_ASSERT(original
.LoadFile("horse.bmp"));
1361 ASSERT_IMAGE_EQUAL_TO_FILE(original
.Scale( 50, 50, wxIMAGE_QUALITY_BICUBIC
),
1362 "image/horse_bicubic_50x50.png");
1363 ASSERT_IMAGE_EQUAL_TO_FILE(original
.Scale(100, 100, wxIMAGE_QUALITY_BICUBIC
),
1364 "image/horse_bicubic_100x100.png");
1365 ASSERT_IMAGE_EQUAL_TO_FILE(original
.Scale(150, 150, wxIMAGE_QUALITY_BICUBIC
),
1366 "image/horse_bicubic_150x150.png");
1367 ASSERT_IMAGE_EQUAL_TO_FILE(original
.Scale(300, 300, wxIMAGE_QUALITY_BICUBIC
),
1368 "image/horse_bicubic_300x300.png");
1370 ASSERT_IMAGE_EQUAL_TO_FILE(original
.Scale( 50, 50, wxIMAGE_QUALITY_BOX_AVERAGE
),
1371 "image/horse_box_average_50x50.png");
1372 ASSERT_IMAGE_EQUAL_TO_FILE(original
.Scale(100, 100, wxIMAGE_QUALITY_BOX_AVERAGE
),
1373 "image/horse_box_average_100x100.png");
1374 ASSERT_IMAGE_EQUAL_TO_FILE(original
.Scale(150, 150, wxIMAGE_QUALITY_BOX_AVERAGE
),
1375 "image/horse_box_average_150x150.png");
1376 ASSERT_IMAGE_EQUAL_TO_FILE(original
.Scale(300, 300, wxIMAGE_QUALITY_BOX_AVERAGE
),
1377 "image/horse_box_average_300x300.png");
1379 ASSERT_IMAGE_EQUAL_TO_FILE(original
.Scale( 50, 50, wxIMAGE_QUALITY_BILINEAR
),
1380 "image/horse_bilinear_50x50.png");
1381 ASSERT_IMAGE_EQUAL_TO_FILE(original
.Scale(100, 100, wxIMAGE_QUALITY_BILINEAR
),
1382 "image/horse_bilinear_100x100.png");
1383 ASSERT_IMAGE_EQUAL_TO_FILE(original
.Scale(150, 150, wxIMAGE_QUALITY_BILINEAR
),
1384 "image/horse_bilinear_150x150.png");
1385 ASSERT_IMAGE_EQUAL_TO_FILE(original
.Scale(300, 300, wxIMAGE_QUALITY_BILINEAR
),
1386 "image/horse_bilinear_300x300.png");
1389 #endif //wxUSE_IMAGE
1393 TODO: add lots of more tests to wxImage functions