Update to 2.0.0 tree from current Fremantle build
[opencv] / src / highgui / grfmt_png.cpp
1 /*M///////////////////////////////////////////////////////////////////////////////////////
2 //
3 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4 //
5 //  By downloading, copying, installing or using the software you agree to this license.
6 //  If you do not agree to this license, do not download, install,
7 //  copy or use the software.
8 //
9 //
10 //                           License Agreement
11 //                For Open Source Computer Vision Library
12 //
13 // Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
14 // Copyright (C) 2009, Willow Garage Inc., all rights reserved.
15 // Third party copyrights are property of their respective owners.
16 //
17 // Redistribution and use in source and binary forms, with or without modification,
18 // are permitted provided that the following conditions are met:
19 //
20 //   * Redistribution's of source code must retain the above copyright notice,
21 //     this list of conditions and the following disclaimer.
22 //
23 //   * Redistribution's in binary form must reproduce the above copyright notice,
24 //     this list of conditions and the following disclaimer in the documentation
25 //     and/or other materials provided with the distribution.
26 //
27 //   * The name of the copyright holders may not be used to endorse or promote products
28 //     derived from this software without specific prior written permission.
29 //
30 // This software is provided by the copyright holders and contributors "as is" and
31 // any express or implied warranties, including, but not limited to, the implied
32 // warranties of merchantability and fitness for a particular purpose are disclaimed.
33 // In no event shall the Intel Corporation or contributors be liable for any direct,
34 // indirect, incidental, special, exemplary, or consequential damages
35 // (including, but not limited to, procurement of substitute goods or services;
36 // loss of use, data, or profits; or business interruption) however caused
37 // and on any theory of liability, whether in contract, strict liability,
38 // or tort (including negligence or otherwise) arising in any way out of
39 // the use of this software, even if advised of the possibility of such damage.
40 //
41 //M*/
42
43 #include "_highgui.h"
44
45 #ifdef HAVE_PNG
46
47 /****************************************************************************************\
48     This part of the file implements PNG codec on base of libpng library,
49     in particular, this code is based on example.c from libpng
50     (see otherlibs/_graphics/readme.txt for copyright notice)
51     and png2bmp sample from libpng distribution (Copyright (C) 1999-2001 MIYASAKA Masaru)
52 \****************************************************************************************/
53
54 #ifdef HAVE_LIBPNG_PNG_H
55 #include <libpng/png.h>
56 #else
57 #include <png.h>
58 #endif
59 #include "grfmt_png.h"
60
61 namespace cv
62 {
63
64 /////////////////////// PngDecoder ///////////////////
65
66 PngDecoder::PngDecoder()
67 {
68     m_signature = "\x89\x50\x4e\x47\xd\xa\x1a\xa";
69     m_color_type = 0;
70     m_png_ptr = 0;
71     m_info_ptr = m_end_info = 0;
72     m_f = 0;
73     m_buf_supported = true;
74     m_buf_pos = 0;
75 }
76
77
78 PngDecoder::~PngDecoder()
79 {
80     close();
81 }
82
83 ImageDecoder PngDecoder::newDecoder() const
84 {
85     return new PngDecoder;
86 }
87
88 void  PngDecoder::close()
89 {
90     if( m_f )
91     {
92         fclose( m_f );
93         m_f = 0;
94     }
95
96     if( m_png_ptr )
97     {
98         png_structp png_ptr = (png_structp)m_png_ptr;
99         png_infop info_ptr = (png_infop)m_info_ptr;
100         png_infop end_info = (png_infop)m_end_info;
101         png_destroy_read_struct( &png_ptr, &info_ptr, &end_info );
102         m_png_ptr = m_info_ptr = m_end_info = 0;
103     }
104 }
105
106
107 void  PngDecoder::readDataFromBuf( void* _png_ptr, uchar* dst, size_t size )
108 {
109     png_structp png_ptr = (png_structp)_png_ptr;
110     PngDecoder* decoder = (PngDecoder*)(png_ptr->io_ptr);
111     CV_Assert( decoder );
112     const Mat& buf = decoder->m_buf;
113     if( decoder->m_buf_pos + size > buf.cols*buf.rows*buf.elemSize() )
114     {
115         png_error(png_ptr, "PNG input buffer is incomplete");
116         return;
117     }
118     memcpy( dst, &decoder->m_buf.data[decoder->m_buf_pos], size );
119     decoder->m_buf_pos += size;
120 }
121
122 bool  PngDecoder::readHeader()
123 {
124     bool result = false;
125     close();
126
127     png_structp png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, 0, 0, 0 );
128
129     if( png_ptr )
130     {
131         png_infop info_ptr = png_create_info_struct( png_ptr );
132         png_infop end_info = png_create_info_struct( png_ptr );
133
134         m_png_ptr = png_ptr;
135         m_info_ptr = info_ptr;
136         m_end_info = end_info;
137         m_buf_pos = 0;
138
139         if( info_ptr && end_info )
140         {
141             if( setjmp( png_ptr->jmpbuf ) == 0 )
142             {
143                 if( !m_buf.empty() )
144                     png_set_read_fn(png_ptr, this, (png_rw_ptr)readDataFromBuf );
145                 else
146                 {
147                     m_f = fopen( m_filename.c_str(), "rb" );
148                     if( m_f )
149                         png_init_io( png_ptr, m_f );
150                 }
151
152                 if( !m_buf.empty() || m_f )
153                 {
154                     png_uint_32 width, height;
155                     int bit_depth, color_type;
156
157                     png_read_info( png_ptr, info_ptr );
158
159                     png_get_IHDR( png_ptr, info_ptr, &width, &height,
160                                   &bit_depth, &color_type, 0, 0, 0 );
161
162                     m_width = (int)width;
163                     m_height = (int)height;
164                     m_color_type = color_type;
165                     m_bit_depth = bit_depth;
166
167                     if( bit_depth <= 8 || bit_depth == 16 )
168                     {
169                         m_type = color_type == PNG_COLOR_TYPE_RGB ||
170                              color_type == PNG_COLOR_TYPE_RGB_ALPHA ||
171                              color_type == PNG_COLOR_TYPE_PALETTE ? CV_8UC3 : CV_8UC1;
172                         if( bit_depth == 16 )
173                             m_type = CV_MAKETYPE(CV_16U, CV_MAT_CN(m_type));
174                         result = true;
175                     }
176                 }
177             }
178         }
179     }
180
181     if( !result )
182         close();
183
184     return result;
185 }
186
187
188 bool  PngDecoder::readData( Mat& img )
189 {
190     bool result = false;
191     AutoBuffer<uchar*> _buffer(m_height);
192     uchar** buffer = _buffer;
193     int color = img.channels() > 1;
194     uchar* data = img.data;
195     int step = img.step;
196
197     if( m_png_ptr && m_info_ptr && m_end_info && m_width && m_height )
198     {
199         png_structp png_ptr = (png_structp)m_png_ptr;
200         png_infop info_ptr = (png_infop)m_info_ptr;
201         png_infop end_info = (png_infop)m_end_info;
202
203         if( setjmp(png_ptr->jmpbuf) == 0 )
204         {
205             int y;
206
207             if( img.depth() == CV_8U && m_bit_depth == 16 )
208                 png_set_strip_16( png_ptr );
209             else if( !isBigEndian() )
210                 png_set_swap( png_ptr );
211
212             /* observation: png_read_image() writes 400 bytes beyond
213              * end of data when reading a 400x118 color png
214              * "mpplus_sand.png".  OpenCV crashes even with demo
215              * programs.  Looking at the loaded image I'd say we get 4
216              * bytes per pixel instead of 3 bytes per pixel.  Test
217              * indicate that it is a good idea to always ask for
218              * stripping alpha..  18.11.2004 Axel Walthelm
219              */
220             png_set_strip_alpha( png_ptr );
221
222             if( m_color_type == PNG_COLOR_TYPE_PALETTE )
223                 png_set_palette_to_rgb( png_ptr );
224
225             if( m_color_type == PNG_COLOR_TYPE_GRAY && m_bit_depth < 8 )
226                 png_set_gray_1_2_4_to_8( png_ptr );
227
228             if( CV_MAT_CN(m_type) > 1 && color )
229                 png_set_bgr( png_ptr ); // convert RGB to BGR
230             else if( color )
231                 png_set_gray_to_rgb( png_ptr ); // Gray->RGB
232             else
233                 png_set_rgb_to_gray( png_ptr, 1, -1, -1 ); // RGB->Gray
234
235             png_read_update_info( png_ptr, info_ptr );
236
237             for( y = 0; y < m_height; y++ )
238                 buffer[y] = data + y*step;
239
240             png_read_image( png_ptr, buffer );
241             png_read_end( png_ptr, end_info );
242
243             result = true;
244         }
245     }
246
247     close();
248     return result;
249 }
250
251
252 /////////////////////// PngEncoder ///////////////////
253
254
255 PngEncoder::PngEncoder()
256 {
257     m_description = "Portable Network Graphics files (*.png)";
258     m_buf_supported = true;
259 }
260
261
262 PngEncoder::~PngEncoder()
263 {
264 }
265
266
267 bool  PngEncoder::isFormatSupported( int depth ) const
268 {
269     return depth == CV_8U || depth == CV_16U;
270 }
271
272 ImageEncoder PngEncoder::newEncoder() const
273 {
274     return new PngEncoder;
275 }
276
277
278 void PngEncoder::writeDataToBuf(void* _png_ptr, uchar* src, size_t size)
279 {
280     if( size == 0 )
281         return;
282     png_structp png_ptr = (png_structp)_png_ptr;
283     PngEncoder* encoder = (PngEncoder*)(png_ptr->io_ptr);
284     CV_Assert( encoder && encoder->m_buf );
285     size_t cursz = encoder->m_buf->size();
286     encoder->m_buf->resize(cursz + size);
287     memcpy( &(*encoder->m_buf)[cursz], src, size );
288 }
289
290
291 void PngEncoder::flushBuf(void*)
292 {
293 }
294
295 bool  PngEncoder::write( const Mat& img, const vector<int>& params )
296 {
297     int compression_level = 0;
298
299     for( size_t i = 0; i < params.size(); i += 2 )
300     {
301         if( params[i] == CV_IMWRITE_PNG_COMPRESSION )
302         {
303             compression_level = params[i+1];
304             compression_level = MIN(MAX(compression_level, 0), MAX_MEM_LEVEL);
305         }
306     }
307
308     png_structp png_ptr = png_create_write_struct( PNG_LIBPNG_VER_STRING, 0, 0, 0 );
309     png_infop info_ptr = 0;
310     FILE* f = 0;
311     int y, width = img.cols, height = img.rows;
312     int depth = img.depth(), channels = img.channels();
313     bool result = false;
314     AutoBuffer<uchar*> buffer;
315
316     if( depth != CV_8U && depth != CV_16U )
317         return false;
318
319     if( png_ptr )
320     {
321         info_ptr = png_create_info_struct( png_ptr );
322
323         if( info_ptr )
324         {
325             if( setjmp( png_ptr->jmpbuf ) == 0 )
326             {
327                 if( m_buf )
328                 {
329                     png_set_write_fn(png_ptr, this,
330                         (png_rw_ptr)writeDataToBuf, (png_flush_ptr)flushBuf);
331                 }
332                 else
333                 {
334                     f = fopen( m_filename.c_str(), "wb" );
335                     if( f )
336                         png_init_io( png_ptr, f );
337                 }
338
339                 if( m_buf || f )
340                 {
341                     if( compression_level > 0 )
342                     {
343                         png_set_compression_mem_level( png_ptr, compression_level );
344                     }
345                     else
346                     {
347                         // tune parameters for speed
348                         // (see http://wiki.linuxquestions.org/wiki/Libpng)
349                         png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, PNG_FILTER_SUB);
350                         png_set_compression_level(png_ptr, Z_BEST_SPEED);
351                     }
352                     png_set_compression_strategy(png_ptr, Z_HUFFMAN_ONLY);
353
354                     png_set_IHDR( png_ptr, info_ptr, width, height, depth == CV_8U ? 8 : 16,
355                         channels == 1 ? PNG_COLOR_TYPE_GRAY :
356                         channels == 3 ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGBA,
357                         PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
358                         PNG_FILTER_TYPE_DEFAULT );
359
360                     png_write_info( png_ptr, info_ptr );
361
362                     png_set_bgr( png_ptr );
363                     if( !isBigEndian() )
364                         png_set_swap( png_ptr );
365
366                     buffer.allocate(height);
367                     for( y = 0; y < height; y++ )
368                         buffer[y] = img.data + y*img.step;
369
370                     png_write_image( png_ptr, buffer );
371                     png_write_end( png_ptr, info_ptr );
372
373                     result = true;
374                 }
375             }
376         }
377     }
378
379     png_destroy_write_struct( &png_ptr, &info_ptr );
380     if(f) fclose( f );
381
382     return result;
383 }
384
385 }
386
387 #endif
388
389 /* End of file. */