]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/gil/extension/io/png/detail/writer_backend.hpp
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / boost / gil / extension / io / png / detail / writer_backend.hpp
1 //
2 // Copyright 2012 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 #ifndef BOOST_GIL_EXTENSION_IO_PNG_DETAIL_WRITER_BACKEND_HPP
9 #define BOOST_GIL_EXTENSION_IO_PNG_DETAIL_WRITER_BACKEND_HPP
10
11 #include <boost/gil/extension/io/png/tags.hpp>
12 #include <boost/gil/extension/io/png/detail/base.hpp>
13 #include <boost/gil/extension/io/png/detail/supported_types.hpp>
14
15 #include <boost/gil/io/base.hpp>
16 #include <boost/gil/io/typedefs.hpp>
17
18 namespace boost { namespace gil {
19
20 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
21 #pragma warning(push)
22 #pragma warning(disable:4512) //assignment operator could not be generated
23 #pragma warning(disable:4611) //interaction between '_setjmp' and C++ object destruction is non-portable
24 #endif
25
26 ///
27 /// PNG Writer Backend
28 ///
29 template< typename Device >
30 struct writer_backend< Device
31 , png_tag
32 >
33 : public detail::png_struct_info_wrapper
34 {
35
36 private:
37
38 using this_t = writer_backend<Device, png_tag>;
39
40 public:
41
42 using format_tag_t = png_tag;
43
44 ///
45 /// Constructor
46 ///
47 writer_backend( const Device& io_dev
48 , const image_write_info< png_tag >& info
49 )
50 : png_struct_info_wrapper( false )
51 , _io_dev( io_dev )
52 , _info( info )
53 {
54 // Create and initialize the png_struct with the desired error handler
55 // functions. If you want to use the default stderr and longjump method,
56 // you can supply NULL for the last three parameters. We also check that
57 // the library version is compatible with the one used at compile time,
58 // in case we are using dynamically linked libraries. REQUIRED.
59 get()->_struct = png_create_write_struct( PNG_LIBPNG_VER_STRING
60 , nullptr // user_error_ptr
61 , nullptr // user_error_fn
62 , nullptr // user_warning_fn
63 );
64
65 io_error_if( get_struct() == nullptr
66 , "png_writer: fail to call png_create_write_struct()"
67 );
68
69 // Allocate/initialize the image information data. REQUIRED
70 get()->_info = png_create_info_struct( get_struct() );
71
72 if( get_info() == nullptr )
73 {
74 png_destroy_write_struct( &get()->_struct
75 , nullptr
76 );
77
78 io_error( "png_writer: fail to call png_create_info_struct()" );
79 }
80
81 // Set error handling. REQUIRED if you aren't supplying your own
82 // error handling functions in the png_create_write_struct() call.
83 if( setjmp( png_jmpbuf( get_struct() )))
84 {
85 //free all of the memory associated with the png_ptr and info_ptr
86 png_destroy_write_struct( &get()->_struct
87 , &get()->_info
88 );
89
90 io_error( "png_writer: fail to call setjmp()" );
91 }
92
93 init_io( get_struct() );
94 }
95
96 protected:
97
98 template< typename View >
99 void write_header( const View& view )
100 {
101 using png_rw_info_t = detail::png_write_support
102 <
103 typename channel_type<typename get_pixel_type<View>::type>::type,
104 typename color_space_type<View>::type
105 >;
106
107 // Set the image information here. Width and height are up to 2^31,
108 // bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
109 // the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,
110 // PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
111 // or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or
112 // PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
113 // currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED
114 png_set_IHDR( get_struct()
115 , get_info()
116 , static_cast< png_image_width::type >( view.width() )
117 , static_cast< png_image_height::type >( view.height() )
118 , static_cast< png_bitdepth::type >( png_rw_info_t::_bit_depth )
119 , static_cast< png_color_type::type >( png_rw_info_t::_color_type )
120 , _info._interlace_method
121 , _info._compression_type
122 , _info._filter_method
123 );
124
125 #ifdef BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED
126 if( _info._valid_cie_colors )
127 {
128 png_set_cHRM( get_struct()
129 , get_info()
130 , _info._white_x
131 , _info._white_y
132 , _info._red_x
133 , _info._red_y
134 , _info._green_x
135 , _info._green_y
136 , _info._blue_x
137 , _info._blue_y
138 );
139 }
140
141 if( _info._valid_file_gamma )
142 {
143 png_set_gAMA( get_struct()
144 , get_info()
145 , _info._file_gamma
146 );
147 }
148 #else
149 if( _info._valid_cie_colors )
150 {
151 png_set_cHRM_fixed( get_struct()
152 , get_info()
153 , _info._white_x
154 , _info._white_y
155 , _info._red_x
156 , _info._red_y
157 , _info._green_x
158 , _info._green_y
159 , _info._blue_x
160 , _info._blue_y
161 );
162 }
163
164 if( _info._valid_file_gamma )
165 {
166 png_set_gAMA_fixed( get_struct()
167 , get_info()
168 , _info._file_gamma
169 );
170 }
171 #endif // BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED
172
173 if( _info._valid_icc_profile )
174 {
175 #if PNG_LIBPNG_VER_MINOR >= 5
176 png_set_iCCP( get_struct()
177 , get_info()
178 , const_cast< png_charp >( _info._icc_name.c_str() )
179 , _info._iccp_compression_type
180 , reinterpret_cast< png_const_bytep >( & (_info._profile.front ()) )
181 , _info._profile_length
182 );
183 #else
184 png_set_iCCP( get_struct()
185 , get_info()
186 , const_cast< png_charp >( _info._icc_name.c_str() )
187 , _info._iccp_compression_type
188 , const_cast< png_charp >( & (_info._profile.front()) )
189 , _info._profile_length
190 );
191 #endif
192 }
193
194 if( _info._valid_intent )
195 {
196 png_set_sRGB( get_struct()
197 , get_info()
198 , _info._intent
199 );
200 }
201
202 if( _info._valid_palette )
203 {
204 png_set_PLTE( get_struct()
205 , get_info()
206 , const_cast< png_colorp >( &_info._palette.front() )
207 , _info._num_palette
208 );
209 }
210
211 if( _info._valid_background )
212 {
213 png_set_bKGD( get_struct()
214 , get_info()
215 , const_cast< png_color_16p >( &_info._background )
216 );
217 }
218
219 if( _info._valid_histogram )
220 {
221 png_set_hIST( get_struct()
222 , get_info()
223 , const_cast< png_uint_16p >( &_info._histogram.front() )
224 );
225 }
226
227 if( _info._valid_offset )
228 {
229 png_set_oFFs( get_struct()
230 , get_info()
231 , _info._offset_x
232 , _info._offset_y
233 , _info._off_unit_type
234 );
235 }
236
237 if( _info._valid_pixel_calibration )
238 {
239 std::vector< const char* > params( _info._num_params );
240 for( std::size_t i = 0; i < params.size(); ++i )
241 {
242 params[i] = _info._params[ i ].c_str();
243 }
244
245 png_set_pCAL( get_struct()
246 , get_info()
247 , const_cast< png_charp >( _info._purpose.c_str() )
248 , _info._X0
249 , _info._X1
250 , _info._cal_type
251 , _info._num_params
252 , const_cast< png_charp >( _info._units.c_str() )
253 , const_cast< png_charpp >( &params.front() )
254 );
255 }
256
257 if( _info._valid_resolution )
258 {
259 png_set_pHYs( get_struct()
260 , get_info()
261 , _info._res_x
262 , _info._res_y
263 , _info._phy_unit_type
264 );
265 }
266
267 if( _info._valid_significant_bits )
268 {
269 png_set_sBIT( get_struct()
270 , get_info()
271 , const_cast< png_color_8p >( &_info._sig_bits )
272 );
273 }
274
275 #ifndef BOOST_GIL_IO_PNG_1_4_OR_LOWER
276
277 #ifdef BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED
278 if( _info._valid_scale_factors )
279 {
280 png_set_sCAL( get_struct()
281 , get_info()
282 , this->_info._scale_unit
283 , this->_info._scale_width
284 , this->_info._scale_height
285 );
286 }
287 #else
288 #ifdef BOOST_GIL_IO_PNG_FIXED_POINT_SUPPORTED
289 if( _info._valid_scale_factors )
290 {
291 png_set_sCAL_fixed( get_struct()
292 , get_info()
293 , this->_info._scale_unit
294 , this->_info._scale_width
295 , this->_info._scale_height
296 );
297 }
298 #else
299 if( _info._valid_scale_factors )
300 {
301 png_set_sCAL_s( get_struct()
302 , get_info()
303 , this->_info._scale_unit
304 , const_cast< png_charp >( this->_info._scale_width.c_str() )
305 , const_cast< png_charp >( this->_info._scale_height.c_str() )
306 );
307 }
308
309 #endif // BOOST_GIL_IO_PNG_FIXED_POINT_SUPPORTED
310 #endif // BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED
311 #endif // BOOST_GIL_IO_PNG_1_4_OR_LOWER
312
313 if( _info._valid_text )
314 {
315 std::vector< png_text > texts( _info._num_text );
316 for( std::size_t i = 0; i < texts.size(); ++i )
317 {
318 png_text pt;
319 pt.compression = _info._text[i]._compression;
320 pt.key = const_cast< png_charp >( this->_info._text[i]._key.c_str() );
321 pt.text = const_cast< png_charp >( this->_info._text[i]._text.c_str() );
322 pt.text_length = _info._text[i]._text.length();
323
324 texts[i] = pt;
325 }
326
327 png_set_text( get_struct()
328 , get_info()
329 , &texts.front()
330 , _info._num_text
331 );
332 }
333
334 if( _info._valid_modification_time )
335 {
336 png_set_tIME( get_struct()
337 , get_info()
338 , const_cast< png_timep >( &_info._mod_time )
339 );
340 }
341
342 if( _info._valid_transparency_factors )
343 {
344 int sample_max = ( 1u << _info._bit_depth );
345
346 /* libpng doesn't reject a tRNS chunk with out-of-range samples */
347 if( !( ( _info._color_type == PNG_COLOR_TYPE_GRAY
348 && (int) _info._trans_values[0].gray > sample_max
349 )
350 || ( _info._color_type == PNG_COLOR_TYPE_RGB
351 &&( (int) _info._trans_values[0].red > sample_max
352 || (int) _info._trans_values[0].green > sample_max
353 || (int) _info._trans_values[0].blue > sample_max
354 )
355 )
356 )
357 )
358 {
359 //@todo Fix that once reading transparency values works
360 /*
361 png_set_tRNS( get_struct()
362 , get_info()
363 , trans
364 , num_trans
365 , trans_values
366 );
367 */
368 }
369 }
370
371 // Compression Levels - valid values are [0,9]
372 png_set_compression_level( get_struct()
373 , _info._compression_level
374 );
375
376 png_set_compression_mem_level( get_struct()
377 , _info._compression_mem_level
378 );
379
380 png_set_compression_strategy( get_struct()
381 , _info._compression_strategy
382 );
383
384 png_set_compression_window_bits( get_struct()
385 , _info._compression_window_bits
386 );
387
388 png_set_compression_method( get_struct()
389 , _info._compression_method
390 );
391
392 png_set_compression_buffer_size( get_struct()
393 , _info._compression_buffer_size
394 );
395
396 #ifdef BOOST_GIL_IO_PNG_DITHERING_SUPPORTED
397 // Dithering
398 if( _info._set_dithering )
399 {
400 png_set_dither( get_struct()
401 , &_info._dithering_palette.front()
402 , _info._dithering_num_palette
403 , _info._dithering_maximum_colors
404 , &_info._dithering_histogram.front()
405 , _info._full_dither
406 );
407 }
408 #endif // BOOST_GIL_IO_PNG_DITHERING_SUPPORTED
409
410 // Filter
411 if( _info._set_filter )
412 {
413 png_set_filter( get_struct()
414 , 0
415 , _info._filter
416 );
417 }
418
419 // Invert Mono
420 if( _info._invert_mono )
421 {
422 png_set_invert_mono( get_struct() );
423 }
424
425 // True Bits
426 if( _info._set_true_bits )
427 {
428 png_set_sBIT( get_struct()
429 , get_info()
430 , &_info._true_bits.front()
431 );
432 }
433
434 // sRGB Intent
435 if( _info._set_srgb_intent )
436 {
437 png_set_sRGB( get_struct()
438 , get_info()
439 , _info._srgb_intent
440 );
441 }
442
443 // Strip Alpha
444 if( _info._strip_alpha )
445 {
446 png_set_strip_alpha( get_struct() );
447 }
448
449 // Swap Alpha
450 if( _info._swap_alpha )
451 {
452 png_set_swap_alpha( get_struct() );
453 }
454
455
456 png_write_info( get_struct()
457 , get_info()
458 );
459 }
460
461 protected:
462
463 static void write_data( png_structp png_ptr
464 , png_bytep data
465 , png_size_t length
466 )
467 {
468 static_cast< Device* >( png_get_io_ptr( png_ptr ))->write( data
469 , length );
470 }
471
472 static void flush( png_structp png_ptr )
473 {
474 static_cast< Device* >(png_get_io_ptr(png_ptr) )->flush();
475 }
476
477 private:
478
479 void init_io( png_structp png_ptr )
480 {
481 png_set_write_fn( png_ptr
482 , static_cast< void* > ( &this->_io_dev )
483 , static_cast< png_rw_ptr > ( &this_t::write_data )
484 , static_cast< png_flush_ptr >( &this_t::flush )
485 );
486 }
487
488 public:
489
490 Device _io_dev;
491
492 image_write_info< png_tag > _info;
493 };
494
495 #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
496 #pragma warning(pop)
497 #endif
498
499 } // namespace gil
500 } // namespace boost
501
502 #endif