Merge pull request #25975 from asmorkalov:as/bmp_error_check

Improved error handling in image codecs.
pull/25786/head
Alexander Smorkalov 6 months ago committed by GitHub
commit b9b2d551ac
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 54
      modules/imgcodecs/src/bitstrm.cpp
  2. 20
      modules/imgcodecs/src/bitstrm.hpp
  3. 38
      modules/imgcodecs/src/grfmt_bmp.cpp
  4. 34
      modules/imgcodecs/src/grfmt_pfm.cpp
  5. 8
      modules/imgcodecs/src/grfmt_pxm.cpp
  6. 18
      modules/imgcodecs/src/grfmt_sunras.cpp
  7. 10
      modules/imgcodecs/src/grfmt_tiff.cpp
  8. 4
      modules/imgcodecs/src/grfmt_tiff.hpp

@ -377,26 +377,30 @@ void WBaseStream::allocate()
} }
void WBaseStream::writeBlock() bool WBaseStream::writeBlock()
{ {
int size = (int)(m_current - m_start); int size = (int)(m_current - m_start);
CV_Assert(isOpened()); CV_Assert(isOpened());
if( size == 0 ) if( size == 0 )
return; return true;
if( m_buf ) if( m_buf )
{ {
size_t sz = m_buf->size(); size_t sz = m_buf->size();
m_buf->resize( sz + size ); m_buf->resize( sz + size );
memcpy( &(*m_buf)[sz], m_start, size ); memcpy( &(*m_buf)[sz], m_start, size );
m_current = m_start;
m_block_pos += size;
return true;
} }
else else
{ {
fwrite( m_start, 1, size, m_file ); size_t written = fwrite( m_start, 1, size, m_file );
m_current = m_start;
m_block_pos += size;
return written == (size_t)size;
} }
m_current = m_start;
m_block_pos += size;
} }
@ -463,15 +467,17 @@ WLByteStream::~WLByteStream()
{ {
} }
void WLByteStream::putByte( int val ) bool WLByteStream::putByte( int val )
{ {
*m_current++ = (uchar)val; *m_current++ = (uchar)val;
if( m_current >= m_end ) if( m_current >= m_end )
writeBlock(); return writeBlock();
return true;
} }
void WLByteStream::putBytes( const void* buffer, int count ) bool WLByteStream::putBytes( const void* buffer, int count )
{ {
uchar* data = (uchar*)buffer; uchar* data = (uchar*)buffer;
@ -492,12 +498,18 @@ void WLByteStream::putBytes( const void* buffer, int count )
count -= l; count -= l;
} }
if( m_current == m_end ) if( m_current == m_end )
writeBlock(); {
bool written = writeBlock();
if (!written)
return false;
}
} }
return true;
} }
void WLByteStream::putWord( int val ) bool WLByteStream::putWord( int val )
{ {
uchar *current = m_current; uchar *current = m_current;
@ -507,17 +519,19 @@ void WLByteStream::putWord( int val )
current[1] = (uchar)(val >> 8); current[1] = (uchar)(val >> 8);
m_current = current + 2; m_current = current + 2;
if( m_current == m_end ) if( m_current == m_end )
writeBlock(); return writeBlock();
} }
else else
{ {
putByte(val); putByte(val);
putByte(val >> 8); putByte(val >> 8);
} }
return true;
} }
void WLByteStream::putDWord( int val ) bool WLByteStream::putDWord( int val )
{ {
uchar *current = m_current; uchar *current = m_current;
@ -529,7 +543,7 @@ void WLByteStream::putDWord( int val )
current[3] = (uchar)(val >> 24); current[3] = (uchar)(val >> 24);
m_current = current + 4; m_current = current + 4;
if( m_current == m_end ) if( m_current == m_end )
writeBlock(); return writeBlock();
} }
else else
{ {
@ -538,6 +552,8 @@ void WLByteStream::putDWord( int val )
putByte(val >> 16); putByte(val >> 16);
putByte(val >> 24); putByte(val >> 24);
} }
return true;
} }
@ -548,7 +564,7 @@ WMByteStream::~WMByteStream()
} }
void WMByteStream::putWord( int val ) bool WMByteStream::putWord( int val )
{ {
uchar *current = m_current; uchar *current = m_current;
@ -558,17 +574,19 @@ void WMByteStream::putWord( int val )
current[1] = (uchar)val; current[1] = (uchar)val;
m_current = current + 2; m_current = current + 2;
if( m_current == m_end ) if( m_current == m_end )
writeBlock(); return writeBlock();
} }
else else
{ {
putByte(val >> 8); putByte(val >> 8);
putByte(val); putByte(val);
} }
return true;
} }
void WMByteStream::putDWord( int val ) bool WMByteStream::putDWord( int val )
{ {
uchar *current = m_current; uchar *current = m_current;
@ -580,7 +598,7 @@ void WMByteStream::putDWord( int val )
current[3] = (uchar)val; current[3] = (uchar)val;
m_current = current + 4; m_current = current + 4;
if( m_current == m_end ) if( m_current == m_end )
writeBlock(); return writeBlock();
} }
else else
{ {
@ -589,6 +607,8 @@ void WMByteStream::putDWord( int val )
putByte(val >> 8); putByte(val >> 8);
putByte(val); putByte(val);
} }
return true;
} }
} }

@ -63,6 +63,12 @@ DECLARE_RBS_EXCEPTION(THROW_FORB)
DECLARE_RBS_EXCEPTION(BAD_HEADER) DECLARE_RBS_EXCEPTION(BAD_HEADER)
#define RBS_BAD_HEADER RBS_BAD_HEADER_Exception(cv::Error::StsError, "Invalid header", CV_Func, __FILE__, __LINE__) #define RBS_BAD_HEADER RBS_BAD_HEADER_Exception(cv::Error::StsError, "Invalid header", CV_Func, __FILE__, __LINE__)
#define CHECK_WRITE(action) \
if (!action) \
{ \
return false; \
}
typedef unsigned long ulong; typedef unsigned long ulong;
// class RBaseStream - base class for other reading streams. // class RBaseStream - base class for other reading streams.
@ -147,7 +153,7 @@ protected:
bool m_is_opened; bool m_is_opened;
std::vector<uchar>* m_buf; std::vector<uchar>* m_buf;
virtual void writeBlock(); virtual bool writeBlock();
virtual void release(); virtual void release();
virtual void allocate(); virtual void allocate();
}; };
@ -160,10 +166,10 @@ class WLByteStream : public WBaseStream
public: public:
virtual ~WLByteStream(); virtual ~WLByteStream();
void putByte( int val ); bool putByte( int val );
void putBytes( const void* buffer, int count ); bool putBytes( const void* buffer, int count );
void putWord( int val ); bool putWord( int val );
void putDWord( int val ); bool putDWord( int val );
}; };
@ -173,8 +179,8 @@ class WMByteStream : public WLByteStream
{ {
public: public:
virtual ~WMByteStream(); virtual ~WMByteStream();
void putWord( int val ); bool putWord( int val );
void putDWord( int val ); bool putDWord( int val );
}; };
inline unsigned BSWAP(unsigned v) inline unsigned BSWAP(unsigned v)

@ -635,38 +635,40 @@ bool BmpEncoder::write( const Mat& img, const std::vector<int>& )
m_buf->reserve( alignSize(fileSize + 16, 256) ); m_buf->reserve( alignSize(fileSize + 16, 256) );
// write signature 'BM' // write signature 'BM'
strm.putBytes( fmtSignBmp, (int)strlen(fmtSignBmp) ); CHECK_WRITE(strm.putBytes( fmtSignBmp, (int)strlen(fmtSignBmp) ));
// write file header // write file header
strm.putDWord( validateToInt(fileSize) ); // file size CHECK_WRITE(strm.putDWord( validateToInt(fileSize) )); // file size
strm.putDWord( 0 ); CHECK_WRITE(strm.putDWord( 0 ));
strm.putDWord( headerSize ); CHECK_WRITE(strm.putDWord( headerSize ));
// write bitmap header // write bitmap header
strm.putDWord( bitmapHeaderSize ); CHECK_WRITE(strm.putDWord( bitmapHeaderSize ));
strm.putDWord( width ); CHECK_WRITE(strm.putDWord( width ));
strm.putDWord( height ); CHECK_WRITE(strm.putDWord( height ));
strm.putWord( 1 ); CHECK_WRITE(strm.putWord( 1 ));
strm.putWord( channels << 3 ); CHECK_WRITE(strm.putWord( channels << 3 ));
strm.putDWord( BMP_RGB ); CHECK_WRITE(strm.putDWord( BMP_RGB ));
strm.putDWord( 0 ); CHECK_WRITE(strm.putDWord( 0 ));
strm.putDWord( 0 ); CHECK_WRITE(strm.putDWord( 0 ));
strm.putDWord( 0 ); CHECK_WRITE(strm.putDWord( 0 ));
strm.putDWord( 0 ); CHECK_WRITE(strm.putDWord( 0 ));
strm.putDWord( 0 ); CHECK_WRITE(strm.putDWord( 0 ));
if( channels == 1 ) if( channels == 1 )
{ {
FillGrayPalette( palette, 8 ); FillGrayPalette( palette, 8 );
strm.putBytes( palette, sizeof(palette)); CHECK_WRITE(strm.putBytes( palette, sizeof(palette)));
} }
width *= channels; width *= channels;
for( int y = height - 1; y >= 0; y-- ) for( int y = height - 1; y >= 0; y-- )
{ {
strm.putBytes( img.ptr(y), width ); CHECK_WRITE(strm.putBytes( img.ptr(y), width ));
if( fileStep > width ) if( fileStep > width )
strm.putBytes( zeropad, fileStep - width ); {
CHECK_WRITE(strm.putBytes( zeropad, fileStep - width ));
}
} }
strm.close(); strm.close();

@ -64,11 +64,11 @@ T read_number(cv::RLByteStream& strm)
return atoT<T>(str); return atoT<T>(str);
} }
template<typename T> void write_anything(cv::WLByteStream& strm, const T& t) template<typename T> bool write_anything(cv::WLByteStream& strm, const T& t)
{ {
std::ostringstream ss; std::ostringstream ss;
ss << t; ss << t;
strm.putBytes(ss.str().c_str(), static_cast<int>(ss.str().size())); return strm.putBytes(ss.str().c_str(), static_cast<int>(ss.str().size()));
} }
} }
@ -206,33 +206,33 @@ bool PFMEncoder::write(const Mat& img, const std::vector<int>& params)
} }
Mat float_img; Mat float_img;
strm.putByte('P'); CHECK_WRITE(strm.putByte('P'));
switch (img.channels()) { switch (img.channels()) {
case 1: case 1:
strm.putByte('f'); CHECK_WRITE(strm.putByte('f'));
img.convertTo(float_img, CV_32FC1); img.convertTo(float_img, CV_32FC1);
break; break;
case 3: case 3:
strm.putByte('F'); CHECK_WRITE(strm.putByte('F'));
img.convertTo(float_img, CV_32FC3); img.convertTo(float_img, CV_32FC3);
break; break;
default: default:
CV_Error(Error::StsBadArg, "Expected 1 or 3 channel image."); CV_Error(Error::StsBadArg, "Expected 1 or 3 channel image.");
} }
strm.putByte('\n'); CHECK_WRITE(strm.putByte('\n'));
write_anything(strm, float_img.cols); CHECK_WRITE(write_anything(strm, float_img.cols));
strm.putByte(' '); CHECK_WRITE(strm.putByte(' '));
write_anything(strm, float_img.rows); CHECK_WRITE(write_anything(strm, float_img.rows));
strm.putByte('\n'); CHECK_WRITE(strm.putByte('\n'));
#ifdef WORDS_BIGENDIAN #ifdef WORDS_BIGENDIAN
write_anything(strm, 1.0); CHECK_WRITE(write_anything(strm, 1.0));
#else #else
write_anything(strm, -1.0); CHECK_WRITE(write_anything(strm, -1.0));
#endif #endif
strm.putByte('\n'); CHECK_WRITE(strm.putByte('\n'));
// Comments are not officially supported in this file format. // Comments are not officially supported in this file format.
// write_anything(strm, "# Generated by OpenCV " CV_VERSION "\n"); // write_anything(strm, "# Generated by OpenCV " CV_VERSION "\n");
@ -248,17 +248,15 @@ bool PFMEncoder::write(const Mat& img, const std::vector<int>& params)
rgb_row[x*3+1] = bgr_row[x*3+1]; rgb_row[x*3+1] = bgr_row[x*3+1];
rgb_row[x*3+2] = bgr_row[x*3+0]; rgb_row[x*3+2] = bgr_row[x*3+0];
} }
strm.putBytes( reinterpret_cast<const uchar*>(rgb_row.data()), CHECK_WRITE(strm.putBytes( reinterpret_cast<const uchar*>(rgb_row.data()),
static_cast<int>(sizeof(float) * row_size) ); static_cast<int>(sizeof(float) * row_size) ));
} else if (float_img.channels() == 1) { } else if (float_img.channels() == 1) {
strm.putBytes(float_img.ptr(y), sizeof(float) * float_img.cols); CHECK_WRITE(strm.putBytes(float_img.ptr(y), sizeof(float) * float_img.cols));
} }
} }
return true; return true;
} }
} }
#endif // HAVE_IMGCODEC_PFM #endif // HAVE_IMGCODEC_PFM

@ -479,7 +479,7 @@ bool PxMEncoder::write(const Mat& img, const std::vector<int>& params)
header_sz += sz; header_sz += sz;
} }
strm.putBytes(buffer, header_sz); CHECK_WRITE(strm.putBytes(buffer, header_sz));
for( y = 0; y < height; y++ ) for( y = 0; y < height; y++ )
{ {
@ -512,7 +512,7 @@ bool PxMEncoder::write(const Mat& img, const std::vector<int>& params)
{ {
*ptr++ = byte; *ptr++ = byte;
} }
strm.putBytes(buffer, (int)(ptr - buffer)); CHECK_WRITE(strm.putBytes(buffer, (int)(ptr - buffer)));
continue; continue;
} }
@ -539,7 +539,7 @@ bool PxMEncoder::write(const Mat& img, const std::vector<int>& params)
} }
} }
strm.putBytes( (channels > 1 || depth > 8) ? buffer : (const char*)data, fileStep); CHECK_WRITE(strm.putBytes( (channels > 1 || depth > 8) ? buffer : (const char*)data, fileStep));
} }
else else
{ {
@ -610,7 +610,7 @@ bool PxMEncoder::write(const Mat& img, const std::vector<int>& params)
*ptr++ = '\n'; *ptr++ = '\n';
strm.putBytes( buffer, (int)(ptr - buffer) ); CHECK_WRITE(strm.putBytes( buffer, (int)(ptr - buffer) ));
} }
} }

@ -410,17 +410,17 @@ bool SunRasterEncoder::write( const Mat& img, const std::vector<int>& )
if( strm.open(m_filename) ) if( strm.open(m_filename) )
{ {
strm.putBytes( fmtSignSunRas, (int)strlen(fmtSignSunRas) ); CHECK_WRITE(strm.putBytes( fmtSignSunRas, (int)strlen(fmtSignSunRas) ));
strm.putDWord( width ); CHECK_WRITE(strm.putDWord( width ));
strm.putDWord( height ); CHECK_WRITE(strm.putDWord( height ));
strm.putDWord( channels*8 ); CHECK_WRITE(strm.putDWord( channels*8 ));
strm.putDWord( fileStep*height ); CHECK_WRITE(strm.putDWord( fileStep*height ));
strm.putDWord( RAS_STANDARD ); CHECK_WRITE(strm.putDWord( RAS_STANDARD ));
strm.putDWord( RMT_NONE ); CHECK_WRITE(strm.putDWord( RMT_NONE ));
strm.putDWord( 0 ); CHECK_WRITE(strm.putDWord( 0 ));
for( y = 0; y < height; y++ ) for( y = 0; y < height; y++ )
strm.putBytes( img.ptr(y), fileStep ); CHECK_WRITE(strm.putBytes( img.ptr(y), fileStep ));
strm.close(); strm.close();
result = true; result = true;

@ -1100,16 +1100,6 @@ bool TiffEncoder::isFormatSupported( int depth ) const
return depth == CV_8U || depth == CV_8S || depth == CV_16U || depth == CV_16S || depth == CV_32S || depth == CV_32F || depth == CV_64F; return depth == CV_8U || depth == CV_8S || depth == CV_16U || depth == CV_16S || depth == CV_32S || depth == CV_32F || depth == CV_64F;
} }
void TiffEncoder::writeTag( WLByteStream& strm, TiffTag tag,
TiffFieldType fieldType,
int count, int value )
{
strm.putWord( tag );
strm.putWord( fieldType );
strm.putDWord( count );
strm.putDWord( value );
}
class TiffEncoderBufHelper class TiffEncoderBufHelper
{ {
public: public:

@ -132,10 +132,6 @@ public:
ImageEncoder newEncoder() const CV_OVERRIDE; ImageEncoder newEncoder() const CV_OVERRIDE;
protected: protected:
void writeTag( WLByteStream& strm, TiffTag tag,
TiffFieldType fieldType,
int count, int value );
bool writeLibTiff( const std::vector<Mat>& img_vec, const std::vector<int>& params ); bool writeLibTiff( const std::vector<Mat>& img_vec, const std::vector<int>& params );
bool write_32FC3_SGILOG(const Mat& img, void* tif); bool write_32FC3_SGILOG(const Mat& img, void* tif);

Loading…
Cancel
Save