KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_bitmap_base.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.TXT for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you may find one here:
18 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19 * or you may search the http://www.gnu.org website for the version 2 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
28
30
31// Code under test
32#include <bitmap_base.h>
33
34#include "wximage_test_utils.h"
35
36#include <wx/mstream.h>
37
38
39// Dummy PNG image 8x8, 4 tiles:
40//
41// green, black,
42// red, blue
43// (the black tile is a circle, otherwise older wx's seem to crash)
44static const std::vector<unsigned char> png_data_4tile = { //
45 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52,
46 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x08, 0x06, 0x00, 0x00, 0x00, 0xC4, 0x0F, 0xBE,
47 0x8B, 0x00, 0x00, 0x00, 0x04, 0x73, 0x42, 0x49, 0x54, 0x08, 0x08, 0x08, 0x08, 0x7C, 0x08, 0x64,
48 0x88, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0E, 0xC4, 0x00, 0x00, 0x0E,
49 0xC4, 0x01, 0x95, 0x2B, 0x0E, 0x1B, 0x00, 0x00, 0x00, 0x19, 0x74, 0x45, 0x58, 0x74, 0x53, 0x6F,
50 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x00, 0x77, 0x77, 0x77, 0x2E, 0x69, 0x6E, 0x6B, 0x73, 0x63,
51 0x61, 0x70, 0x65, 0x2E, 0x6F, 0x72, 0x67, 0x9B, 0xEE, 0x3C, 0x1A, 0x00, 0x00, 0x00, 0x40, 0x49,
52 0x44, 0x41, 0x54, 0x18, 0x95, 0xA5, 0xCD, 0x4B, 0x0A, 0xC0, 0x20, 0x14, 0x43, 0xD1, 0x63, 0x77,
53 0xA7, 0xDD, 0xFF, 0x06, 0xD4, 0x7D, 0x3C, 0x07, 0x95, 0x42, 0x3F, 0xE0, 0xC0, 0x84, 0x0C, 0x02,
54 0xE1, 0x86, 0x78, 0x99, 0x13, 0x1D, 0x0D, 0xC5, 0xCF, 0xA0, 0x21, 0x66, 0xEA, 0x61, 0xA9, 0x2F,
55 0xA1, 0x4C, 0x4A, 0x45, 0x4E, 0x71, 0xA1, 0x6E, 0xA5, 0x67, 0xB5, 0xBC, 0xD8, 0x1F, 0x0C, 0xA7,
56 0xFD, 0x23, 0x67, 0x70, 0xDA, 0x89, 0xA2, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE,
57 0x42, 0x60, 0x82
58};
59
61static const VECTOR2I size_4tile{ 8, 8 };
62
63static const KIGFX::COLOR4D col_red{ 1.0, 0.0, 0.0, 1.0 };
64static const KIGFX::COLOR4D col_green{ 0.0, 1.0, 0.0, 1.0 };
65static const KIGFX::COLOR4D col_blue{ 0.0, 0.0, 1.0, 1.0 };
66static const KIGFX::COLOR4D col_black{ 0.0, 0.0, 0.0, 1.0 };
67
68
70{
71public:
73 {
74 wxMemoryInputStream mis( png_data_4tile.data(), png_data_4tile.size() );
75
76 bool ok = m_4tile.ReadImageFile( mis );
77
78 // this is needed for most tests and can fail if the image handlers
79 // are not initialised (e.g. with wxInitAllImageHandlers)
80 BOOST_REQUIRE( ok );
81
82 // use an easier scale for test purposes
83 m_4tile.SetPixelSizeIu( 2.0 );
84 m_4tile.SetScale( 5.0 );
85 }
86
87 /*
88 * Simple image of 4 coloured tiles
89 */
91};
92
93
97BOOST_FIXTURE_TEST_SUITE( BitmapBase, TEST_BITMAP_BASE_FIXTURE )
98
99
100
104{
106 // Const to test we can get this data from a const object
107 const BITMAP_BASE& cempty = empty;
108 const int expected_ppi = 300;
109
110 BOOST_CHECK_EQUAL( cempty.GetImageData(), nullptr );
111 BOOST_CHECK_EQUAL( cempty.GetPPI(), expected_ppi );
112 BOOST_CHECK_EQUAL( cempty.GetScale(), 1.0 );
113 BOOST_CHECK_EQUAL( cempty.GetPixelSizeIu(), 254000.0 / expected_ppi );
114
115 // can do this on an empty image
116 empty.Rotate( true );
118}
119
120
125{
128
129 // should still have nothing in it
130 BOOST_CHECK_EQUAL( copied.GetImageData(), nullptr );
131}
132
133
140
141
146{
147 // make sure we can do all this to a const img
148 const BITMAP_BASE& img = m_4tile;
149
150 // have "some" image data
151 BOOST_REQUIRE_NE( img.GetImageData(), nullptr );
152
153 // 3780 pixels/meter = 37.8 px/cm; 37.8 * 2.54 = 96.012 -> rounds to 96
154 const int expected_ppi = 96;
155 BOOST_CHECK_EQUAL( img.GetPPI(), expected_ppi );
156 BOOST_CHECK_EQUAL( img.GetScale(), 5.0 );
157
158 // we changed this, make sure it's right
159 BOOST_CHECK_EQUAL( img.GetPixelSizeIu(), 2.0 );
160
161 BOOST_CHECK( img.GetSizePixels() == size_4tile );
162 BOOST_CHECK( img.GetSize() == size_4tile * 10 );
163
164 const BOX2I bb = img.GetBoundingBox();
165 BOOST_CHECK( bb.GetPosition() == VECTOR2I( -40, -40 ) );
166 BOOST_CHECK( bb.GetEnd() == VECTOR2I( 40, 40 ) );
167}
168
169
178BOOST_AUTO_TEST_CASE( PPIFromNonIntegerPixelsPerCm )
179{
180 // Minimal 1x1 RGB PNG with pHYs chunk: 3780 pixels/meter in both axes.
181 // 3780 PPM -> 37.8 px/cm -> 37.8 * 2.54 = 96.012 -> rounds to 96 PPI.
182 // Generated with Python (zlib/struct), CRCs verified.
183 static const std::vector<unsigned char> png_with_phys = {
184 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52,
185 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x02, 0x00, 0x00, 0x00, 0x90, 0x77, 0x53,
186 0xDE, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0E, 0xC4, 0x00, 0x00, 0x0E,
187 0xC4, 0x01, 0x95, 0x2B, 0x0E, 0x1B, 0x00, 0x00, 0x00, 0x0C, 0x49, 0x44, 0x41, 0x54, 0x78, 0xDA,
188 0x63, 0xF8, 0xCF, 0xC0, 0x00, 0x00, 0x03, 0x01, 0x01, 0x00, 0xF7, 0x03, 0x41, 0x43, 0x00, 0x00,
189 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82
190 };
191
192 BITMAP_BASE bmp;
193 wxMemoryInputStream mis( png_with_phys.data(), png_with_phys.size() );
194 bool ok = bmp.ReadImageFile( mis );
195
196 BOOST_REQUIRE( ok );
197
198 // 3780 PPM should give 96 PPI, not 94 (the old truncation result)
199 BOOST_CHECK_EQUAL( bmp.GetPPI(), 96 );
200}
201
202
207{
208 const wxImage* img_data = m_4tile.GetImageData();
209 BOOST_REQUIRE_NE( img_data, nullptr );
210
211 // green, black,
212 // red, blue
213 const std::vector<TEST_PIXEL_CASE> exp_pixels = {
214 { 1, 1, col_green },
215 { 6, 1, col_black },
216 { 1, 6, col_red },
217 { 6, 6, col_blue },
218 };
219
220 for( const auto& c : exp_pixels )
221 {
223 KI_TEST::IsImagePixelOfColor, ( *img_data )( c.m_x )( c.m_y )( c.m_color ) );
224 }
225}
226
230BOOST_AUTO_TEST_CASE( RotateImageCCW )
231{
232 m_4tile.Rotate( true ); // true = CCW
233
234 const wxImage* img_data = m_4tile.GetImageData();
235 BOOST_REQUIRE_NE( img_data, nullptr );
236
237 // Original: After 90 CCW:
238 // green, black, black, blue,
239 // red, blue green, red
240 const std::vector<TEST_PIXEL_CASE> exp_pixels = {
241 { 1, 1, col_black },
242 { 6, 1, col_blue },
243 { 1, 6, col_green },
244 { 6, 6, col_red },
245 };
246
247 for( const auto& c : exp_pixels )
248 {
250 KI_TEST::IsImagePixelOfColor, ( *img_data )( c.m_x )( c.m_y )( c.m_color ) );
251 }
252}
253
257BOOST_AUTO_TEST_CASE( RotateImageCW )
258{
259 m_4tile.Rotate( false ); // false = CW
260
261 const wxImage* img_data = m_4tile.GetImageData();
262 BOOST_REQUIRE_NE( img_data, nullptr );
263
264 // Original: After 90 CW:
265 // green, black, red, green,
266 // red, blue blue, black
267 const std::vector<TEST_PIXEL_CASE> exp_pixels = {
268 { 1, 1, col_red },
269 { 6, 1, col_green },
270 { 1, 6, col_blue },
271 { 6, 6, col_black },
272 };
273
274 for( const auto& c : exp_pixels )
275 {
277 KI_TEST::IsImagePixelOfColor, ( *img_data )( c.m_x )( c.m_y )( c.m_color ) );
278 }
279}
280
285{
286 m_4tile.Mirror( FLIP_DIRECTION::TOP_BOTTOM );
287
288 const wxImage* img_data = m_4tile.GetImageData();
289 BOOST_REQUIRE_NE( img_data, nullptr );
290
291 // red, blue
292 // green, black
293 const std::vector<TEST_PIXEL_CASE> exp_pixels = {
294 { 1, 1, col_red },
295 { 6, 1, col_blue },
296 { 1, 6, col_green },
297 { 6, 6, col_black },
298 };
299
300 for( const auto& c : exp_pixels )
301 {
303 KI_TEST::IsImagePixelOfColor, ( *img_data )( c.m_x )( c.m_y )( c.m_color ) );
304 }
305}
306
313BOOST_AUTO_TEST_CASE( SetImageOutputsData )
314{
315 BITMAP_BASE bitmap;
316 wxImage img( 2, 2 );
317 img.SetRGB( 0, 0, 0, 255, 0 );
318 img.SetRGB( 1, 0, 0, 0, 255 );
319 img.SetRGB( 0, 1, 255, 0, 0 );
320 img.SetRGB( 1, 1, 0, 0, 255 );
321
322 // Set the wxImage directly, not via a stream/file
323 // (this happens, e.g. when the clipboard gives you a wxImage)
324 bitmap.SetImage( img );
325
326 wxMemoryOutputStream mos;
327 BOOST_CHECK( bitmap.SaveImageData( mos ) );
328
329 BOOST_REQUIRE( mos.GetSize() > 0 );
330
331 // check the output is the same as the input
332 wxMemoryInputStream mis( mos );
333 wxImage img2;
334
335 BOOST_CHECK( img2.LoadFile( mis, wxBITMAP_TYPE_PNG ) );
336
338}
339
BOX2< VECTOR2I > BOX2I
Definition box2.h:922
This class handle bitmap images in KiCad.
Definition bitmap_base.h:49
VECTOR2I GetSizePixels() const
const BOX2I GetBoundingBox() const
Return the orthogonal, bounding box of this object for display purposes.
double GetPixelSizeIu() const
Definition bitmap_base.h:65
double GetScale() const
Definition bitmap_base.h:73
bool SaveImageData(wxOutputStream &aOutStream) const
Write the bitmap data to aOutStream.
bool SetImage(const wxImage &aImage)
Set the image from an existing wxImage.
bool ReadImageFile(const wxString &aFullFilename)
Reads and stores in memory an image file.
int GetPPI() const
wxImage * GetImageData()
Definition bitmap_base.h:68
VECTOR2I GetSize() const
constexpr const Vec & GetPosition() const
Definition box2.h:211
constexpr const Vec GetEnd() const
Definition box2.h:212
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:105
static bool empty(const wxTextEntryBase *aCtrl)
@ TOP_BOTTOM
Flip top to bottom (around the X axis)
Definition mirror.h:29
bool IsImagePixelOfColor(const wxImage &aImage, int aX, int aY, const KIGFX::COLOR4D &aColor)
Predicate to check an image pixel matches color and alpha.
bool ImagesHaveSamePixels(const wxImage &aImgA, const wxImage &aImgB)
Check if an image is identical to another image, pixel by pixel.
KIGFX::COLOR4D m_color
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
static const KIGFX::COLOR4D col_blue
BOOST_AUTO_TEST_CASE(Empty)
Declare the test suite.
static const VECTOR2I size_4tile
static const KIGFX::COLOR4D col_red
static const KIGFX::COLOR4D col_green
static const std::vector< unsigned char > png_data_4tile
4tile is an 8x8 image
static const KIGFX::COLOR4D col_black
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
bool copied
BOOST_CHECK_PREDICATE(ArePolylineEndPointsNearCircle,(chain)(c.m_geom.m_center_point)(radius)(accuracy+epsilon))
BOOST_CHECK_EQUAL(result, "25.4")
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:687