diff --git a/modules/imgcodecs/src/grfmt_bmp.cpp b/modules/imgcodecs/src/grfmt_bmp.cpp index abb272c93e..9c76597908 100644 --- a/modules/imgcodecs/src/grfmt_bmp.cpp +++ b/modules/imgcodecs/src/grfmt_bmp.cpp @@ -127,6 +127,7 @@ bool BmpDecoder::readHeader() ++bit_count; } m_rgba_bit_offset[index_rgba] = bit_count; + m_rgba_scale_factor[index_rgba] = 255.0f / mask; } } m_strm.skip( size - 56 ); @@ -503,21 +504,33 @@ decode_rle8_bad: ; break; /************************* 32 BPP ************************/ case 32: - for( y = 0; y < m_height; y++, data += step ) { - m_strm.getBytes( src, src_pitch ); - - if( !color ) - icvCvt_BGRA2Gray_8u_C4C1R( src, 0, data, 0, Size(m_width,1) ); - else if( img.channels() == 3 ) - icvCvt_BGRA2BGR_8u_C4C3R(src, 0, data, 0, Size(m_width, 1)); - else if ( img.channels() == 4 ) + bool has_bit_mask = (m_rgba_bit_offset[0] >= 0) && (m_rgba_bit_offset[1] >= 0) && (m_rgba_bit_offset[2] >= 0); + for( y = 0; y < m_height; y++, data += step ) { - bool has_bit_mask = (m_rgba_bit_offset[0] >= 0) && (m_rgba_bit_offset[1] >= 0) && (m_rgba_bit_offset[2] >= 0); - if ( has_bit_mask ) - maskBGRA(data, src, m_width); - else - memcpy(data, src, m_width * 4); + m_strm.getBytes( src, src_pitch ); + + if( !color ) + { + if ( has_bit_mask ) + maskBGRAtoGray(data, src, m_width); + else + icvCvt_BGRA2Gray_8u_C4C1R( src, 0, data, 0, Size(m_width,1) ); + } + else if( img.channels() == 3 ) + { + if ( has_bit_mask ) + maskBGRA(data, src, m_width, false); + else + icvCvt_BGRA2BGR_8u_C4C3R(src, 0, data, 0, Size(m_width, 1)); + } + else if ( img.channels() == 4 ) + { + if ( has_bit_mask ) + maskBGRA(data, src, m_width, true); + else + memcpy(data, src, m_width * 4); + } } } result = true; @@ -538,20 +551,40 @@ void BmpDecoder::initMask() { memset(m_rgba_mask, 0, sizeof(m_rgba_mask)); memset(m_rgba_bit_offset, -1, sizeof(m_rgba_bit_offset)); + for (size_t i = 0; i < 4; i++) { + m_rgba_scale_factor[i] = 1.0f; + } } -void BmpDecoder::maskBGRA(uchar* des, uchar* src, int num) +void BmpDecoder::maskBGRA(uchar* des, const uchar* src, int num, bool alpha_required) { - for( int i = 0; i < num; i++, des += 4, src += 4 ) + int dest_stride = alpha_required ? 4 : 3; + for( int i = 0; i < num; i++, des += dest_stride, src += 4 ) { uint data = *((uint*)src); - des[0] = (uchar)((m_rgba_mask[2] & data) >> m_rgba_bit_offset[2]); - des[1] = (uchar)((m_rgba_mask[1] & data) >> m_rgba_bit_offset[1]); - des[2] = (uchar)((m_rgba_mask[0] & data) >> m_rgba_bit_offset[0]); - if (m_rgba_bit_offset[3] >= 0) - des[3] = (uchar)((m_rgba_mask[3] & data) >> m_rgba_bit_offset[3]); - else - des[3] = 255; + des[0] = (uchar)(((m_rgba_mask[2] & data) >> m_rgba_bit_offset[2]) * m_rgba_scale_factor[2]); + des[1] = (uchar)(((m_rgba_mask[1] & data) >> m_rgba_bit_offset[1]) * m_rgba_scale_factor[1]); + des[2] = (uchar)(((m_rgba_mask[0] & data) >> m_rgba_bit_offset[0]) * m_rgba_scale_factor[0]); + if (alpha_required) + { + if (m_rgba_bit_offset[3] >= 0) + des[3] = (uchar)(((m_rgba_mask[3] & data) >> m_rgba_bit_offset[3]) * m_rgba_scale_factor[3]); + else + des[3] = 255; + } + } +} + +void BmpDecoder::maskBGRAtoGray(uchar* des, const uchar* src, int num) +{ + for( int i = 0; i < num; i++, des++, src += 4 ) + { + uint data = *((uint*)src); + int red = (uchar)(((m_rgba_mask[0] & data) >> m_rgba_bit_offset[0]) * m_rgba_scale_factor[0]); + int green = (uchar)(((m_rgba_mask[1] & data) >> m_rgba_bit_offset[1]) * m_rgba_scale_factor[1]); + int blue = (uchar)(((m_rgba_mask[2] & data) >> m_rgba_bit_offset[2]) * m_rgba_scale_factor[2]); + + *des = (uchar)(0.299f * red + 0.587f * green + 0.114f * blue); } } ////////////////////////////////////////////////////////////////////////////////////////// diff --git a/modules/imgcodecs/src/grfmt_bmp.hpp b/modules/imgcodecs/src/grfmt_bmp.hpp index 4b34124bf7..a9f5fe6040 100644 --- a/modules/imgcodecs/src/grfmt_bmp.hpp +++ b/modules/imgcodecs/src/grfmt_bmp.hpp @@ -74,7 +74,8 @@ public: protected: void initMask(); - void maskBGRA(uchar* des, uchar* src, int num); + void maskBGRA(uchar* des, const uchar* src, int num, bool alpha_required); + void maskBGRAtoGray(uchar* des, const uchar* src, int num); enum Origin { @@ -90,6 +91,7 @@ protected: BmpCompression m_rle_code; uint m_rgba_mask[4]; int m_rgba_bit_offset[4]; + float m_rgba_scale_factor[4]; }; diff --git a/modules/imgcodecs/test/test_grfmt.cpp b/modules/imgcodecs/test/test_grfmt.cpp index fa6c54c8d0..4ea3716d32 100644 --- a/modules/imgcodecs/test/test_grfmt.cpp +++ b/modules/imgcodecs/test/test_grfmt.cpp @@ -331,6 +331,37 @@ TEST(Imgcodecs_Bmp, read_32bit_xrgb) ASSERT_EQ(data[3], 255); } +TEST(Imgcodecs_Bmp, rgba_scale) +{ + const string root = cvtest::TS::ptr()->get_data_path(); + const string filenameInput = root + "readwrite/test_rgba_scale.bmp"; + + Mat img = cv::imread(filenameInput, IMREAD_UNCHANGED); + ASSERT_FALSE(img.empty()); + ASSERT_EQ(CV_8UC4, img.type()); + + uchar* data = img.ptr(); + ASSERT_EQ(data[0], 255); + ASSERT_EQ(data[1], 255); + ASSERT_EQ(data[2], 255); + ASSERT_EQ(data[3], 255); + + img = cv::imread(filenameInput, IMREAD_COLOR); + ASSERT_FALSE(img.empty()); + ASSERT_EQ(CV_8UC3, img.type()); + + data = img.ptr(); + ASSERT_EQ(data[0], 255); + ASSERT_EQ(data[1], 255); + ASSERT_EQ(data[2], 255); + + img = cv::imread(filenameInput, IMREAD_GRAYSCALE); + ASSERT_FALSE(img.empty()); + ASSERT_EQ(CV_8UC1, img.type()); + + data = img.ptr(); + ASSERT_EQ(data[0], 255); +} #ifdef HAVE_IMGCODEC_HDR TEST(Imgcodecs_Hdr, regression)