1 //
2 // Copyright 2013 Christian Henning
3 //
4 // Distributed under the Boost Software License, Version 1.0
5 // See accompanying file LICENSE_1_0.txt or copy at
6 // http://www.boost.org/LICENSE_1_0.txt
7 //
8 //#define BOOST_TEST_MODULE bmp_read_test_module
9 #include <boost/gil.hpp>
10 #include <boost/gil/extension/io/bmp.hpp>
11 
12 #include <boost/test/unit_test.hpp>
13 
14 #include "paths.hpp"
15 #include "scanline_read_test.hpp"
16 
17 using namespace std;
18 using namespace boost::gil;
19 
20 using tag_t = bmp_tag;
21 
BOOST_AUTO_TEST_SUITE(gil_io_bmp_tests)22 BOOST_AUTO_TEST_SUITE( gil_io_bmp_tests )
23 
24 #ifdef BOOST_GIL_IO_USE_BMP_TEST_SUITE_IMAGES
25 
26 template< typename Image >
27 void write( Image&        img
28           , const string& file_name
29           )
30 {
31 #ifdef BOOST_GIL_IO_TEST_ALLOW_WRITING_IMAGES
32     write_view( bmp_out + file_name
33               , view( img )
34               , tag_t()
35               );
36 #endif // BOOST_GIL_IO_TEST_ALLOW_WRITING_IMAGES
37 }
38 
BOOST_AUTO_TEST_CASE(read_header_test)39 BOOST_AUTO_TEST_CASE( read_header_test )
40 {
41     {
42         using backend_t = get_reader_backend<std::string const, tag_t>::type;
43 
44         backend_t backend = read_image_info( bmp_filename
45                                            , tag_t()
46                                            );
47 
48         BOOST_CHECK_EQUAL( backend._info._offset               ,      54u );
49         BOOST_CHECK_EQUAL( backend._info._header_size          ,      40u );
50         BOOST_CHECK_EQUAL( backend._info._width                ,     1000 );
51         BOOST_CHECK_EQUAL( backend._info._height               ,      600 );
52         BOOST_CHECK_EQUAL( backend._info._bits_per_pixel       ,       24 );
53         BOOST_CHECK_EQUAL( backend._info._compression          ,       0u );
54         BOOST_CHECK_EQUAL( backend._info._image_size           , 1800000u );
55         BOOST_CHECK_EQUAL( backend._info._horizontal_resolution,        0 );
56         BOOST_CHECK_EQUAL( backend._info._vertical_resolution  ,        0 );
57         BOOST_CHECK_EQUAL( backend._info._num_colors           ,       0u );
58         BOOST_CHECK_EQUAL( backend._info._num_important_colors ,       0u );
59         BOOST_CHECK_EQUAL( backend._info._valid                ,     true );
60     }
61 }
62 
BOOST_AUTO_TEST_CASE(read_reference_images_test)63 BOOST_AUTO_TEST_CASE( read_reference_images_test )
64 {
65     // comments are taken from http://entropymine.com/jason/bmpsuite/reference/reference.html
66 
67     // g01bw.bmp - black and white palette (#000000,#FFFFFF)
68     {
69         rgba8_image_t img;
70         read_image( bmp_in + "g01bw.bmp", img, tag_t() );
71     }
72 
73     // g01wb.bmp - white and black palette (#FFFFFF,#000000).
74     // Should look the same as g01bw, not inverted.
75     {
76         rgba8_image_t img;
77 
78         read_image( bmp_in + "g01wb.bmp", img, tag_t() );
79         BOOST_CHECK_EQUAL( view( img ).width() , 127u );
80         BOOST_CHECK_EQUAL( view( img ).height(),  64u );
81 
82         write( img, "g01wb.bmp" );
83     }
84 
85     // g01bg.bmp - blue and green palette (#4040FF,#40FF40)
86     {
87         rgba8_image_t img;
88 
89         read_image( bmp_in + "g01bg.bmp", img, tag_t() );
90         BOOST_CHECK_EQUAL( view( img ).width() , 127u );
91         BOOST_CHECK_EQUAL( view( img ).height(),  64u );
92 
93         write( img, "g01bg.bmp" );
94     }
95 
96     // g01p1.bmp - 1-color (blue) palette (#4040FF)
97     {
98         rgba8_image_t img;
99 
100         read_image( bmp_in + "g01p1.bmp", img, tag_t() );
101         BOOST_CHECK_EQUAL( view( img ).width() , 127u );
102         BOOST_CHECK_EQUAL( view( img ).height(),  64u );
103 
104         write( img, "g01p1.bmp" );
105     }
106 
107     // g04.bmp - basic 4bpp (16 color) image
108     {
109         rgba8_image_t img;
110 
111         read_image( bmp_in + "g04.bmp", img, tag_t() );
112         BOOST_CHECK_EQUAL( view( img ).width() , 127u );
113         BOOST_CHECK_EQUAL( view( img ).height(),  64u );
114 
115         write( img, "g04.bmp" );
116     }
117 
118     // g04rle.bmp - RLE compressed.
119     {
120         rgb8_image_t img;
121 
122         read_image( bmp_in + "g04rle.bmp", img, tag_t() );
123         BOOST_CHECK_EQUAL( view( img ).width() , 127u );
124         BOOST_CHECK_EQUAL( view( img ).height(),  64u );
125 
126         write( img, "g04rle.bmp" );
127     }
128 
129     // g04p4.bmp - 4-color grayscale palette
130     {
131         rgba8_image_t img;
132 
133         read_image( bmp_in + "g04p4.bmp", img, tag_t() );
134         BOOST_CHECK_EQUAL( view( img ).width() , 127u );
135         BOOST_CHECK_EQUAL( view( img ).height(),  64u );
136 
137         write( img, "g04p4.bmp" );
138     }
139 
140     // g08.bmp - basic 8bpp (256 color) image
141     {
142         rgba8_image_t img;
143 
144         read_image( bmp_in + "g08.bmp", img, tag_t() );
145         BOOST_CHECK_EQUAL( view( img ).width() , 127u );
146         BOOST_CHECK_EQUAL( view( img ).height(),  64u );
147 
148         write( img, "g08.bmp" );
149     }
150 
151     // g08p256.bmp - biClrUsed=256, biClrImportant=0 [=256]
152     {
153         rgba8_image_t img;
154 
155         read_image( bmp_in + "g08p256.bmp", img, tag_t() );
156         BOOST_CHECK_EQUAL( view( img ).width() , 127u );
157         BOOST_CHECK_EQUAL( view( img ).height(),  64u );
158 
159         write( img, "g08p256.bmp" );
160     }
161 
162     // g08pi256.bmp - biClrUsed=256, biClrImportant=256
163     {
164         rgba8_image_t img;
165 
166         read_image( bmp_in + "g08pi256.bmp", img, tag_t() );
167         BOOST_CHECK_EQUAL( view( img ).width() , 127u );
168         BOOST_CHECK_EQUAL( view( img ).height(),  64u );
169 
170         write( img, "g08pi256.bmp" );
171     }
172 
173     // g08pi64.bmp - biClrUsed=256, biClrImportant=64. It's barely possible that some
174     // sophisticated viewers may display this image in grayscale, if there are a
175     // limited number of colors available.
176     {
177         rgba8_image_t img;
178 
179         read_image( bmp_in + "g08pi64.bmp", img, tag_t() );
180         BOOST_CHECK_EQUAL( view( img ).width() , 127u );
181         BOOST_CHECK_EQUAL( view( img ).height(),  64u );
182 
183         write( img, "g08pi64.bmp" );
184     }
185 
186     // g08rle.bmp - RLE compressed.
187     {
188         rgb8_image_t img;
189 
190         read_image( bmp_in + "g08rle.bmp", img, tag_t() );
191         BOOST_CHECK_EQUAL( view( img ).width() , 127u );
192         BOOST_CHECK_EQUAL( view( img ).height(),  64u );
193 
194         write( img, "g08rle.bmp" );
195     }
196 
197     // g08os2.bmp - OS/2-style bitmap. This is an obsolete variety of BMP
198     // that is still encountered sometimes. It has 3-byte palette
199     // entries (instead of 4), and 16-bit width/height fields (instead of 32).
200     {
201         rgb8_image_t img;
202 
203         read_image( bmp_in + "g08os2.bmp", img, tag_t() );
204         BOOST_CHECK_EQUAL( view( img ).width() , 127u );
205         BOOST_CHECK_EQUAL( view( img ).height(),  64u );
206 
207         write( img, "g08os2.bmp" );
208     }
209 
210     // g08res22.bmp - resolution 7874x7874 pixels/meter (200x200 dpi)
211     {
212         rgba8_image_t img;
213 
214         read_image( bmp_in + "g08res22.bmp", img, tag_t() );
215         BOOST_CHECK_EQUAL( view( img ).width() , 127u );
216         BOOST_CHECK_EQUAL( view( img ).height(),  64u );
217 
218         write( img, "g08res22.bmp" );
219     }
220 
221     // g08res11.bmp - resolution 3937x3937 pixels/meter (100x100 dpi)
222     {
223         rgba8_image_t img;
224 
225         read_image( bmp_in + "g08res11.bmp", img, tag_t() );
226         BOOST_CHECK_EQUAL( view( img ).width() , 127u );
227         BOOST_CHECK_EQUAL( view( img ).height(),  64u );
228 
229         write( img, "g08res11.bmp" );
230     }
231 
232     // g08res21.bmp resolution 7874x3937 pixels/meter (200x100 dpi).
233     // Some programs (e.g. Imaging for Windows) may display this image
234     // stretched vertically, which is the optimal thing to do if the
235     // program is primarily a viewer, rather than an editor.
236     {
237         rgba8_image_t img;
238 
239         read_image( bmp_in + "g08res21.bmp", img, tag_t() );
240         BOOST_CHECK_EQUAL( view( img ).width() , 127u );
241         BOOST_CHECK_EQUAL( view( img ).height(),  64u );
242 
243         write( img, "g08res21.bmp" );
244     }
245 
246     // g08s0.bmp - bits size not given (set to 0). This is legal for uncompressed bitmaps.
247     {
248         rgba8_image_t img;
249 
250         read_image( bmp_in + "g08s0.bmp", img, tag_t() );
251         BOOST_CHECK_EQUAL( view( img ).width() , 127u );
252         BOOST_CHECK_EQUAL( view( img ).height(),  64u );
253 
254         write( img, "g08s0.bmp" );
255     }
256 
257     // g08offs.bmp - bfOffBits in header not set to the usual value.
258     // There are 100 extra unused bytes between palette and bits.
259     {
260         rgba8_image_t img;
261 
262         read_image( bmp_in + "g08offs.bmp", img, tag_t() );
263         BOOST_CHECK_EQUAL( view( img ).width() , 127u );
264         BOOST_CHECK_EQUAL( view( img ).height(),  64u );
265 
266         write( img, "g08offs.bmp" );
267     }
268 
269     // g08w126.bmp - size 126x63 (right and bottom slightly clipped)
270     {
271         rgba8_image_t img;
272 
273         read_image( bmp_in + "g08w126.bmp", img, tag_t() );
274         BOOST_CHECK_EQUAL( view( img ).width() , 126u );
275         BOOST_CHECK_EQUAL( view( img ).height(),  63u );
276 
277         write( img, "g08w126.bmp" );
278     }
279 
280     // g08w125.bmp - size 125x62
281     {
282         rgba8_image_t img;
283 
284         read_image( bmp_in + "g08w125.bmp", img, tag_t() );
285         BOOST_CHECK_EQUAL( view( img ).width() , 125u );
286         BOOST_CHECK_EQUAL( view( img ).height(),  62u );
287 
288         write( img, "g08w125.bmp" );
289     }
290 
291     // g08w124.bmp - size 124x61
292     {
293         rgba8_image_t img;
294 
295         read_image( bmp_in + "g08w124.bmp", img, tag_t() );
296         BOOST_CHECK_EQUAL( view( img ).width() , 124u );
297         BOOST_CHECK_EQUAL( view( img ).height(),  61u );
298 
299         write( img, "g08w124.bmp" );
300     }
301 
302     // g08p64.bmp - 64-color grayscale palette
303     {
304         rgba8_image_t img;
305 
306         read_image( bmp_in + "g08p64.bmp", img, tag_t() );
307         BOOST_CHECK_EQUAL( view( img ).width() , 127u );
308         BOOST_CHECK_EQUAL( view( img ).height(),  64u );
309 
310         write( img, "g08p64.bmp" );
311     }
312 
313     // g16def555.bmp - 15-bit color (1 bit wasted), biCompression=BI_RGB (no bitfields, defaults to 5-5-5)
314     {
315         rgb8_image_t img;
316 
317         read_image( bmp_in + "g16def555.bmp", img, tag_t() );
318         BOOST_CHECK_EQUAL( view( img ).width() , 127u );
319         BOOST_CHECK_EQUAL( view( img ).height(),  64u );
320 
321         write( img, "g16def555.bmp" );
322     }
323 
324     // g16bf555.bmp - 15-bit color, biCompression=BI_BITFIELDS (bitfields indicate 5-5-5)
325     {
326         rgb8_image_t img;
327 
328         read_image( bmp_in + "g16bf555.bmp", img, tag_t() );
329         BOOST_CHECK_EQUAL( view( img ).width() , 127u );
330         BOOST_CHECK_EQUAL( view( img ).height(),  64u );
331 
332         write( img, "g16bf555.bmp" );
333     }
334 
335     // g16bf565.bmp - 16-bit color, biCompression=BI_BITFIELDS (bitfields indicate 5-6-5)
336     {
337         rgb8_image_t img;
338 
339         read_image( bmp_in + "g16bf565.bmp", img, tag_t() );
340         BOOST_CHECK_EQUAL( view( img ).width() , 127u );
341         BOOST_CHECK_EQUAL( view( img ).height(),  64u );
342 
343         write( img, "g16bf565.bmp" );
344     }
345 
346     // g24.bmp - 24-bit color (BGR)
347     {
348         rgb8_image_t img;
349 
350         read_image( bmp_in + "g24.bmp", img, tag_t() );
351         BOOST_CHECK_EQUAL( view( img ).width() , 127u );
352         BOOST_CHECK_EQUAL( view( img ).height(),  64u );
353 
354         write( img, "g24.bmp" );
355     }
356 
357     // g32def.bmp - 24-bit color (8 bits wasted), biCompression=BI_RGB (no bitfields, defaults to BGRx)
358     {
359         rgba8_image_t img;
360 
361         read_image( bmp_in + "g32def.bmp", img, tag_t() );
362         BOOST_CHECK_EQUAL( view( img ).width() , 127u );
363         BOOST_CHECK_EQUAL( view( img ).height(),  64u );
364 
365         write( img, "g32def.bmp" );
366     }
367 
368     // g32bf.bmp - 24-bit color (8 bits wasted), biCompression=BI_BITFIELDS (bitfields indicate BGRx)
369     {
370         rgba8_image_t img;
371 
372         read_image( bmp_in + "g32bf.bmp", img, tag_t() );
373         BOOST_CHECK_EQUAL( view( img ).width() , 127u );
374         BOOST_CHECK_EQUAL( view( img ).height(),  64u );
375 
376         write( img, "g32bf.bmp" );
377     }
378 }
379 
380 
BOOST_AUTO_TEST_CASE(read_reference_images_image_iterator_test)381 BOOST_AUTO_TEST_CASE( read_reference_images_image_iterator_test )
382 {
383     // comments are taken from http://entropymine.com/jason/bmpsuite/reference/reference.html
384 
385     // g01bw.bmp - black and white palette (#000000,#FFFFFF)
386     test_scanline_reader< rgba8_image_t, bmp_tag >( string( bmp_in + "g01bw.bmp" ).c_str() );
387 
388     // g01wb.bmp - white and black palette (#FFFFFF,#000000).
389     // Should look the same as g01bw, not inverted.
390     test_scanline_reader< rgba8_image_t, bmp_tag >( string( bmp_in + "g01wb.bmp" ).c_str() );
391 
392     // g01bg.bmp - blue and green palette (#4040FF,#40FF40)
393     test_scanline_reader< rgba8_image_t, bmp_tag >( string( bmp_in + "g01bg.bmp" ).c_str() );
394 
395     // g01p1.bmp - 1-color (blue) palette (#4040FF)
396     test_scanline_reader< rgba8_image_t, bmp_tag >( string( bmp_in + "g01p1.bmp" ).c_str() );
397 
398     // g04.bmp - basic 4bpp (16 color) image
399     test_scanline_reader< rgba8_image_t, bmp_tag >( string( bmp_in + "g04.bmp" ).c_str() );
400 
401     // not supported
402     // g04rle.bmp - RLE compressed.
403     //test_scanline_reader< bgra8_image_t, bmp_tag >( string( bmp_in + "g01bg.bmp" ).c_str() );
404 
405     // g04p4.bmp - 4-color grayscale palette
406     test_scanline_reader< rgba8_image_t, bmp_tag >( string( bmp_in + "g04p4.bmp" ).c_str() );
407 
408     // g08.bmp - basic 8bpp (256 color) image
409     test_scanline_reader< rgba8_image_t, bmp_tag >( string( bmp_in + "g08.bmp" ).c_str() );
410 
411     // g08p256.bmp - biClrUsed=256, biClrImportant=0 [=256]
412     test_scanline_reader< rgba8_image_t, bmp_tag >( string( bmp_in + "g08p256.bmp" ).c_str() );
413 
414     // g08pi256.bmp - biClrUsed=256, biClrImportant=256
415     test_scanline_reader< rgba8_image_t, bmp_tag >( string( bmp_in + "g08pi256.bmp" ).c_str() );
416 
417     // g08pi64.bmp - biClrUsed=256, biClrImportant=64. It's barely possible that some
418     // sophisticated viewers may display this image in grayscale, if there are a
419     // limited number of colors available.
420     test_scanline_reader< rgba8_image_t, bmp_tag >( string( bmp_in + "g08pi64.bmp" ).c_str() );
421 
422     // not supported
423     // g08rle.bmp - RLE compressed.
424 
425     // g08os2.bmp - OS/2-style bitmap. This is an obsolete variety of BMP
426     // that is still encountered sometimes. It has 3-byte palette
427     // entries (instead of 4), and 16-bit width/height fields (instead of 32).
428     test_scanline_reader< rgb8_image_t, bmp_tag >( string( bmp_in + "g08os2.bmp" ).c_str() );
429 
430     // g08res22.bmp - resolution 7874x7874 pixels/meter (200x200 dpi)
431     test_scanline_reader< rgba8_image_t, bmp_tag >( string( bmp_in + "g08res22.bmp" ).c_str() );
432 
433     // g08res11.bmp - resolution 3937x3937 pixels/meter (100x100 dpi)
434     test_scanline_reader< rgba8_image_t, bmp_tag >( string( bmp_in + "g08res11.bmp" ).c_str() );
435 
436     // g08res21.bmp resolution 7874x3937 pixels/meter (200x100 dpi).
437     // Some programs (e.g. Imaging for Windows) may display this image
438     // stretched vertically, which is the optimal thing to do if the
439     // program is primarily a viewer, rather than an editor.
440     test_scanline_reader< rgba8_image_t, bmp_tag >( string( bmp_in + "g08res21.bmp" ).c_str() );
441 
442     // g08s0.bmp - bits size not given (set to 0). This is legal for uncompressed bitmaps.
443     test_scanline_reader< rgba8_image_t, bmp_tag >( string( bmp_in + "g08s0.bmp" ).c_str() );
444 
445     // g08offs.bmp - bfOffBits in header not set to the usual value.
446     // There are 100 extra unused bytes between palette and bits.
447     test_scanline_reader< rgba8_image_t, bmp_tag >( string( bmp_in + "g08offs.bmp" ).c_str() );
448 
449     // g08w126.bmp - size 126x63 (right and bottom slightly clipped)
450     test_scanline_reader< rgba8_image_t, bmp_tag >( string( bmp_in + "g08w126.bmp" ).c_str() );
451 
452     // g08w125.bmp - size 125x62
453     test_scanline_reader< rgba8_image_t, bmp_tag >( string( bmp_in + "g08w125.bmp" ).c_str() );
454 
455     // g08w124.bmp - size 124x61
456     test_scanline_reader< rgba8_image_t, bmp_tag >( string( bmp_in + "g08w124.bmp" ).c_str() );
457 
458     // g08p64.bmp - 64-color grayscale palette
459     test_scanline_reader< rgba8_image_t, bmp_tag >( string( bmp_in + "g08p64.bmp" ).c_str() );
460 
461     // g16def555.bmp - 15-bit color (1 bit wasted), biCompression=BI_RGB (no bitfields, defaults to 5-5-5)
462     test_scanline_reader< rgb8_image_t, bmp_tag >( string( bmp_in + "g16def555.bmp" ).c_str() );
463 
464     // g16bf555.bmp - 15-bit color, biCompression=BI_BITFIELDS (bitfields indicate 5-5-5)
465     test_scanline_reader< rgb8_image_t, bmp_tag >( string( bmp_in + "g16bf555.bmp" ).c_str() );
466 
467     // g16bf565.bmp - 16-bit color, biCompression=BI_BITFIELDS (bitfields indicate 5-6-5)
468     test_scanline_reader< rgb8_image_t, bmp_tag >( string( bmp_in + "g16bf565.bmp" ).c_str() );
469 
470     // g24.bmp - 24-bit color (BGR)
471     test_scanline_reader< bgr8_image_t, bmp_tag >( string( bmp_in + "g24.bmp" ).c_str() );
472 
473     // g32def.bmp - 24-bit color (8 bits wasted), biCompression=BI_RGB (no bitfields, defaults to BGRx)
474     test_scanline_reader< bgra8_image_t, bmp_tag >( string( bmp_in + "g32def.bmp" ).c_str() );
475 
476     // g32bf.bmp - 24-bit color (8 bits wasted), biCompression=BI_BITFIELDS (bitfields indicate BGRx)
477     test_scanline_reader< bgra8_image_t, bmp_tag >( string( bmp_in + "g32bf.bmp" ).c_str() );
478 }
479 
BOOST_AUTO_TEST_CASE(partial_image_test)480 BOOST_AUTO_TEST_CASE( partial_image_test )
481 {
482     const std::string filename( bmp_in + "rgb.bmp" );
483 
484     {
485         rgb8_image_t img;
486         read_image( filename
487                   , img
488                   , image_read_settings< bmp_tag >( point_t( 0, 0 ), point_t( 50, 50 ) )
489                   );
490 
491 #ifdef BOOST_GIL_IO_TEST_ALLOW_WRITING_IMAGES
492         write_view( bmp_out + "rgb_partial.bmp"
493                   , view( img )
494                   , tag_t()
495                   );
496 #endif // BOOST_GIL_IO_TEST_ALLOW_WRITING_IMAGES
497     }
498 }
499 
500 #endif // BOOST_GIL_IO_USE_BMP_TEST_SUITE_IMAGES
501 
502 BOOST_AUTO_TEST_SUITE_END()
503