Home | History | Annotate | Download | only in src
      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 "precomp.hpp"
     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 #ifndef _LFS64_LARGEFILE
     55 #  define _LFS64_LARGEFILE 0
     56 #endif
     57 #ifndef _FILE_OFFSET_BITS
     58 #  define _FILE_OFFSET_BITS 0
     59 #endif
     60 
     61 #ifdef HAVE_LIBPNG_PNG_H
     62 #include <libpng/png.h>
     63 #else
     64 #include <png.h>
     65 #endif
     66 #include <zlib.h>
     67 
     68 #include "grfmt_png.hpp"
     69 
     70 #if defined _MSC_VER && _MSC_VER >= 1200
     71     // interaction between '_setjmp' and C++ object destruction is non-portable
     72     #pragma warning( disable: 4611 )
     73 #endif
     74 
     75 // the following defines are a hack to avoid multiple problems with frame ponter handling and setjmp
     76 // see http://gcc.gnu.org/ml/gcc/2011-10/msg00324.html for some details
     77 #define mingw_getsp(...) 0
     78 #define __builtin_frame_address(...) 0
     79 
     80 namespace cv
     81 {
     82 
     83 /////////////////////// PngDecoder ///////////////////
     84 
     85 PngDecoder::PngDecoder()
     86 {
     87     m_signature = "\x89\x50\x4e\x47\xd\xa\x1a\xa";
     88     m_color_type = 0;
     89     m_png_ptr = 0;
     90     m_info_ptr = m_end_info = 0;
     91     m_f = 0;
     92     m_buf_supported = true;
     93     m_buf_pos = 0;
     94 }
     95 
     96 
     97 PngDecoder::~PngDecoder()
     98 {
     99     close();
    100 }
    101 
    102 ImageDecoder PngDecoder::newDecoder() const
    103 {
    104     return makePtr<PngDecoder>();
    105 }
    106 
    107 void  PngDecoder::close()
    108 {
    109     if( m_f )
    110     {
    111         fclose( m_f );
    112         m_f = 0;
    113     }
    114 
    115     if( m_png_ptr )
    116     {
    117         png_structp png_ptr = (png_structp)m_png_ptr;
    118         png_infop info_ptr = (png_infop)m_info_ptr;
    119         png_infop end_info = (png_infop)m_end_info;
    120         png_destroy_read_struct( &png_ptr, &info_ptr, &end_info );
    121         m_png_ptr = m_info_ptr = m_end_info = 0;
    122     }
    123 }
    124 
    125 
    126 void  PngDecoder::readDataFromBuf( void* _png_ptr, uchar* dst, size_t size )
    127 {
    128     png_structp png_ptr = (png_structp)_png_ptr;
    129     PngDecoder* decoder = (PngDecoder*)(png_get_io_ptr(png_ptr));
    130     CV_Assert( decoder );
    131     const Mat& buf = decoder->m_buf;
    132     if( decoder->m_buf_pos + size > buf.cols*buf.rows*buf.elemSize() )
    133     {
    134         png_error(png_ptr, "PNG input buffer is incomplete");
    135         return;
    136     }
    137     memcpy( dst, decoder->m_buf.ptr() + decoder->m_buf_pos, size );
    138     decoder->m_buf_pos += size;
    139 }
    140 
    141 bool  PngDecoder::readHeader()
    142 {
    143     bool result = false;
    144     close();
    145 
    146     png_structp png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, 0, 0, 0 );
    147 
    148     if( png_ptr )
    149     {
    150         png_infop info_ptr = png_create_info_struct( png_ptr );
    151         png_infop end_info = png_create_info_struct( png_ptr );
    152 
    153         m_png_ptr = png_ptr;
    154         m_info_ptr = info_ptr;
    155         m_end_info = end_info;
    156         m_buf_pos = 0;
    157 
    158         if( info_ptr && end_info )
    159         {
    160             if( setjmp( png_jmpbuf( png_ptr ) ) == 0 )
    161             {
    162                 if( !m_buf.empty() )
    163                     png_set_read_fn(png_ptr, this, (png_rw_ptr)readDataFromBuf );
    164                 else
    165                 {
    166                     m_f = fopen( m_filename.c_str(), "rb" );
    167                     if( m_f )
    168                         png_init_io( png_ptr, m_f );
    169                 }
    170 
    171                 if( !m_buf.empty() || m_f )
    172                 {
    173                     png_uint_32 wdth, hght;
    174                     int bit_depth, color_type, num_trans=0;
    175                     png_bytep trans;
    176                     png_color_16p trans_values;
    177 
    178                     png_read_info( png_ptr, info_ptr );
    179 
    180                     png_get_IHDR( png_ptr, info_ptr, &wdth, &hght,
    181                                   &bit_depth, &color_type, 0, 0, 0 );
    182 
    183                     m_width = (int)wdth;
    184                     m_height = (int)hght;
    185                     m_color_type = color_type;
    186                     m_bit_depth = bit_depth;
    187 
    188                     if( bit_depth <= 8 || bit_depth == 16 )
    189                     {
    190                         switch(color_type)
    191                         {
    192                             case PNG_COLOR_TYPE_RGB:
    193                                 m_type = CV_8UC3;
    194                                 break;
    195                             case PNG_COLOR_TYPE_PALETTE:
    196                                 png_get_tRNS( png_ptr, info_ptr, &trans, &num_trans, &trans_values);
    197                                 //Check if there is a transparency value in the palette
    198                                 if ( num_trans > 0 )
    199                                     m_type = CV_8UC4;
    200                                 else
    201                                     m_type = CV_8UC3;
    202                                 break;
    203                             case PNG_COLOR_TYPE_RGB_ALPHA:
    204                                 m_type = CV_8UC4;
    205                                 break;
    206                             default:
    207                                 m_type = CV_8UC1;
    208                         }
    209                         if( bit_depth == 16 )
    210                             m_type = CV_MAKETYPE(CV_16U, CV_MAT_CN(m_type));
    211                         result = true;
    212                     }
    213                 }
    214             }
    215         }
    216     }
    217 
    218     if( !result )
    219         close();
    220 
    221     return result;
    222 }
    223 
    224 
    225 bool  PngDecoder::readData( Mat& img )
    226 {
    227     bool result = false;
    228     AutoBuffer<uchar*> _buffer(m_height);
    229     uchar** buffer = _buffer;
    230     int color = img.channels() > 1;
    231     uchar* data = img.ptr();
    232     int step = (int)img.step;
    233 
    234     if( m_png_ptr && m_info_ptr && m_end_info && m_width && m_height )
    235     {
    236         png_structp png_ptr = (png_structp)m_png_ptr;
    237         png_infop info_ptr = (png_infop)m_info_ptr;
    238         png_infop end_info = (png_infop)m_end_info;
    239 
    240         if( setjmp( png_jmpbuf ( png_ptr ) ) == 0 )
    241         {
    242             int y;
    243 
    244             if( img.depth() == CV_8U && m_bit_depth == 16 )
    245                 png_set_strip_16( png_ptr );
    246             else if( !isBigEndian() )
    247                 png_set_swap( png_ptr );
    248 
    249             if(img.channels() < 4)
    250             {
    251                 /* observation: png_read_image() writes 400 bytes beyond
    252                  * end of data when reading a 400x118 color png
    253                  * "mpplus_sand.png".  OpenCV crashes even with demo
    254                  * programs.  Looking at the loaded image I'd say we get 4
    255                  * bytes per pixel instead of 3 bytes per pixel.  Test
    256                  * indicate that it is a good idea to always ask for
    257                  * stripping alpha..  18.11.2004 Axel Walthelm
    258                  */
    259                  png_set_strip_alpha( png_ptr );
    260             }
    261 
    262             if( m_color_type == PNG_COLOR_TYPE_PALETTE )
    263                 png_set_palette_to_rgb( png_ptr );
    264 
    265             if( m_color_type == PNG_COLOR_TYPE_GRAY && m_bit_depth < 8 )
    266 #if (PNG_LIBPNG_VER_MAJOR*10000 + PNG_LIBPNG_VER_MINOR*100 + PNG_LIBPNG_VER_RELEASE >= 10209) || \
    267     (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR == 0 && PNG_LIBPNG_VER_RELEASE >= 18)
    268                 png_set_expand_gray_1_2_4_to_8( png_ptr );
    269 #else
    270                 png_set_gray_1_2_4_to_8( png_ptr );
    271 #endif
    272 
    273             if( CV_MAT_CN(m_type) > 1 && color )
    274                 png_set_bgr( png_ptr ); // convert RGB to BGR
    275             else if( color )
    276                 png_set_gray_to_rgb( png_ptr ); // Gray->RGB
    277             else
    278                 png_set_rgb_to_gray( png_ptr, 1, 0.299, 0.587 ); // RGB->Gray
    279 
    280             png_set_interlace_handling( png_ptr );
    281             png_read_update_info( png_ptr, info_ptr );
    282 
    283             for( y = 0; y < m_height; y++ )
    284                 buffer[y] = data + y*step;
    285 
    286             png_read_image( png_ptr, buffer );
    287             png_read_end( png_ptr, end_info );
    288 
    289             result = true;
    290         }
    291     }
    292 
    293     close();
    294     return result;
    295 }
    296 
    297 
    298 /////////////////////// PngEncoder ///////////////////
    299 
    300 
    301 PngEncoder::PngEncoder()
    302 {
    303     m_description = "Portable Network Graphics files (*.png)";
    304     m_buf_supported = true;
    305 }
    306 
    307 
    308 PngEncoder::~PngEncoder()
    309 {
    310 }
    311 
    312 
    313 bool  PngEncoder::isFormatSupported( int depth ) const
    314 {
    315     return depth == CV_8U || depth == CV_16U;
    316 }
    317 
    318 ImageEncoder PngEncoder::newEncoder() const
    319 {
    320     return makePtr<PngEncoder>();
    321 }
    322 
    323 
    324 void PngEncoder::writeDataToBuf(void* _png_ptr, uchar* src, size_t size)
    325 {
    326     if( size == 0 )
    327         return;
    328     png_structp png_ptr = (png_structp)_png_ptr;
    329     PngEncoder* encoder = (PngEncoder*)(png_get_io_ptr(png_ptr));
    330     CV_Assert( encoder && encoder->m_buf );
    331     size_t cursz = encoder->m_buf->size();
    332     encoder->m_buf->resize(cursz + size);
    333     memcpy( &(*encoder->m_buf)[cursz], src, size );
    334 }
    335 
    336 
    337 void PngEncoder::flushBuf(void*)
    338 {
    339 }
    340 
    341 bool  PngEncoder::write( const Mat& img, const std::vector<int>& params )
    342 {
    343     png_structp png_ptr = png_create_write_struct( PNG_LIBPNG_VER_STRING, 0, 0, 0 );
    344     png_infop info_ptr = 0;
    345     FILE* f = 0;
    346     int y, width = img.cols, height = img.rows;
    347     int depth = img.depth(), channels = img.channels();
    348     bool result = false;
    349     AutoBuffer<uchar*> buffer;
    350 
    351     if( depth != CV_8U && depth != CV_16U )
    352         return false;
    353 
    354     if( png_ptr )
    355     {
    356         info_ptr = png_create_info_struct( png_ptr );
    357 
    358         if( info_ptr )
    359         {
    360             if( setjmp( png_jmpbuf ( png_ptr ) ) == 0 )
    361             {
    362                 if( m_buf )
    363                 {
    364                     png_set_write_fn(png_ptr, this,
    365                         (png_rw_ptr)writeDataToBuf, (png_flush_ptr)flushBuf);
    366                 }
    367                 else
    368                 {
    369                     f = fopen( m_filename.c_str(), "wb" );
    370                     if( f )
    371                         png_init_io( png_ptr, f );
    372                 }
    373 
    374                 int compression_level = -1; // Invalid value to allow setting 0-9 as valid
    375                 int compression_strategy = Z_RLE; // Default strategy
    376                 bool isBilevel = false;
    377 
    378                 for( size_t i = 0; i < params.size(); i += 2 )
    379                 {
    380                     if( params[i] == CV_IMWRITE_PNG_COMPRESSION )
    381                     {
    382                         compression_level = params[i+1];
    383                         compression_level = MIN(MAX(compression_level, 0), Z_BEST_COMPRESSION);
    384                     }
    385                     if( params[i] == CV_IMWRITE_PNG_STRATEGY )
    386                     {
    387                         compression_strategy = params[i+1];
    388                         compression_strategy = MIN(MAX(compression_strategy, 0), Z_FIXED);
    389                     }
    390                     if( params[i] == CV_IMWRITE_PNG_BILEVEL )
    391                     {
    392                         isBilevel = params[i+1] != 0;
    393                     }
    394                 }
    395 
    396                 if( m_buf || f )
    397                 {
    398                     if( compression_level >= 0 )
    399                     {
    400                         png_set_compression_level( png_ptr, compression_level );
    401                     }
    402                     else
    403                     {
    404                         // tune parameters for speed
    405                         // (see http://wiki.linuxquestions.org/wiki/Libpng)
    406                         png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, PNG_FILTER_SUB);
    407                         png_set_compression_level(png_ptr, Z_BEST_SPEED);
    408                     }
    409                     png_set_compression_strategy(png_ptr, compression_strategy);
    410 
    411                     png_set_IHDR( png_ptr, info_ptr, width, height, depth == CV_8U ? isBilevel?1:8 : 16,
    412                         channels == 1 ? PNG_COLOR_TYPE_GRAY :
    413                         channels == 3 ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGBA,
    414                         PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
    415                         PNG_FILTER_TYPE_DEFAULT );
    416 
    417                     png_write_info( png_ptr, info_ptr );
    418 
    419                     if (isBilevel)
    420                         png_set_packing(png_ptr);
    421 
    422                     png_set_bgr( png_ptr );
    423                     if( !isBigEndian() )
    424                         png_set_swap( png_ptr );
    425 
    426                     buffer.allocate(height);
    427                     for( y = 0; y < height; y++ )
    428                         buffer[y] = img.data + y*img.step;
    429 
    430                     png_write_image( png_ptr, buffer );
    431                     png_write_end( png_ptr, info_ptr );
    432 
    433                     result = true;
    434                 }
    435             }
    436         }
    437     }
    438 
    439     png_destroy_write_struct( &png_ptr, &info_ptr );
    440     if(f) fclose( f );
    441 
    442     return result;
    443 }
    444 
    445 }
    446 
    447 #endif
    448 
    449 /* End of file. */
    450