1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: tests/image/image.cpp
3 // Purpose: Test wxImage
4 // Author: Francesco Montorsi
7 // Copyright: (c) 2009 Francesco Montorsi
8 // Licence: wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
11 // ----------------------------------------------------------------------------
13 // ----------------------------------------------------------------------------
26 #include "wx/anidecod.h" // wxImageArray
28 #include "wx/palette.h"
31 #include "wx/mstream.h"
32 #include "wx/zstream.h"
33 #include "wx/wfstream.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_TIF
, 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( SaveAnimatedGIF
);
75 CPPUNIT_TEST( ReadCorruptedTGA
);
76 CPPUNIT_TEST( GIFComment
);
77 CPPUNIT_TEST_SUITE_END();
79 void LoadFromSocketStream();
80 void LoadFromZipStream();
83 void CompareLoadedImage();
84 void CompareSavedImage();
85 void SaveAnimatedGIF();
86 void ReadCorruptedTGA();
89 DECLARE_NO_COPY_CLASS(ImageTestCase
)
92 CPPUNIT_TEST_SUITE_REGISTRATION( ImageTestCase
);
93 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( ImageTestCase
, "ImageTestCase" );
95 ImageTestCase::ImageTestCase()
97 wxSocketBase::Initialize();
99 // the formats we're going to test:
100 wxImage::AddHandler(new wxICOHandler
);
101 wxImage::AddHandler(new wxXPMHandler
);
102 wxImage::AddHandler(new wxPNGHandler
);
103 wxImage::AddHandler(new wxANIHandler
);
104 wxImage::AddHandler(new wxBMPHandler
);
105 wxImage::AddHandler(new wxCURHandler
);
106 wxImage::AddHandler(new wxGIFHandler
);
107 wxImage::AddHandler(new wxJPEGHandler
);
108 wxImage::AddHandler(new wxPCXHandler
);
109 wxImage::AddHandler(new wxPNMHandler
);
110 wxImage::AddHandler(new wxTGAHandler
);
111 wxImage::AddHandler(new wxTIFFHandler
);
114 ImageTestCase::~ImageTestCase()
116 wxSocketBase::Shutdown();
119 void ImageTestCase::LoadFromFile()
122 for (unsigned int i
=0; i
<WXSIZEOF(g_testfiles
); i
++)
123 CPPUNIT_ASSERT(img
.LoadFile(g_testfiles
[i
].file
));
126 void ImageTestCase::LoadFromSocketStream()
128 if (!IsNetworkAvailable()) // implemented in test.cpp
130 wxLogWarning("No network connectivity; skipping the "
131 "ImageTestCase::LoadFromSocketStream test unit.");
140 { "http://www.wxwidgets.org/logo9.jpg", wxBITMAP_TYPE_JPEG
},
141 { "http://www.wxwidgets.org/favicon.ico", wxBITMAP_TYPE_ICO
}
144 for (unsigned int i
=0; i
<WXSIZEOF(testData
); i
++)
146 wxURL
url(testData
[i
].url
);
147 WX_ASSERT_EQUAL_MESSAGE
149 ("Constructing URL \"%s\" failed.", testData
[i
].url
),
154 wxInputStream
*in_stream
= url
.GetInputStream();
157 ("Opening URL \"%s\" failed.", testData
[i
].url
),
158 in_stream
&& in_stream
->IsOk()
163 // NOTE: it's important to inform wxImage about the type of the image being
164 // loaded otherwise it will try to autodetect the format, but that
165 // requires a seekable stream!
168 ("Loading image from \"%s\" failed.", testData
[i
].url
),
169 img
.LoadFile(*in_stream
, testData
[i
].type
)
176 void ImageTestCase::LoadFromZipStream()
178 for (unsigned int i
=0; i
<WXSIZEOF(g_testfiles
); i
++)
180 switch (g_testfiles
[i
].type
)
182 case wxBITMAP_TYPE_XPM
:
183 case wxBITMAP_TYPE_GIF
:
184 case wxBITMAP_TYPE_PCX
:
185 case wxBITMAP_TYPE_TGA
:
186 case wxBITMAP_TYPE_TIF
:
187 continue; // skip testing those wxImageHandlers which cannot
188 // load data from non-seekable streams
194 // compress the test file on the fly:
195 wxMemoryOutputStream memOut
;
197 wxFileInputStream
file(g_testfiles
[i
].file
);
198 CPPUNIT_ASSERT(file
.IsOk());
200 wxZlibOutputStream
compressFilter(memOut
, 5, wxZLIB_GZIP
);
201 CPPUNIT_ASSERT(compressFilter
.IsOk());
203 file
.Read(compressFilter
);
204 CPPUNIT_ASSERT(file
.GetLastError() == wxSTREAM_EOF
);
207 // now fetch the compressed memory to wxImage, decompressing it on the fly; this
208 // allows us to test loading images from non-seekable streams other than socket streams
209 wxMemoryInputStream
memIn(memOut
);
210 CPPUNIT_ASSERT(memIn
.IsOk());
211 wxZlibInputStream
decompressFilter(memIn
, wxZLIB_GZIP
);
212 CPPUNIT_ASSERT(decompressFilter
.IsOk());
216 // NOTE: it's important to inform wxImage about the type of the image being
217 // loaded otherwise it will try to autodetect the format, but that
218 // requires a seekable stream!
219 WX_ASSERT_MESSAGE(("Could not load file type '%d' after it was zipped", g_testfiles
[i
].type
),
220 img
.LoadFile(decompressFilter
, g_testfiles
[i
].type
));
224 void ImageTestCase::SizeImage()
226 // Test the wxImage::Size() function which takes a rectangle from source and
227 // places it in a new image at a given position. This test checks, if the
228 // correct areas are chosen, and clipping is done correctly.
231 static const char * xpm_orig
[] = {
232 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
244 // the expected results for all tests:
245 static const char * xpm_l_t
[] = {
246 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
258 static const char * xpm_t
[] = {
259 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
271 static const char * xpm_r_t
[] = {
272 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
284 static const char * xpm_l
[] = {
285 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
297 static const char * xpm_r
[] = {
298 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
310 static const char * xpm_l_b
[] = {
311 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
323 static const char * xpm_b
[] = {
324 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
336 static const char * xpm_r_b
[] = {
337 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
349 static const char * xpm_sm
[] = {
350 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
360 static const char * xpm_gt
[] = {
361 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
375 static const char * xpm_gt_l_t
[] = {
376 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
390 static const char * xpm_gt_l
[] = {
391 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
405 static const char * xpm_gt_l_b
[] = {
406 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
420 static const char * xpm_gt_l_bb
[] = {
421 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
435 static const char * xpm_gt_t
[] = {
436 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
450 static const char * xpm_gt_b
[] = {
451 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
465 static const char * xpm_gt_bb
[] = {
466 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
480 static const char * xpm_gt_r_t
[] = {
481 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
495 static const char * xpm_gt_r
[] = {
496 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
510 static const char * xpm_gt_r_b
[] = {
511 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
525 static const char * xpm_gt_r_bb
[] = {
526 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
540 static const char * xpm_gt_rr_t
[] = {
541 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
555 static const char * xpm_gt_rr
[] = {
556 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
570 static const char * xpm_gt_rr_b
[] = {
571 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
585 static const char * xpm_gt_rr_bb
[] = {
586 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
600 static const char * xpm_sm_ll_tt
[] = {
601 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
611 static const char * xpm_sm_ll_t
[] = {
612 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
622 static const char * xpm_sm_ll
[] = {
623 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
633 static const char * xpm_sm_ll_b
[] = {
634 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
644 static const char * xpm_sm_l_tt
[] = {
645 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
655 static const char * xpm_sm_l_t
[] = {
656 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
666 static const char * xpm_sm_l
[] = {
667 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
677 static const char * xpm_sm_l_b
[] = {
678 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
688 static const char * xpm_sm_tt
[] = {
689 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
699 static const char * xpm_sm_t
[] = {
700 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
710 static const char * xpm_sm_b
[] = {
711 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
721 static const char * xpm_sm_r_tt
[] = {
722 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
732 static const char * xpm_sm_r_t
[] = {
733 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
743 static const char * xpm_sm_r
[] = {
744 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
754 static const char * xpm_sm_r_b
[] = {
755 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
766 // this table defines all tests
769 int w
, h
, dx
, dy
; // first parameters for Size()
770 const char **ref_xpm
; // expected result
773 { 10, 10, 0, 0, xpm_orig
}, // same size, same position
774 { 12, 12, 0, 0, xpm_gt
}, // target larger, same position
775 { 8, 8, 0, 0, xpm_sm
}, // target smaller, same position
776 { 10, 10, -2, -2, xpm_l_t
}, // same size, move left up
777 { 10, 10, -2, 0, xpm_l
}, // same size, move left
778 { 10, 10, -2, 2, xpm_l_b
}, // same size, move left down
779 { 10, 10, 0, -2, xpm_t
}, // same size, move up
780 { 10, 10, 0, 2, xpm_b
}, // same size, move down
781 { 10, 10, 2, -2, xpm_r_t
}, // same size, move right up
782 { 10, 10, 2, 0, xpm_r
}, // same size, move right
783 { 10, 10, 2, 2, xpm_r_b
}, // same size, move right down
784 { 12, 12, -2, -2, xpm_gt_l_t
}, // target larger, move left up
785 { 12, 12, -2, 0, xpm_gt_l
}, // target larger, move left
786 { 12, 12, -2, 2, xpm_gt_l_b
}, // target larger, move left down
787 { 12, 12, -2, 4, xpm_gt_l_bb
}, // target larger, move left down
788 { 12, 12, 0, -2, xpm_gt_t
}, // target larger, move up
789 { 12, 12, 0, 2, xpm_gt_b
}, // target larger, move down
790 { 12, 12, 0, 4, xpm_gt_bb
}, // target larger, move down
791 { 12, 12, 2, -2, xpm_gt_r_t
}, // target larger, move right up
792 { 12, 12, 2, 0, xpm_gt_r
}, // target larger, move right
793 { 12, 12, 2, 2, xpm_gt_r_b
}, // target larger, move right down
794 { 12, 12, 2, 4, xpm_gt_r_bb
}, // target larger, move right down
795 { 12, 12, 4, -2, xpm_gt_rr_t
}, // target larger, move right up
796 { 12, 12, 4, 0, xpm_gt_rr
}, // target larger, move right
797 { 12, 12, 4, 2, xpm_gt_rr_b
}, // target larger, move right down
798 { 12, 12, 4, 4, xpm_gt_rr_bb
}, // target larger, move right down
799 { 8, 8, -4, -4, xpm_sm_ll_tt
}, // target smaller, move left up
800 { 8, 8, -4, -2, xpm_sm_ll_t
}, // target smaller, move left up
801 { 8, 8, -4, 0, xpm_sm_ll
}, // target smaller, move left
802 { 8, 8, -4, 2, xpm_sm_ll_b
}, // target smaller, move left down
803 { 8, 8, -2, -4, xpm_sm_l_tt
}, // target smaller, move left up
804 { 8, 8, -2, -2, xpm_sm_l_t
}, // target smaller, move left up
805 { 8, 8, -2, 0, xpm_sm_l
}, // target smaller, move left
806 { 8, 8, -2, 2, xpm_sm_l_b
}, // target smaller, move left down
807 { 8, 8, 0, -4, xpm_sm_tt
}, // target smaller, move up
808 { 8, 8, 0, -2, xpm_sm_t
}, // target smaller, move up
809 { 8, 8, 0, 2, xpm_sm_b
}, // target smaller, move down
810 { 8, 8, 2, -4, xpm_sm_r_tt
}, // target smaller, move right up
811 { 8, 8, 2, -2, xpm_sm_r_t
}, // target smaller, move right up
812 { 8, 8, 2, 0, xpm_sm_r
}, // target smaller, move right
813 { 8, 8, 2, 2, xpm_sm_r_b
}, // target smaller, move right down
816 const wxImage
src_img(xpm_orig
);
817 for ( unsigned i
= 0; i
< WXSIZEOF(sizeTestData
); i
++ )
819 SizeTestData
& st
= sizeTestData
[i
];
821 actual(src_img
.Size(wxSize(st
.w
, st
.h
), wxPoint(st
.dx
, st
.dy
), 0, 0, 0)),
822 expected(st
.ref_xpm
);
824 // to check results with an image viewer uncomment this:
825 //actual.SaveFile(wxString::Format("imagetest-%02d-actual.png", i), wxBITMAP_TYPE_PNG);
826 //expected.SaveFile(wxString::Format("imagetest-%02d-exp.png", i), wxBITMAP_TYPE_PNG);
828 CPPUNIT_ASSERT_EQUAL( actual
.GetSize().x
, expected
.GetSize().x
);
829 CPPUNIT_ASSERT_EQUAL( actual
.GetSize().y
, expected
.GetSize().y
);
831 const unsigned data_len
= 3 * expected
.GetHeight() * expected
.GetWidth();
835 ("Resize test #%u: (%d, %d), (%d, %d)", i
, st
.w
, st
.h
, st
.dx
, st
.dy
),
836 memcmp(actual
.GetData(), expected
.GetData(), data_len
) == 0
841 void ImageTestCase::CompareLoadedImage()
843 wxImage
expected8("horse.xpm");
844 CPPUNIT_ASSERT( expected8
.IsOk() );
846 wxImage
expected24("horse.png");
847 CPPUNIT_ASSERT( expected24
.IsOk() );
849 const size_t dataLen
= expected8
.GetWidth() * expected8
.GetHeight() * 3;
851 for (size_t i
=0; i
<WXSIZEOF(g_testfiles
); i
++)
853 if ( !(g_testfiles
[i
].bitDepth
== 8 || g_testfiles
[i
].bitDepth
== 24)
854 || g_testfiles
[i
].type
== wxBITMAP_TYPE_JPEG
/*skip lossy JPEG*/)
859 wxImage
actual(g_testfiles
[i
].file
);
861 if ( actual
.GetSize() != expected8
.GetSize() )
869 ("Compare test '%s' for loading failed", g_testfiles
[i
].file
),
871 memcmp(actual
.GetData(),
872 (g_testfiles
[i
].bitDepth
== 8)
873 ? expected8
.GetData()
874 : expected24
.GetData(),
883 wxIMAGE_HAVE_ALPHA
= (1 << 0),
884 wxIMAGE_HAVE_PALETTE
= (1 << 1)
888 void CompareImage(const wxImageHandler
& handler
, const wxImage
& image
,
889 int properties
= 0, const wxImage
*compareTo
= NULL
)
891 wxBitmapType type
= handler
.GetType();
893 const bool testPalette
= (properties
& wxIMAGE_HAVE_PALETTE
) != 0;
895 This is getting messy and should probably be transformed into a table
896 with image format features before it gets hairier.
899 && ( !(type
== wxBITMAP_TYPE_BMP
900 || type
== wxBITMAP_TYPE_GIF
901 || type
== wxBITMAP_TYPE_PNG
)
902 || type
== wxBITMAP_TYPE_XPM
) )
907 const bool testAlpha
= (properties
& wxIMAGE_HAVE_ALPHA
) != 0;
909 && !(type
== wxBITMAP_TYPE_PNG
|| type
== wxBITMAP_TYPE_TGA
) )
911 // don't test images with alpha if this handler doesn't support alpha
915 if (type
== wxBITMAP_TYPE_JPEG
/* skip lossy JPEG */
916 || type
== wxBITMAP_TYPE_TIF
)
919 TIFF is skipped because the memory stream can't be loaded. Libtiff
920 looks for a TIFF directory at offset 120008 while the memory
921 stream size is only 120008 bytes (when saving as a file
922 the file size is 120280 bytes).
927 wxMemoryOutputStream memOut
;
928 if ( !image
.SaveFile(memOut
, type
) )
930 // Unfortunately we can't know if the handler just doesn't support
931 // saving images, or if it failed to save.
935 wxMemoryInputStream
memIn(memOut
);
936 CPPUNIT_ASSERT(memIn
.IsOk());
938 wxImage
actual(memIn
);
939 CPPUNIT_ASSERT(actual
.IsOk());
941 const wxImage
*expected
= compareTo
? compareTo
: &image
;
942 CPPUNIT_ASSERT( actual
.GetSize() == expected
->GetSize() );
944 unsigned bitsPerPixel
= testPalette
? 8 : (testAlpha
? 32 : 24);
947 ("Compare test '%s (%d-bit)' for saving failed",
948 handler
.GetExtension(), bitsPerPixel
),
950 memcmp(actual
.GetData(), expected
->GetData(),
951 expected
->GetWidth() * expected
->GetHeight() * 3) == 0
955 CPPUNIT_ASSERT(actual
.HasPalette()
956 == (testPalette
|| type
== wxBITMAP_TYPE_XPM
));
959 CPPUNIT_ASSERT( actual
.HasAlpha() == testAlpha
);
968 ("Compare alpha test '%s' for saving failed", handler
.GetExtension()),
970 memcmp(actual
.GetAlpha(), expected
->GetAlpha(),
971 expected
->GetWidth() * expected
->GetHeight()) == 0
975 void ImageTestCase::CompareSavedImage()
977 // FIXME-VC6: Pre-declare the loop variables for compatibility with
978 // pre-standard compilers such as MSVC6 that don't implement proper scope
979 // for the variables declared in the for loops.
982 wxImage
expected24("horse.png");
983 CPPUNIT_ASSERT( expected24
.IsOk() );
984 CPPUNIT_ASSERT( !expected24
.HasAlpha() );
986 wxImage expected8
= expected24
.ConvertToGreyscale();
989 unsigned char greys
[256];
990 for (i
= 0; i
< 256; ++i
)
994 wxPalette
palette(256, greys
, greys
, greys
);
995 expected8
.SetPalette(palette
);
996 #endif // #if wxUSE_PALETTE
998 expected8
.SetOption(wxIMAGE_OPTION_BMP_FORMAT
, wxBMP_8BPP_PALETTE
);
1000 // Create an image with alpha based on the loaded image
1001 wxImage
expected32(expected24
);
1002 expected32
.SetAlpha();
1004 int width
= expected32
.GetWidth();
1005 int height
= expected32
.GetHeight();
1006 for (y
= 0; y
< height
; ++y
)
1008 for (x
= 0; x
< width
; ++x
)
1010 expected32
.SetAlpha(x
, y
, (x
*y
) & wxIMAGE_ALPHA_OPAQUE
);
1014 const wxList
& list
= wxImage::GetHandlers();
1015 for ( wxList::compatibility_iterator node
= list
.GetFirst();
1016 node
; node
= node
->GetNext() )
1018 wxImageHandler
*handler
= (wxImageHandler
*) node
->GetData();
1021 CompareImage(*handler
, expected8
, wxIMAGE_HAVE_PALETTE
);
1023 CompareImage(*handler
, expected24
);
1024 CompareImage(*handler
, expected32
, wxIMAGE_HAVE_ALPHA
);
1028 expected8
.LoadFile("horse.gif");
1029 CPPUNIT_ASSERT( expected8
.IsOk() );
1031 CPPUNIT_ASSERT( expected8
.HasPalette() );
1032 #endif // #if wxUSE_PALETTE
1034 expected8
.SetAlpha();
1036 width
= expected8
.GetWidth();
1037 height
= expected8
.GetHeight();
1038 for (y
= 0; y
< height
; ++y
)
1040 for (x
= 0; x
< width
; ++x
)
1042 expected8
.SetAlpha(x
, y
, (x
*y
) & wxIMAGE_ALPHA_OPAQUE
);
1047 Explicitly make known we want a palettised PNG. If we don't then this
1048 particular image gets saved as a true colour image because there's an
1049 alpha channel present and the PNG saver prefers to keep the alpha over
1050 saving as a palettised image that has alpha converted to a mask.
1052 expected8
.SetOption(wxIMAGE_OPTION_PNG_FORMAT
, wxPNG_TYPE_PALETTE
);
1055 The image contains 256 indexed colours and needs another palette entry
1056 for storing the transparency index. This results in wanting 257 palette
1057 entries but that amount is not supported by PNG, as such this image
1058 should not contain a palette (but still have alpha) and be stored as a
1059 true colour image instead.
1061 CompareImage(*wxImage::FindHandler(wxBITMAP_TYPE_PNG
),
1062 expected8
, wxIMAGE_HAVE_ALPHA
);
1066 Now do the same test again but remove one (random) palette entry. This
1067 should result in saving the PNG with a palette.
1069 unsigned char red
[256], green
[256], blue
[256];
1070 const wxPalette
& pal
= expected8
.GetPalette();
1071 const int paletteCount
= pal
.GetColoursCount();
1072 for (i
= 0; i
< paletteCount
; ++i
)
1074 expected8
.GetPalette().GetRGB(i
, &red
[i
], &green
[i
], &blue
[i
]);
1076 wxPalette
newPal(paletteCount
- 1, red
, green
, blue
);
1078 red
[paletteCount
-1], green
[paletteCount
-1], blue
[paletteCount
-1],
1079 red
[paletteCount
-2], green
[paletteCount
-2], blue
[paletteCount
-2]);
1081 expected8
.SetPalette(newPal
);
1083 wxImage ref8
= expected8
;
1086 Convert the alpha channel to a mask like the PNG saver does. Also convert
1087 the colour used for transparency from 1,0,0 to 2,0,0. The latter gets
1088 done by the PNG loader in search of an unused colour to use for
1089 transparency (this should be fixed).
1091 ref8
.ConvertAlphaToMask();
1092 ref8
.Replace(1, 0, 0, 2, 0, 0);
1094 CompareImage(*wxImage::FindHandler(wxBITMAP_TYPE_PNG
),
1095 expected8
, wxIMAGE_HAVE_PALETTE
, &ref8
);
1099 void ImageTestCase::SaveAnimatedGIF()
1102 wxImage
image("horse.gif");
1103 CPPUNIT_ASSERT( image
.IsOk() );
1105 wxImageArray images
;
1108 for (i
= 0; i
< 4-1; ++i
)
1110 images
.Add( images
[i
].Rotate90() );
1112 images
[i
+1].SetPalette(images
[0].GetPalette());
1115 wxMemoryOutputStream memOut
;
1116 CPPUNIT_ASSERT( wxGIFHandler().SaveAnimation(images
, &memOut
) );
1118 wxGIFHandler handler
;
1119 wxMemoryInputStream
memIn(memOut
);
1120 CPPUNIT_ASSERT(memIn
.IsOk());
1121 const int imageCount
= handler
.GetImageCount(memIn
);
1122 CPPUNIT_ASSERT_EQUAL(4, imageCount
);
1124 for (i
= 0; i
< imageCount
; ++i
)
1126 wxFileOffset pos
= memIn
.TellI();
1127 CPPUNIT_ASSERT( handler
.LoadFile(&image
, memIn
, true, i
) );
1132 ("Compare test for GIF frame number %d failed", i
),
1133 memcmp(image
.GetData(), images
[i
].GetData(),
1134 images
[i
].GetWidth() * images
[i
].GetHeight() * 3) == 0
1137 #endif // #if wxUSE_PALETTE
1140 void ImageTestCase::ReadCorruptedTGA()
1142 static unsigned char corruptTGA
[18+1+3] =
1146 10, // RLE compressed image.
1152 1, 0, // Width is 1.
1153 1, 0, // Height is 1.
1154 24, // Bits per pixel.
1157 0xff, // Run length (repeat next pixel 127+1 times).
1158 0xff, 0xff, 0xff // One 24-bit pixel.
1161 wxMemoryInputStream
memIn(corruptTGA
, WXSIZEOF(corruptTGA
));
1162 CPPUNIT_ASSERT(memIn
.IsOk());
1165 CPPUNIT_ASSERT( !tgaImage
.LoadFile(memIn
) );
1169 Instead of repeating a pixel 127+1 times, now tell it there will
1170 follow 127+1 uncompressed pixels (while we only should have 1 in total).
1172 corruptTGA
[18] = 0x7f;
1173 CPPUNIT_ASSERT( !tgaImage
.LoadFile(memIn
) );
1176 static void TestGIFComment(const wxString
& comment
)
1178 wxImage
image("horse.gif");
1180 image
.SetOption(wxIMAGE_OPTION_GIF_COMMENT
, comment
);
1181 wxMemoryOutputStream memOut
;
1182 CPPUNIT_ASSERT(image
.SaveFile(memOut
, wxBITMAP_TYPE_GIF
));
1184 wxMemoryInputStream
memIn(memOut
);
1185 CPPUNIT_ASSERT( image
.LoadFile(memIn
) );
1187 CPPUNIT_ASSERT_EQUAL(comment
,
1188 image
.GetOption(wxIMAGE_OPTION_GIF_COMMENT
));
1191 void ImageTestCase::GIFComment()
1193 // Test reading a comment.
1194 wxImage
image("horse.gif");
1195 CPPUNIT_ASSERT_EQUAL(" Imported from GRADATION image: gray",
1196 image
.GetOption(wxIMAGE_OPTION_GIF_COMMENT
));
1199 // Test writing a comment and reading it back.
1200 TestGIFComment("Giving the GIF a gifted giraffe as a gift");
1203 // Test writing and reading a comment again but with a long comment.
1204 TestGIFComment(wxString(wxT('a'), 256)
1205 + wxString(wxT('b'), 256)
1206 + wxString(wxT('c'), 256));
1209 // Test writing comments in an animated GIF and reading them back.
1210 CPPUNIT_ASSERT( image
.LoadFile("horse.gif") );
1212 wxImageArray images
;
1214 for (i
= 0; i
< 4; ++i
)
1218 images
.Add( images
[i
-1].Rotate90() );
1219 images
[i
].SetPalette(images
[0].GetPalette());
1226 images
[i
].SetOption(wxIMAGE_OPTION_GIF_COMMENT
,
1227 wxString::Format("GIF comment for frame #%d", i
+1));
1232 wxMemoryOutputStream memOut
;
1233 CPPUNIT_ASSERT( wxGIFHandler().SaveAnimation(images
, &memOut
) );
1235 wxGIFHandler handler
;
1236 wxMemoryInputStream
memIn(memOut
);
1237 CPPUNIT_ASSERT(memIn
.IsOk());
1238 const int imageCount
= handler
.GetImageCount(memIn
);
1239 for (i
= 0; i
< imageCount
; ++i
)
1241 wxFileOffset pos
= memIn
.TellI();
1242 CPPUNIT_ASSERT( handler
.LoadFile(&image
, memIn
, true /*verbose?*/, i
) );
1244 CPPUNIT_ASSERT_EQUAL(
1245 wxString::Format("GIF comment for frame #%d", i
+1),
1246 image
.GetOption(wxIMAGE_OPTION_GIF_COMMENT
));
1251 #endif //wxUSE_IMAGE
1255 TODO: add lots of more tests to wxImage functions