Merge pull request #20875 from Harvey-Huang:master

* bmp specified BI_BITFIELDS should take care RGBA bit mask

* change the name

* support xrgb bmp file

* support xrgb bmp file(add test case)

* update testing code
pull/20928/head
Harvey 3 years ago committed by GitHub
parent d376fe9e17
commit 9267536fee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 56
      modules/imgcodecs/src/grfmt_bmp.cpp
  2. 5
      modules/imgcodecs/src/grfmt_bmp.hpp
  3. 26
      modules/imgcodecs/test/test_grfmt.cpp

@ -58,6 +58,7 @@ BmpDecoder::BmpDecoder()
m_origin = ORIGIN_TL;
m_bpp = 0;
m_rle_code = BMP_RGB;
initMask();
}
@ -97,6 +98,7 @@ bool BmpDecoder::readHeader()
int size = m_strm.getDWord();
CV_Assert(size > 0); // overflow, 2Gb limit
initMask();
if( size >= 36 )
{
m_width = m_strm.getDWord();
@ -107,7 +109,30 @@ bool BmpDecoder::readHeader()
m_rle_code = (BmpCompression)m_rle_code_;
m_strm.skip(12);
int clrused = m_strm.getDWord();
m_strm.skip( size - 36 );
if( m_bpp == 32 && m_rle_code == BMP_BITFIELDS && size >= 56 )
{
m_strm.skip(4); //important colors
//0 is Red channel bit mask, 1 is Green channel bit mask, 2 is Blue channel bit mask, 3 is Alpha channel bit mask
for( int index_rgba = 0; index_rgba < 4; ++index_rgba )
{
uint mask = m_strm.getDWord();
m_rgba_mask[index_rgba] = mask;
if(mask != 0)
{
int bit_count = 0;
while(!(mask & 1))
{
mask >>= 1;
++bit_count;
}
m_rgba_bit_offset[index_rgba] = bit_count;
}
}
m_strm.skip( size - 56 );
}
else
m_strm.skip( size - 36 );
if( m_width > 0 && m_height != 0 &&
(((m_bpp == 1 || m_bpp == 4 || m_bpp == 8 ||
@ -486,8 +511,14 @@ decode_rle8_bad: ;
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 )
memcpy(data, src, m_width * 4);
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);
if ( has_bit_mask )
maskBGRA(data, src, m_width);
else
memcpy(data, src, m_width * 4);
}
}
result = true;
break;
@ -503,7 +534,26 @@ decode_rle8_bad: ;
return result;
}
void BmpDecoder::initMask()
{
memset(m_rgba_mask, 0, sizeof(m_rgba_mask));
memset(m_rgba_bit_offset, -1, sizeof(m_rgba_bit_offset));
}
void BmpDecoder::maskBGRA(uchar* des, uchar* src, int num)
{
for( int i = 0; i < num; i++, des += 4, 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;
}
}
//////////////////////////////////////////////////////////////////////////////////////////
BmpEncoder::BmpEncoder()

@ -73,6 +73,9 @@ public:
protected:
void initMask();
void maskBGRA(uchar* des, uchar* src, int num);
enum Origin
{
ORIGIN_TL = 0,
@ -85,6 +88,8 @@ protected:
int m_bpp;
int m_offset;
BmpCompression m_rle_code;
uint m_rgba_mask[4];
int m_rgba_bit_offset[4];
};

@ -295,6 +295,32 @@ TEST(Imgcodecs_Bmp, read_rle8)
EXPECT_PRED_FORMAT2(cvtest::MatComparator(0, 0), rle, ord);
}
TEST(Imgcodecs_Bmp, rgba_bit_mask)
{
const string root = cvtest::TS::ptr()->get_data_path();
const string filenameInput = root + "readwrite/test_rgba_mask.bmp";
const Mat img = cv::imread(filenameInput, IMREAD_UNCHANGED);
ASSERT_FALSE(img.empty());
ASSERT_EQ(CV_8UC4, img.type());
const uchar* data = img.ptr();
ASSERT_EQ(data[3], 255);
}
TEST(Imgcodecs_Bmp, read_32bit_xrgb)
{
const string root = cvtest::TS::ptr()->get_data_path();
const string filenameInput = root + "readwrite/test_32bit_xrgb.bmp";
const Mat img = cv::imread(filenameInput, IMREAD_UNCHANGED);
ASSERT_FALSE(img.empty());
ASSERT_EQ(CV_8UC4, img.type());
const uchar* data = img.ptr();
ASSERT_EQ(data[3], 255);
}
#ifdef HAVE_IMGCODEC_HDR
TEST(Imgcodecs_Hdr, regression)
{

Loading…
Cancel
Save