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_SUITE_END();
78 void LoadFromSocketStream();
79 void LoadFromZipStream();
82 void CompareLoadedImage();
83 void CompareSavedImage();
84 void SaveAnimatedGIF();
85 void ReadCorruptedTGA();
87 DECLARE_NO_COPY_CLASS(ImageTestCase
)
90 CPPUNIT_TEST_SUITE_REGISTRATION( ImageTestCase
);
91 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( ImageTestCase
, "ImageTestCase" );
93 ImageTestCase::ImageTestCase()
95 wxSocketBase::Initialize();
97 // the formats we're going to test:
98 wxImage::AddHandler(new wxICOHandler
);
99 wxImage::AddHandler(new wxXPMHandler
);
100 wxImage::AddHandler(new wxPNGHandler
);
101 wxImage::AddHandler(new wxANIHandler
);
102 wxImage::AddHandler(new wxBMPHandler
);
103 wxImage::AddHandler(new wxCURHandler
);
104 wxImage::AddHandler(new wxGIFHandler
);
105 wxImage::AddHandler(new wxJPEGHandler
);
106 wxImage::AddHandler(new wxPCXHandler
);
107 wxImage::AddHandler(new wxPNMHandler
);
108 wxImage::AddHandler(new wxTGAHandler
);
109 wxImage::AddHandler(new wxTIFFHandler
);
112 ImageTestCase::~ImageTestCase()
114 wxSocketBase::Shutdown();
117 void ImageTestCase::LoadFromFile()
120 for (unsigned int i
=0; i
<WXSIZEOF(g_testfiles
); i
++)
121 CPPUNIT_ASSERT(img
.LoadFile(g_testfiles
[i
].file
));
124 void ImageTestCase::LoadFromSocketStream()
126 if (!IsNetworkAvailable()) // implemented in test.cpp
128 wxLogWarning("No network connectivity; skipping the "
129 "ImageTestCase::LoadFromSocketStream test unit.");
138 { "http://www.wxwidgets.org/logo9.jpg", wxBITMAP_TYPE_JPEG
},
139 { "http://www.wxwidgets.org/favicon.ico", wxBITMAP_TYPE_ICO
}
142 for (unsigned int i
=0; i
<WXSIZEOF(testData
); i
++)
144 wxURL
url(testData
[i
].url
);
145 WX_ASSERT_EQUAL_MESSAGE
147 ("Constructing URL \"%s\" failed.", testData
[i
].url
),
152 wxInputStream
*in_stream
= url
.GetInputStream();
155 ("Opening URL \"%s\" failed.", testData
[i
].url
),
156 in_stream
&& in_stream
->IsOk()
161 // NOTE: it's important to inform wxImage about the type of the image being
162 // loaded otherwise it will try to autodetect the format, but that
163 // requires a seekable stream!
166 ("Loading image from \"%s\" failed.", testData
[i
].url
),
167 img
.LoadFile(*in_stream
, testData
[i
].type
)
174 void ImageTestCase::LoadFromZipStream()
176 for (unsigned int i
=0; i
<WXSIZEOF(g_testfiles
); i
++)
178 switch (g_testfiles
[i
].type
)
180 case wxBITMAP_TYPE_XPM
:
181 case wxBITMAP_TYPE_GIF
:
182 case wxBITMAP_TYPE_PCX
:
183 case wxBITMAP_TYPE_TGA
:
184 case wxBITMAP_TYPE_TIF
:
185 continue; // skip testing those wxImageHandlers which cannot
186 // load data from non-seekable streams
192 // compress the test file on the fly:
193 wxMemoryOutputStream memOut
;
195 wxFileInputStream
file(g_testfiles
[i
].file
);
196 CPPUNIT_ASSERT(file
.IsOk());
198 wxZlibOutputStream
compressFilter(memOut
, 5, wxZLIB_GZIP
);
199 CPPUNIT_ASSERT(compressFilter
.IsOk());
201 file
.Read(compressFilter
);
202 CPPUNIT_ASSERT(file
.GetLastError() == wxSTREAM_EOF
);
205 // now fetch the compressed memory to wxImage, decompressing it on the fly; this
206 // allows us to test loading images from non-seekable streams other than socket streams
207 wxMemoryInputStream
memIn(memOut
);
208 CPPUNIT_ASSERT(memIn
.IsOk());
209 wxZlibInputStream
decompressFilter(memIn
, wxZLIB_GZIP
);
210 CPPUNIT_ASSERT(decompressFilter
.IsOk());
214 // NOTE: it's important to inform wxImage about the type of the image being
215 // loaded otherwise it will try to autodetect the format, but that
216 // requires a seekable stream!
217 WX_ASSERT_MESSAGE(("Could not load file type '%d' after it was zipped", g_testfiles
[i
].type
),
218 img
.LoadFile(decompressFilter
, g_testfiles
[i
].type
));
222 void ImageTestCase::SizeImage()
224 // Test the wxImage::Size() function which takes a rectangle from source and
225 // places it in a new image at a given position. This test checks, if the
226 // correct areas are chosen, and clipping is done correctly.
229 static const char * xpm_orig
[] = {
230 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
242 // the expected results for all tests:
243 static const char * xpm_l_t
[] = {
244 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
256 static const char * xpm_t
[] = {
257 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
269 static const char * xpm_r_t
[] = {
270 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
282 static const char * xpm_l
[] = {
283 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
295 static const char * xpm_r
[] = {
296 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
308 static const char * xpm_l_b
[] = {
309 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
321 static const char * xpm_b
[] = {
322 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
334 static const char * xpm_r_b
[] = {
335 "10 10 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
347 static const char * xpm_sm
[] = {
348 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
358 static const char * xpm_gt
[] = {
359 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
373 static const char * xpm_gt_l_t
[] = {
374 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
388 static const char * xpm_gt_l
[] = {
389 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
403 static const char * xpm_gt_l_b
[] = {
404 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
418 static const char * xpm_gt_l_bb
[] = {
419 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
433 static const char * xpm_gt_t
[] = {
434 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
448 static const char * xpm_gt_b
[] = {
449 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
463 static const char * xpm_gt_bb
[] = {
464 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
478 static const char * xpm_gt_r_t
[] = {
479 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
493 static const char * xpm_gt_r
[] = {
494 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
508 static const char * xpm_gt_r_b
[] = {
509 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
523 static const char * xpm_gt_r_bb
[] = {
524 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
538 static const char * xpm_gt_rr_t
[] = {
539 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
553 static const char * xpm_gt_rr
[] = {
554 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
568 static const char * xpm_gt_rr_b
[] = {
569 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
583 static const char * xpm_gt_rr_bb
[] = {
584 "12 12 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
598 static const char * xpm_sm_ll_tt
[] = {
599 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
609 static const char * xpm_sm_ll_t
[] = {
610 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
620 static const char * xpm_sm_ll
[] = {
621 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
631 static const char * xpm_sm_ll_b
[] = {
632 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
642 static const char * xpm_sm_l_tt
[] = {
643 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
653 static const char * xpm_sm_l_t
[] = {
654 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
664 static const char * xpm_sm_l
[] = {
665 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
675 static const char * xpm_sm_l_b
[] = {
676 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
686 static const char * xpm_sm_tt
[] = {
687 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
697 static const char * xpm_sm_t
[] = {
698 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
708 static const char * xpm_sm_b
[] = {
709 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
719 static const char * xpm_sm_r_tt
[] = {
720 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
730 static const char * xpm_sm_r_t
[] = {
731 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
741 static const char * xpm_sm_r
[] = {
742 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
752 static const char * xpm_sm_r_b
[] = {
753 "8 8 5 1", "B c Black", " c #00ff00", ". c #0000ff", "+ c #7f7f7f", "@ c #FF0000",
764 // this table defines all tests
767 int w
, h
, dx
, dy
; // first parameters for Size()
768 const char **ref_xpm
; // expected result
771 { 10, 10, 0, 0, xpm_orig
}, // same size, same position
772 { 12, 12, 0, 0, xpm_gt
}, // target larger, same position
773 { 8, 8, 0, 0, xpm_sm
}, // target smaller, same position
774 { 10, 10, -2, -2, xpm_l_t
}, // same size, move left up
775 { 10, 10, -2, 0, xpm_l
}, // same size, move left
776 { 10, 10, -2, 2, xpm_l_b
}, // same size, move left down
777 { 10, 10, 0, -2, xpm_t
}, // same size, move up
778 { 10, 10, 0, 2, xpm_b
}, // same size, move down
779 { 10, 10, 2, -2, xpm_r_t
}, // same size, move right up
780 { 10, 10, 2, 0, xpm_r
}, // same size, move right
781 { 10, 10, 2, 2, xpm_r_b
}, // same size, move right down
782 { 12, 12, -2, -2, xpm_gt_l_t
}, // target larger, move left up
783 { 12, 12, -2, 0, xpm_gt_l
}, // target larger, move left
784 { 12, 12, -2, 2, xpm_gt_l_b
}, // target larger, move left down
785 { 12, 12, -2, 4, xpm_gt_l_bb
}, // target larger, move left down
786 { 12, 12, 0, -2, xpm_gt_t
}, // target larger, move up
787 { 12, 12, 0, 2, xpm_gt_b
}, // target larger, move down
788 { 12, 12, 0, 4, xpm_gt_bb
}, // target larger, move down
789 { 12, 12, 2, -2, xpm_gt_r_t
}, // target larger, move right up
790 { 12, 12, 2, 0, xpm_gt_r
}, // target larger, move right
791 { 12, 12, 2, 2, xpm_gt_r_b
}, // target larger, move right down
792 { 12, 12, 2, 4, xpm_gt_r_bb
}, // target larger, move right down
793 { 12, 12, 4, -2, xpm_gt_rr_t
}, // target larger, move right up
794 { 12, 12, 4, 0, xpm_gt_rr
}, // target larger, move right
795 { 12, 12, 4, 2, xpm_gt_rr_b
}, // target larger, move right down
796 { 12, 12, 4, 4, xpm_gt_rr_bb
}, // target larger, move right down
797 { 8, 8, -4, -4, xpm_sm_ll_tt
}, // target smaller, move left up
798 { 8, 8, -4, -2, xpm_sm_ll_t
}, // target smaller, move left up
799 { 8, 8, -4, 0, xpm_sm_ll
}, // target smaller, move left
800 { 8, 8, -4, 2, xpm_sm_ll_b
}, // target smaller, move left down
801 { 8, 8, -2, -4, xpm_sm_l_tt
}, // target smaller, move left up
802 { 8, 8, -2, -2, xpm_sm_l_t
}, // target smaller, move left up
803 { 8, 8, -2, 0, xpm_sm_l
}, // target smaller, move left
804 { 8, 8, -2, 2, xpm_sm_l_b
}, // target smaller, move left down
805 { 8, 8, 0, -4, xpm_sm_tt
}, // target smaller, move up
806 { 8, 8, 0, -2, xpm_sm_t
}, // target smaller, move up
807 { 8, 8, 0, 2, xpm_sm_b
}, // target smaller, move down
808 { 8, 8, 2, -4, xpm_sm_r_tt
}, // target smaller, move right up
809 { 8, 8, 2, -2, xpm_sm_r_t
}, // target smaller, move right up
810 { 8, 8, 2, 0, xpm_sm_r
}, // target smaller, move right
811 { 8, 8, 2, 2, xpm_sm_r_b
}, // target smaller, move right down
814 const wxImage
src_img(xpm_orig
);
815 for ( unsigned i
= 0; i
< WXSIZEOF(sizeTestData
); i
++ )
817 SizeTestData
& st
= sizeTestData
[i
];
819 actual(src_img
.Size(wxSize(st
.w
, st
.h
), wxPoint(st
.dx
, st
.dy
), 0, 0, 0)),
820 expected(st
.ref_xpm
);
822 // to check results with an image viewer uncomment this:
823 //actual.SaveFile(wxString::Format("imagetest-%02d-actual.png", i), wxBITMAP_TYPE_PNG);
824 //expected.SaveFile(wxString::Format("imagetest-%02d-exp.png", i), wxBITMAP_TYPE_PNG);
826 CPPUNIT_ASSERT_EQUAL( actual
.GetSize().x
, expected
.GetSize().x
);
827 CPPUNIT_ASSERT_EQUAL( actual
.GetSize().y
, expected
.GetSize().y
);
829 const unsigned data_len
= 3 * expected
.GetHeight() * expected
.GetWidth();
833 ("Resize test #%u: (%d, %d), (%d, %d)", i
, st
.w
, st
.h
, st
.dx
, st
.dy
),
834 memcmp(actual
.GetData(), expected
.GetData(), data_len
) == 0
839 void ImageTestCase::CompareLoadedImage()
841 wxImage
expected8("horse.xpm");
842 CPPUNIT_ASSERT( expected8
.IsOk() );
844 wxImage
expected24("horse.png");
845 CPPUNIT_ASSERT( expected24
.IsOk() );
847 const size_t dataLen
= expected8
.GetWidth() * expected8
.GetHeight() * 3;
849 for (size_t i
=0; i
<WXSIZEOF(g_testfiles
); i
++)
851 if ( !(g_testfiles
[i
].bitDepth
== 8 || g_testfiles
[i
].bitDepth
== 24)
852 || g_testfiles
[i
].type
== wxBITMAP_TYPE_JPEG
/*skip lossy JPEG*/)
857 wxImage
actual(g_testfiles
[i
].file
);
859 if ( actual
.GetSize() != expected8
.GetSize() )
867 ("Compare test '%s' for loading failed", g_testfiles
[i
].file
),
869 memcmp(actual
.GetData(),
870 (g_testfiles
[i
].bitDepth
== 8)
871 ? expected8
.GetData()
872 : expected24
.GetData(),
881 wxIMAGE_HAVE_ALPHA
= (1 << 0),
882 wxIMAGE_HAVE_PALETTE
= (1 << 1)
886 void CompareImage(const wxImageHandler
& handler
, const wxImage
& image
,
887 int properties
= 0, const wxImage
*compareTo
= NULL
)
889 wxBitmapType type
= handler
.GetType();
891 const bool testPalette
= (properties
& wxIMAGE_HAVE_PALETTE
) != 0;
893 This is getting messy and should probably be transformed into a table
894 with image format features before it gets hairier.
897 && ( !(type
== wxBITMAP_TYPE_BMP
898 || type
== wxBITMAP_TYPE_GIF
899 || type
== wxBITMAP_TYPE_PNG
)
900 || type
== wxBITMAP_TYPE_XPM
) )
905 const bool testAlpha
= (properties
& wxIMAGE_HAVE_ALPHA
) != 0;
907 && !(type
== wxBITMAP_TYPE_PNG
|| type
== wxBITMAP_TYPE_TGA
) )
909 // don't test images with alpha if this handler doesn't support alpha
913 if (type
== wxBITMAP_TYPE_JPEG
/* skip lossy JPEG */
914 || type
== wxBITMAP_TYPE_TIF
)
917 TIFF is skipped because the memory stream can't be loaded. Libtiff
918 looks for a TIFF directory at offset 120008 while the memory
919 stream size is only 120008 bytes (when saving as a file
920 the file size is 120280 bytes).
925 wxMemoryOutputStream memOut
;
926 if ( !image
.SaveFile(memOut
, type
) )
928 // Unfortunately we can't know if the handler just doesn't support
929 // saving images, or if it failed to save.
933 wxMemoryInputStream
memIn(memOut
);
934 CPPUNIT_ASSERT(memIn
.IsOk());
936 wxImage
actual(memIn
);
937 CPPUNIT_ASSERT(actual
.IsOk());
939 const wxImage
*expected
= compareTo
? compareTo
: &image
;
940 CPPUNIT_ASSERT( actual
.GetSize() == expected
->GetSize() );
942 unsigned bitsPerPixel
= testPalette
? 8 : (testAlpha
? 32 : 24);
945 ("Compare test '%s (%d-bit)' for saving failed",
946 handler
.GetExtension(), bitsPerPixel
),
948 memcmp(actual
.GetData(), expected
->GetData(),
949 expected
->GetWidth() * expected
->GetHeight() * 3) == 0
953 CPPUNIT_ASSERT(actual
.HasPalette()
954 == (testPalette
|| type
== wxBITMAP_TYPE_XPM
));
957 CPPUNIT_ASSERT( actual
.HasAlpha() == testAlpha
);
966 ("Compare alpha test '%s' for saving failed", handler
.GetExtension()),
968 memcmp(actual
.GetAlpha(), expected
->GetAlpha(),
969 expected
->GetWidth() * expected
->GetHeight()) == 0
973 void ImageTestCase::CompareSavedImage()
975 // FIXME-VC6: Pre-declare the loop variables for compatibility with
976 // pre-standard compilers such as MSVC6 that don't implement proper scope
977 // for the variables declared in the for loops.
980 wxImage
expected24("horse.png");
981 CPPUNIT_ASSERT( expected24
.IsOk() );
982 CPPUNIT_ASSERT( !expected24
.HasAlpha() );
984 wxImage expected8
= expected24
.ConvertToGreyscale();
987 unsigned char greys
[256];
988 for (i
= 0; i
< 256; ++i
)
992 wxPalette
palette(256, greys
, greys
, greys
);
993 expected8
.SetPalette(palette
);
994 #endif // #if wxUSE_PALETTE
996 expected8
.SetOption(wxIMAGE_OPTION_BMP_FORMAT
, wxBMP_8BPP_PALETTE
);
998 // Create an image with alpha based on the loaded image
999 wxImage
expected32(expected24
);
1000 expected32
.SetAlpha();
1002 int width
= expected32
.GetWidth();
1003 int height
= expected32
.GetHeight();
1004 for (y
= 0; y
< height
; ++y
)
1006 for (x
= 0; x
< width
; ++x
)
1008 expected32
.SetAlpha(x
, y
, (x
*y
) & wxIMAGE_ALPHA_OPAQUE
);
1012 const wxList
& list
= wxImage::GetHandlers();
1013 for ( wxList::compatibility_iterator node
= list
.GetFirst();
1014 node
; node
= node
->GetNext() )
1016 wxImageHandler
*handler
= (wxImageHandler
*) node
->GetData();
1019 CompareImage(*handler
, expected8
, wxIMAGE_HAVE_PALETTE
);
1021 CompareImage(*handler
, expected24
);
1022 CompareImage(*handler
, expected32
, wxIMAGE_HAVE_ALPHA
);
1026 expected8
.LoadFile("horse.gif");
1027 CPPUNIT_ASSERT( expected8
.IsOk() );
1029 CPPUNIT_ASSERT( expected8
.HasPalette() );
1030 #endif // #if wxUSE_PALETTE
1032 expected8
.SetAlpha();
1034 width
= expected8
.GetWidth();
1035 height
= expected8
.GetHeight();
1036 for (y
= 0; y
< height
; ++y
)
1038 for (x
= 0; x
< width
; ++x
)
1040 expected8
.SetAlpha(x
, y
, (x
*y
) & wxIMAGE_ALPHA_OPAQUE
);
1045 Explicitly make known we want a palettised PNG. If we don't then this
1046 particular image gets saved as a true colour image because there's an
1047 alpha channel present and the PNG saver prefers to keep the alpha over
1048 saving as a palettised image that has alpha converted to a mask.
1050 expected8
.SetOption(wxIMAGE_OPTION_PNG_FORMAT
, wxPNG_TYPE_PALETTE
);
1053 The image contains 256 indexed colours and needs another palette entry
1054 for storing the transparency index. This results in wanting 257 palette
1055 entries but that amount is not supported by PNG, as such this image
1056 should not contain a palette (but still have alpha) and be stored as a
1057 true colour image instead.
1059 CompareImage(*wxImage::FindHandler(wxBITMAP_TYPE_PNG
),
1060 expected8
, wxIMAGE_HAVE_ALPHA
);
1064 Now do the same test again but remove one (random) palette entry. This
1065 should result in saving the PNG with a palette.
1067 unsigned char red
[256], green
[256], blue
[256];
1068 const wxPalette
& pal
= expected8
.GetPalette();
1069 const int paletteCount
= pal
.GetColoursCount();
1070 for (i
= 0; i
< paletteCount
; ++i
)
1072 expected8
.GetPalette().GetRGB(i
, &red
[i
], &green
[i
], &blue
[i
]);
1074 wxPalette
newPal(paletteCount
- 1, red
, green
, blue
);
1076 red
[paletteCount
-1], green
[paletteCount
-1], blue
[paletteCount
-1],
1077 red
[paletteCount
-2], green
[paletteCount
-2], blue
[paletteCount
-2]);
1079 expected8
.SetPalette(newPal
);
1081 wxImage ref8
= expected8
;
1084 Convert the alpha channel to a mask like the PNG saver does. Also convert
1085 the colour used for transparency from 1,0,0 to 2,0,0. The latter gets
1086 done by the PNG loader in search of an unused colour to use for
1087 transparency (this should be fixed).
1089 ref8
.ConvertAlphaToMask();
1090 ref8
.Replace(1, 0, 0, 2, 0, 0);
1092 CompareImage(*wxImage::FindHandler(wxBITMAP_TYPE_PNG
),
1093 expected8
, wxIMAGE_HAVE_PALETTE
, &ref8
);
1097 void ImageTestCase::SaveAnimatedGIF()
1100 wxImage
image("horse.gif");
1101 CPPUNIT_ASSERT( image
.IsOk() );
1103 wxImageArray images
;
1106 for (i
= 0; i
< 4-1; ++i
)
1108 images
.Add( images
[i
].Rotate90() );
1110 images
[i
+1].SetPalette(images
[0].GetPalette());
1113 wxMemoryOutputStream memOut
;
1114 CPPUNIT_ASSERT( wxGIFHandler().SaveAnimation(images
, &memOut
) );
1116 wxGIFHandler handler
;
1117 wxMemoryInputStream
memIn(memOut
);
1118 CPPUNIT_ASSERT(memIn
.IsOk());
1119 const int imageCount
= handler
.GetImageCount(memIn
);
1120 CPPUNIT_ASSERT_EQUAL(4, imageCount
);
1122 for (i
= 0; i
< imageCount
; ++i
)
1124 wxFileOffset pos
= memIn
.TellI();
1125 CPPUNIT_ASSERT( handler
.LoadFile(&image
, memIn
, true, i
) );
1130 ("Compare test for GIF frame number %d failed", i
),
1131 memcmp(image
.GetData(), images
[i
].GetData(),
1132 images
[i
].GetWidth() * images
[i
].GetHeight() * 3) == 0
1135 #endif // #if wxUSE_PALETTE
1138 void ImageTestCase::ReadCorruptedTGA()
1140 static unsigned char corruptTGA
[18+1+3] =
1144 10, // RLE compressed image.
1150 1, 0, // Width is 1.
1151 1, 0, // Height is 1.
1152 24, // Bits per pixel.
1155 0xff, // Run length (repeat next pixel 127+1 times).
1156 0xff, 0xff, 0xff // One 24-bit pixel.
1159 wxMemoryInputStream
memIn(corruptTGA
, WXSIZEOF(corruptTGA
));
1160 CPPUNIT_ASSERT(memIn
.IsOk());
1163 CPPUNIT_ASSERT( !tgaImage
.LoadFile(memIn
) );
1167 Instead of repeating a pixel 127+1 times, now tell it there will
1168 follow 127+1 uncompressed pixels (while we only should have 1 in total).
1170 corruptTGA
[18] = 0x7f;
1171 CPPUNIT_ASSERT( !tgaImage
.LoadFile(memIn
) );
1174 #endif //wxUSE_IMAGE
1178 TODO: add lots of more tests to wxImage functions