better png transparency handling

pull/5987/head
thierry 9 years ago
parent cb0b2bd1af
commit 1b5352688f
  1. 27
      modules/imgcodecs/src/grfmt_png.cpp
  2. 5
      modules/imgcodecs/src/loadsave.cpp

@ -187,15 +187,12 @@ bool PngDecoder::readHeader()
if( bit_depth <= 8 || bit_depth == 16 ) if( bit_depth <= 8 || bit_depth == 16 )
{ {
png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, &trans_values);
switch(color_type) switch(color_type)
{ {
case PNG_COLOR_TYPE_RGB: case PNG_COLOR_TYPE_RGB:
m_type = CV_8UC3;
break;
case PNG_COLOR_TYPE_PALETTE: case PNG_COLOR_TYPE_PALETTE:
png_get_tRNS( png_ptr, info_ptr, &trans, &num_trans, &trans_values); if( num_trans > 0 )
//Check if there is a transparency value in the palette
if ( num_trans > 0 )
m_type = CV_8UC4; m_type = CV_8UC4;
else else
m_type = CV_8UC3; m_type = CV_8UC3;
@ -203,8 +200,14 @@ bool PngDecoder::readHeader()
case PNG_COLOR_TYPE_RGB_ALPHA: case PNG_COLOR_TYPE_RGB_ALPHA:
m_type = CV_8UC4; m_type = CV_8UC4;
break; break;
case PNG_COLOR_TYPE_GRAY_ALPHA:
m_type = CV_8UC2;
break;
default: default:
m_type = CV_8UC1; if( num_trans > 0 )
m_type = CV_8UC2;
else
m_type = CV_8UC1;
} }
if( bit_depth == 16 ) if( bit_depth == 16 )
m_type = CV_MAKETYPE(CV_16U, CV_MAT_CN(m_type)); m_type = CV_MAKETYPE(CV_16U, CV_MAT_CN(m_type));
@ -227,7 +230,7 @@ bool PngDecoder::readData( Mat& img )
volatile bool result = false; volatile bool result = false;
AutoBuffer<uchar*> _buffer(m_height); AutoBuffer<uchar*> _buffer(m_height);
uchar** buffer = _buffer; uchar** buffer = _buffer;
int color = img.channels() > 1; int color = img.channels() > 2;
uchar* data = img.ptr(); uchar* data = img.ptr();
int step = (int)img.step; int step = (int)img.step;
@ -246,7 +249,7 @@ bool PngDecoder::readData( Mat& img )
else if( !isBigEndian() ) else if( !isBigEndian() )
png_set_swap( png_ptr ); png_set_swap( png_ptr );
if(img.channels() < 4) if(img.channels() != 4 && img.channels() != 2)
{ {
/* observation: png_read_image() writes 400 bytes beyond /* observation: png_read_image() writes 400 bytes beyond
* end of data when reading a 400x118 color png * end of data when reading a 400x118 color png
@ -257,12 +260,13 @@ bool PngDecoder::readData( Mat& img )
* stripping alpha.. 18.11.2004 Axel Walthelm * stripping alpha.. 18.11.2004 Axel Walthelm
*/ */
png_set_strip_alpha( png_ptr ); png_set_strip_alpha( png_ptr );
} } else
png_set_tRNS_to_alpha( png_ptr );
if( m_color_type == PNG_COLOR_TYPE_PALETTE ) if( m_color_type == PNG_COLOR_TYPE_PALETTE )
png_set_palette_to_rgb( png_ptr ); png_set_palette_to_rgb( png_ptr );
if( m_color_type == PNG_COLOR_TYPE_GRAY && m_bit_depth < 8 ) if( (m_color_type & PNG_COLOR_MASK_COLOR) != 0 && m_bit_depth < 8 )
#if (PNG_LIBPNG_VER_MAJOR*10000 + PNG_LIBPNG_VER_MINOR*100 + PNG_LIBPNG_VER_RELEASE >= 10209) || \ #if (PNG_LIBPNG_VER_MAJOR*10000 + PNG_LIBPNG_VER_MINOR*100 + PNG_LIBPNG_VER_RELEASE >= 10209) || \
(PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR == 0 && PNG_LIBPNG_VER_RELEASE >= 18) (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR == 0 && PNG_LIBPNG_VER_RELEASE >= 18)
png_set_expand_gray_1_2_4_to_8( png_ptr ); png_set_expand_gray_1_2_4_to_8( png_ptr );
@ -270,7 +274,7 @@ bool PngDecoder::readData( Mat& img )
png_set_gray_1_2_4_to_8( png_ptr ); png_set_gray_1_2_4_to_8( png_ptr );
#endif #endif
if( CV_MAT_CN(m_type) > 1 && color ) if( CV_MAT_CN(m_type) > 2 && color )
png_set_bgr( png_ptr ); // convert RGB to BGR png_set_bgr( png_ptr ); // convert RGB to BGR
else if( color ) else if( color )
png_set_gray_to_rgb( png_ptr ); // Gray->RGB png_set_gray_to_rgb( png_ptr ); // Gray->RGB
@ -410,6 +414,7 @@ bool PngEncoder::write( const Mat& img, const std::vector<int>& params )
png_set_IHDR( png_ptr, info_ptr, width, height, depth == CV_8U ? isBilevel?1:8 : 16, png_set_IHDR( png_ptr, info_ptr, width, height, depth == CV_8U ? isBilevel?1:8 : 16,
channels == 1 ? PNG_COLOR_TYPE_GRAY : channels == 1 ? PNG_COLOR_TYPE_GRAY :
channels == 2 ? PNG_COLOR_TYPE_GRAY_ALPHA :
channels == 3 ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGBA, channels == 3 ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGBA,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT ); PNG_FILTER_TYPE_DEFAULT );

@ -452,8 +452,6 @@ static bool imwrite_( const String& filename, const Mat& image,
Mat temp; Mat temp;
const Mat* pimage = &image; const Mat* pimage = &image;
CV_Assert( image.channels() == 1 || image.channels() == 3 || image.channels() == 4 );
ImageEncoder encoder = findEncoder( filename ); ImageEncoder encoder = findEncoder( filename );
if( !encoder ) if( !encoder )
CV_Error( CV_StsError, "could not find a writer for the specified extension" ); CV_Error( CV_StsError, "could not find a writer for the specified extension" );
@ -590,9 +588,6 @@ bool imencode( const String& ext, InputArray _image,
{ {
Mat image = _image.getMat(); Mat image = _image.getMat();
int channels = image.channels();
CV_Assert( channels == 1 || channels == 3 || channels == 4 );
ImageEncoder encoder = findEncoder( ext ); ImageEncoder encoder = findEncoder( ext );
if( !encoder ) if( !encoder )
CV_Error( CV_StsError, "could not find encoder for the specified extension" ); CV_Error( CV_StsError, "could not find encoder for the specified extension" );

Loading…
Cancel
Save