diff --git a/modules/imgcodecs/src/grfmt_png.cpp b/modules/imgcodecs/src/grfmt_png.cpp index 4ecf32cd4c..a2ea54b414 100644 --- a/modules/imgcodecs/src/grfmt_png.cpp +++ b/modules/imgcodecs/src/grfmt_png.cpp @@ -181,8 +181,6 @@ PngDecoder::PngDecoder() { m_signature = "\x89\x50\x4e\x47\xd\xa\x1a\xa"; m_color_type = 0; - m_png_ptr = nullptr; - m_info_ptr = m_end_info = nullptr; m_f = 0; m_buf_supported = true; m_buf_pos = 0; @@ -205,15 +203,6 @@ PngDecoder::~PngDecoder() fclose( m_f ); m_f = nullptr; } - - if( m_png_ptr ) - { - png_structp png_ptr = (png_structp)m_png_ptr; - png_infop info_ptr = (png_infop)m_info_ptr; - png_infop end_info = (png_infop)m_end_info; - png_destroy_read_struct( &png_ptr, &info_ptr, &end_info ); - m_png_ptr = m_info_ptr = m_end_info = nullptr; - } } ImageDecoder PngDecoder::newDecoder() const @@ -240,164 +229,149 @@ bool PngDecoder::readHeader() { volatile bool result = false; - png_structp png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, 0, 0, 0 ); - png_infop info_ptr = nullptr; - png_infop end_info = nullptr; + PngPtrs png_ptrs; + png_structp png_ptr = png_ptrs.getPng(); + png_infop info_ptr = png_ptrs.getInfo(); + png_infop end_info = png_ptrs.getEndInfo(); - if( png_ptr ) + if( png_ptr && info_ptr && end_info ) { - info_ptr = png_create_info_struct( png_ptr ); - end_info = png_create_info_struct( png_ptr ); - m_buf_pos = 0; - - if( info_ptr && end_info ) + if( setjmp( png_jmpbuf( png_ptr ) ) == 0 ) { - if( setjmp( png_jmpbuf( png_ptr ) ) == 0 ) + unsigned char sig[8]; + uint32_t id = 0; + Chunk chunk; + + if( !m_buf.empty() ) + png_set_read_fn(png_ptr, this, (png_rw_ptr)readDataFromBuf ); + else { - unsigned char sig[8]; - uint32_t id = 0; - Chunk chunk; - - if( !m_buf.empty() ) - png_set_read_fn(png_ptr, this, (png_rw_ptr)readDataFromBuf ); - else + m_f = fopen(m_filename.c_str(), "rb"); + if (!m_f) { - m_f = fopen(m_filename.c_str(), "rb"); - if (!m_f) - { - png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); - return false; - } - png_init_io(png_ptr, m_f); - - if (fread(sig, 1, 8, m_f)) - id = read_chunk(m_chunkIHDR); + return false; } + png_init_io(png_ptr, m_f); - if (id != id_IHDR) - { - read_from_io(&sig, 8, 1); + if (fread(sig, 1, 8, m_f)) id = read_chunk(m_chunkIHDR); - } + } - if (!(id == id_IHDR && m_chunkIHDR.p.size() == 25)) + if (id != id_IHDR) + { + read_from_io(&sig, 8, 1); + id = read_chunk(m_chunkIHDR); + } + + if (!(id == id_IHDR && m_chunkIHDR.p.size() == 25)) + { + return false; + } + + while (true) + { + m_is_fcTL_loaded = false; + id = read_chunk(chunk); + + if ((m_f && feof(m_f)) || (!m_buf.empty() && m_buf_pos > m_buf.total())) { - png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); return false; } - while (true) + if (id == id_IDAT) { - m_is_fcTL_loaded = false; - id = read_chunk(chunk); - - if ((m_f && feof(m_f)) || (!m_buf.empty() && m_buf_pos > m_buf.total())) - { - png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); - return false; - } - - if (id == id_IDAT) - { - if (m_f) - fseek(m_f, 0, SEEK_SET); - else - m_buf_pos = 0; - break; - } - - if (id == id_acTL && chunk.p.size() == 20) - { - m_animation.loop_count = png_get_uint_32(&chunk.p[12]); - - if (chunk.p[8] > 0) - { - chunk.p[8] = 0; - chunk.p[9] = 0; - m_frame_count = png_get_uint_32(&chunk.p[8]); - m_frame_count++; - } - else - m_frame_count = png_get_uint_32(&chunk.p[8]); - } - - if (id == id_fcTL) - { - m_is_fcTL_loaded = true; - w0 = png_get_uint_32(&chunk.p[12]); - h0 = png_get_uint_32(&chunk.p[16]); - x0 = png_get_uint_32(&chunk.p[20]); - y0 = png_get_uint_32(&chunk.p[24]); - delay_num = png_get_uint_16(&chunk.p[28]); - delay_den = png_get_uint_16(&chunk.p[30]); - dop = chunk.p[32]; - bop = chunk.p[33]; - } - - if (id == id_bKGD) - { - int bgcolor = png_get_uint_32(&chunk.p[8]); - m_animation.bgcolor[3] = (bgcolor >> 24) & 0xFF; - m_animation.bgcolor[2] = (bgcolor >> 16) & 0xFF; - m_animation.bgcolor[1] = (bgcolor >> 8) & 0xFF; - m_animation.bgcolor[0] = bgcolor & 0xFF; - } - - if (id == id_PLTE || id == id_tRNS) - m_chunksInfo.push_back(chunk); + if (m_f) + fseek(m_f, 0, SEEK_SET); + else + m_buf_pos = 0; + break; } - png_uint_32 wdth, hght; - int bit_depth, color_type, num_trans=0; - png_bytep trans; - png_color_16p trans_values; - - png_read_info( png_ptr, info_ptr ); - png_get_IHDR(png_ptr, info_ptr, &wdth, &hght, - &bit_depth, &color_type, 0, 0, 0); - - m_width = (int)wdth; - m_height = (int)hght; - m_color_type = color_type; - m_bit_depth = bit_depth; - - if (bit_depth <= 8 || bit_depth == 16) + if (id == id_acTL && chunk.p.size() == 20) { - switch (color_type) + m_animation.loop_count = png_get_uint_32(&chunk.p[12]); + + if (chunk.p[8] > 0) { - case PNG_COLOR_TYPE_RGB: - case PNG_COLOR_TYPE_PALETTE: - png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, &trans_values); - if (num_trans > 0) - m_type = CV_8UC4; - else - m_type = CV_8UC3; - break; - case PNG_COLOR_TYPE_GRAY_ALPHA: - case PNG_COLOR_TYPE_RGB_ALPHA: + chunk.p[8] = 0; + chunk.p[9] = 0; + m_frame_count = png_get_uint_32(&chunk.p[8]); + m_frame_count++; + } + else + m_frame_count = png_get_uint_32(&chunk.p[8]); + } + + if (id == id_fcTL) + { + m_is_fcTL_loaded = true; + w0 = png_get_uint_32(&chunk.p[12]); + h0 = png_get_uint_32(&chunk.p[16]); + x0 = png_get_uint_32(&chunk.p[20]); + y0 = png_get_uint_32(&chunk.p[24]); + delay_num = png_get_uint_16(&chunk.p[28]); + delay_den = png_get_uint_16(&chunk.p[30]); + dop = chunk.p[32]; + bop = chunk.p[33]; + } + + if (id == id_bKGD) + { + int bgcolor = png_get_uint_32(&chunk.p[8]); + m_animation.bgcolor[3] = (bgcolor >> 24) & 0xFF; + m_animation.bgcolor[2] = (bgcolor >> 16) & 0xFF; + m_animation.bgcolor[1] = (bgcolor >> 8) & 0xFF; + m_animation.bgcolor[0] = bgcolor & 0xFF; + } + + if (id == id_PLTE || id == id_tRNS) + m_chunksInfo.push_back(chunk); + } + + png_uint_32 wdth, hght; + int bit_depth, color_type, num_trans=0; + png_bytep trans; + png_color_16p trans_values; + + png_read_info( png_ptr, info_ptr ); + png_get_IHDR(png_ptr, info_ptr, &wdth, &hght, + &bit_depth, &color_type, 0, 0, 0); + + m_width = (int)wdth; + m_height = (int)hght; + m_color_type = color_type; + m_bit_depth = bit_depth; + + if (bit_depth <= 8 || bit_depth == 16) + { + switch (color_type) + { + case PNG_COLOR_TYPE_RGB: + case PNG_COLOR_TYPE_PALETTE: + png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, &trans_values); + if (num_trans > 0) m_type = CV_8UC4; - break; - default: - m_type = CV_8UC1; - } - if (bit_depth == 16) - m_type = CV_MAKETYPE(CV_16U, CV_MAT_CN(m_type)); - result = true; + else + m_type = CV_8UC3; + break; + case PNG_COLOR_TYPE_GRAY_ALPHA: + case PNG_COLOR_TYPE_RGB_ALPHA: + m_type = CV_8UC4; + break; + default: + m_type = CV_8UC1; } + if (bit_depth == 16) + m_type = CV_MAKETYPE(CV_16U, CV_MAT_CN(m_type)); + result = true; } } } if(result) { - m_png_ptr = png_ptr; - m_info_ptr = info_ptr; - m_end_info = end_info; - } - else - { - png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); + m_png_ptrs = std::move(png_ptrs); } return result; @@ -430,8 +404,8 @@ bool PngDecoder::readData( Mat& img ) frameCur.setMat(mat_cur); processing_start((void*)&frameRaw, mat_cur); - png_structp png_ptr = (png_structp)m_png_ptr; - png_infop info_ptr = (png_infop)m_info_ptr; + png_structp png_ptr = m_png_ptrs.getPng(); + png_infop info_ptr = m_png_ptrs.getInfo(); while (true) { @@ -540,11 +514,11 @@ bool PngDecoder::readData( Mat& img ) unsigned char** buffer = _buffer.data(); bool color = img.channels() > 1; - png_structp png_ptr = (png_structp)m_png_ptr; - png_infop info_ptr = (png_infop)m_info_ptr; - png_infop end_info = (png_infop)m_end_info; + png_structp png_ptr = m_png_ptrs.getPng(); + png_infop info_ptr = m_png_ptrs.getInfo(); + png_infop end_info = m_png_ptrs.getEndInfo(); - if( m_png_ptr && m_info_ptr && m_end_info && m_width && m_height ) + if( png_ptr && info_ptr && end_info && m_width && m_height ) { if( setjmp( png_jmpbuf ( png_ptr ) ) == 0 ) { @@ -735,30 +709,20 @@ bool PngDecoder::processing_start(void* frame_ptr, const Mat& img) { static uint8_t header[8] = { 137, 80, 78, 71, 13, 10, 26, 10 }; - if (m_png_ptr) - { - png_structp png_ptr = (png_structp)m_png_ptr; - png_infop info_ptr = (png_infop)m_info_ptr; - png_infop end_info = (png_infop)m_end_info; - png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); - m_png_ptr = m_info_ptr = m_end_info = nullptr; - } + PngPtrs png_ptrs; + png_structp png_ptr = png_ptrs.getPng(); + png_infop info_ptr = png_ptrs.getInfo(); - png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - png_infop info_ptr = png_create_info_struct(png_ptr); - - m_png_ptr = png_ptr; - m_info_ptr = info_ptr; - - if (!png_ptr || !info_ptr) + if (!png_ptr || !info_ptr) { return false; + } if (setjmp(png_jmpbuf(png_ptr))) { - png_destroy_read_struct(&png_ptr, &info_ptr, 0); return false; } + m_png_ptrs = std::move(png_ptrs); png_set_crc_action(png_ptr, PNG_CRC_QUIET_USE, PNG_CRC_QUIET_USE); png_set_progressive_read_fn(png_ptr, frame_ptr, (png_progressive_info_ptr)info_fn, row_fn, NULL); @@ -787,24 +751,22 @@ bool PngDecoder::processing_finish() { static uint8_t footer[12] = { 0, 0, 0, 0, 73, 69, 78, 68, 174, 66, 96, 130 }; - png_structp png_ptr = (png_structp)m_png_ptr; - png_infop info_ptr = (png_infop)m_info_ptr; - png_infop end_info = (png_infop)m_end_info; + png_structp png_ptr = m_png_ptrs.getPng(); + png_infop info_ptr = m_png_ptrs.getInfo(); - if (!png_ptr) + if (!png_ptr) { + m_png_ptrs.clear(); return false; + } if (setjmp(png_jmpbuf(png_ptr))) { - png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); + m_png_ptrs.clear(); return false; } png_process_data(png_ptr, info_ptr, footer, 12); - png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); - m_png_ptr = nullptr; - m_info_ptr = nullptr; - m_end_info = nullptr; + m_png_ptrs.clear(); return true; } diff --git a/modules/imgcodecs/src/grfmt_png.hpp b/modules/imgcodecs/src/grfmt_png.hpp index fa2642b8f3..a950b9e941 100644 --- a/modules/imgcodecs/src/grfmt_png.hpp +++ b/modules/imgcodecs/src/grfmt_png.hpp @@ -140,10 +140,47 @@ protected: size_t read_from_io(void* _Buffer, size_t _ElementSize, size_t _ElementCount); uint32_t read_chunk(Chunk& chunk); + struct PngPtrs { + public: + PngPtrs() { + png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, 0, 0, 0 ); + if (png_ptr) { + info_ptr = png_create_info_struct( png_ptr ); + end_info = png_create_info_struct( png_ptr ); + } else { + info_ptr = end_info = nullptr; + } + } + ~PngPtrs() { + clear(); + } + PngPtrs& operator=(PngPtrs&& other) { + clear(); + png_ptr = other.png_ptr; + info_ptr = other.info_ptr; + end_info = other.end_info; + other.png_ptr = nullptr; + other.info_ptr = other.end_info = nullptr; + return *this; + } + void clear() { + if (png_ptr) { + png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); + png_ptr = nullptr; + info_ptr = end_info = nullptr; + } + } + png_structp getPng() const { return png_ptr; } + png_infop getInfo() const { return info_ptr; } + png_infop getEndInfo() const { return end_info; } + private: + png_structp png_ptr; // pointer to decompression structure + png_infop info_ptr; // pointer to image information structure + png_infop end_info; // pointer to one more image information structure + }; + + PngPtrs m_png_ptrs; int m_bit_depth; - void* m_png_ptr; // pointer to decompression structure - void* m_info_ptr; // pointer to image information structure - void* m_end_info; // pointer to one more image information structure FILE* m_f; int m_color_type; Chunk m_chunkIHDR;