mirror of
https://github.com/opencv/opencv.git
synced 2026-07-30 07:43:03 +04:00
Merge branch 4.x
This commit is contained in:
@@ -95,9 +95,9 @@ enum ImwriteFlags {
|
||||
IMWRITE_JPEG_SAMPLING_FACTOR = 7, //!< For JPEG, set sampling factor. See cv::ImwriteJPEGSamplingFactorParams.
|
||||
IMWRITE_PNG_COMPRESSION = 16, //!< For PNG, it can be the compression level from 0 to 9. A higher value means a smaller size and longer compression time. If specified, strategy is changed to IMWRITE_PNG_STRATEGY_DEFAULT (Z_DEFAULT_STRATEGY). Default value is 1 (best speed setting).
|
||||
IMWRITE_PNG_STRATEGY = 17, //!< For PNG, One of cv::ImwritePNGFlags, default is IMWRITE_PNG_STRATEGY_RLE.
|
||||
IMWRITE_PNG_BILEVEL = 18, //!< For PNG, Binary level PNG, 0 or 1, default is 0.
|
||||
IMWRITE_PNG_FILTER = 19, //!< For PNG, One of cv::ImwritePNGFilterFlags, default is IMWRITE_PNG_FILTER_SUB.
|
||||
IMWRITE_PNG_ZLIBBUFFER_SIZE = 20, //!< For PNG with libpng, sets the size of the internal zlib compression buffer in bytes, from 6 to 1048576(1024 KiB). Default is 8192(8 KiB). For normal use, 131072(128 KiB) or 262144(256 KiB) may be sufficient. If WITH_SPNG=ON, it is not supported.
|
||||
IMWRITE_PNG_BILEVEL = 18, //!< For PNG, Binary level PNG, 0 or 1, default is 0. For APNG, it is not supported.
|
||||
IMWRITE_PNG_FILTER = 19, //!< For PNG, One of cv::ImwritePNGFilterFlags, default is IMWRITE_PNG_FILTER_SUB. For APNG, it is not supported.
|
||||
IMWRITE_PNG_ZLIBBUFFER_SIZE = 20, //!< For PNG with libpng, sets the size of the internal zlib compression buffer in bytes, from 6 to 1048576(1024 KiB). Default is 8192(8 KiB). For normal use, 131072(128 KiB) or 262144(256 KiB) may be sufficient. If WITH_SPNG=ON, it is not supported. For APNG, it is not supported.
|
||||
IMWRITE_PXM_BINARY = 32, //!< For PPM, PGM, or PBM, it can be a binary format flag, 0 or 1. Default value is 1.
|
||||
IMWRITE_EXR_TYPE = (3 << 4) + 0 /* 48 */, //!< override EXR storage type (FLOAT (FP32) is default)
|
||||
IMWRITE_EXR_COMPRESSION = (3 << 4) + 1 /* 49 */, //!< override EXR compression type (ZIP_COMPRESSION = 3 is default)
|
||||
|
||||
@@ -59,7 +59,17 @@ void RBaseStream::readBlock()
|
||||
throw RBS_THROW_EOS;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
// See https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/fseek-fseeki64?view=msvc-170
|
||||
// See https://en.wikipedia.org/wiki/64-bit_computing#64-bit_data_models
|
||||
// - Windows uses LLP64 data model, sizeof long int = 32.
|
||||
// - Linux uses LP64 data model, sizeof long int = 64.
|
||||
// So for Windows, we have to use _fseeki64() instead of fseek().
|
||||
_fseeki64( m_file, m_block_pos, SEEK_SET );
|
||||
#else
|
||||
fseek( m_file, m_block_pos, SEEK_SET );
|
||||
#endif
|
||||
|
||||
size_t readed = fread( m_start, 1, m_block_size, m_file );
|
||||
m_end = m_start + readed;
|
||||
|
||||
@@ -120,7 +130,7 @@ void RBaseStream::release()
|
||||
}
|
||||
|
||||
|
||||
void RBaseStream::setPos( int pos )
|
||||
void RBaseStream::setPos( int64_t pos )
|
||||
{
|
||||
CV_Assert(isOpened() && pos >= 0);
|
||||
|
||||
@@ -132,7 +142,7 @@ void RBaseStream::setPos( int pos )
|
||||
}
|
||||
|
||||
int offset = pos % m_block_size;
|
||||
int old_block_pos = m_block_pos;
|
||||
int64_t old_block_pos = m_block_pos;
|
||||
m_block_pos = pos - offset;
|
||||
m_current = m_start + offset;
|
||||
if (old_block_pos != m_block_pos)
|
||||
@@ -140,16 +150,16 @@ void RBaseStream::setPos( int pos )
|
||||
}
|
||||
|
||||
|
||||
int RBaseStream::getPos()
|
||||
int64_t RBaseStream::getPos()
|
||||
{
|
||||
CV_Assert(isOpened());
|
||||
int pos = validateToInt((m_current - m_start) + m_block_pos);
|
||||
int64_t pos = validateToInt64((m_current - m_start) + m_block_pos);
|
||||
CV_Assert(pos >= m_block_pos); // overflow check
|
||||
CV_Assert(pos >= 0); // overflow check
|
||||
return pos;
|
||||
}
|
||||
|
||||
void RBaseStream::skip( int bytes )
|
||||
void RBaseStream::skip( int64_t bytes )
|
||||
{
|
||||
CV_Assert(bytes >= 0);
|
||||
uchar* old = m_current;
|
||||
|
||||
@@ -45,9 +45,9 @@ public:
|
||||
virtual bool open( const Mat& buf );
|
||||
virtual void close();
|
||||
bool isOpened();
|
||||
void setPos( int pos );
|
||||
int getPos();
|
||||
void skip( int bytes );
|
||||
void setPos( int64_t pos );
|
||||
int64_t getPos();
|
||||
void skip( int64_t bytes );
|
||||
|
||||
protected:
|
||||
|
||||
@@ -57,7 +57,7 @@ protected:
|
||||
uchar* m_current;
|
||||
FILE* m_file;
|
||||
int m_block_size;
|
||||
int m_block_pos;
|
||||
int64_t m_block_pos;
|
||||
bool m_is_opened;
|
||||
|
||||
virtual void readBlock();
|
||||
|
||||
@@ -237,9 +237,6 @@ bool BmpDecoder::readData( Mat& img )
|
||||
int nch = color ? 3 : 1;
|
||||
int y, width3 = m_width*nch;
|
||||
|
||||
// FIXIT: use safe pointer arithmetic (avoid 'int'), use size_t, intptr_t, etc
|
||||
CV_Assert(((uint64)m_height * m_width * nch < (CV_BIG_UINT(1) << 30)) && "BMP reader implementation doesn't support large images >= 1Gb");
|
||||
|
||||
if( m_offset < 0 || !m_strm.isOpened())
|
||||
return false;
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@ protected:
|
||||
PaletteEntry m_palette[256];
|
||||
Origin m_origin;
|
||||
int m_bpp;
|
||||
int m_offset;
|
||||
int64_t m_offset;
|
||||
BmpCompression m_rle_code;
|
||||
uint m_rgba_mask[4];
|
||||
int m_rgba_bit_offset[4];
|
||||
|
||||
@@ -78,8 +78,8 @@ public:
|
||||
protected:
|
||||
|
||||
RLByteStream m_strm;
|
||||
int m_maxval, m_channels, m_sampledepth, m_offset,
|
||||
selected_fmt;
|
||||
int64_t m_offset;
|
||||
int m_maxval, m_channels, m_sampledepth, selected_fmt;
|
||||
bool bit_mode;
|
||||
};
|
||||
|
||||
|
||||
+163
-122
@@ -434,138 +434,147 @@ bool PngDecoder::readData( Mat& img )
|
||||
if (!processing_start((void*)&frameRaw, mat_cur))
|
||||
return false;
|
||||
|
||||
while (true)
|
||||
// See https://github.com/opencv/opencv/issues/27744
|
||||
if( setjmp( png_jmpbuf ( m_png_ptr ) ) == 0 )
|
||||
{
|
||||
id = read_chunk(chunk);
|
||||
if (!id)
|
||||
return false;
|
||||
|
||||
if (id == id_fcTL && m_is_IDAT_loaded)
|
||||
while (true)
|
||||
{
|
||||
if (!m_is_fcTL_loaded)
|
||||
id = read_chunk(chunk);
|
||||
if (!id)
|
||||
return false;
|
||||
|
||||
if (id == id_fcTL && m_is_IDAT_loaded)
|
||||
{
|
||||
m_mat_raw.copyTo(m_animation.still_image);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (processing_finish())
|
||||
if (!m_is_fcTL_loaded)
|
||||
{
|
||||
if (dop == 2)
|
||||
memcpy(frameNext.getPixels(), frameCur.getPixels(), imagesize);
|
||||
|
||||
if (x0 + w0 > frameCur.getWidth() || y0 + h0 > frameCur.getHeight())
|
||||
return false;
|
||||
|
||||
compose_frame(frameCur.getRows(), frameRaw.getRows(), bop, x0, y0, w0, h0, mat_cur);
|
||||
if (!delay_den)
|
||||
delay_den = 100;
|
||||
m_animation.durations.push_back(cvRound(1000. * delay_num / delay_den));
|
||||
|
||||
if (mat_cur.channels() == img.channels())
|
||||
m_mat_raw.copyTo(m_animation.still_image);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (processing_finish())
|
||||
{
|
||||
if (mat_cur.depth() == CV_16U && img.depth() == CV_8U)
|
||||
mat_cur.convertTo(img, CV_8U, 1. / 255);
|
||||
if (dop == 2)
|
||||
memcpy(frameNext.getPixels(), frameCur.getPixels(), imagesize);
|
||||
|
||||
if (x0 + w0 > frameCur.getWidth() || y0 + h0 > frameCur.getHeight())
|
||||
return false;
|
||||
|
||||
compose_frame(frameCur.getRows(), frameRaw.getRows(), bop, x0, y0, w0, h0, mat_cur);
|
||||
if (!delay_den)
|
||||
delay_den = 100;
|
||||
m_animation.durations.push_back(cvRound(1000. * delay_num / delay_den));
|
||||
|
||||
if (mat_cur.channels() == img.channels())
|
||||
{
|
||||
if (mat_cur.depth() == CV_16U && img.depth() == CV_8U)
|
||||
mat_cur.convertTo(img, CV_8U, 1. / 255);
|
||||
else
|
||||
mat_cur.copyTo(img);
|
||||
}
|
||||
else
|
||||
mat_cur.copyTo(img);
|
||||
{
|
||||
Mat mat_cur_scaled;
|
||||
if (mat_cur.depth() == CV_16U && img.depth() == CV_8U)
|
||||
mat_cur.convertTo(mat_cur_scaled, CV_8U, 1. / 255);
|
||||
else
|
||||
mat_cur_scaled = mat_cur;
|
||||
|
||||
if (img.channels() == 1)
|
||||
cvtColor(mat_cur_scaled, img, COLOR_BGRA2GRAY);
|
||||
else if (img.channels() == 3)
|
||||
cvtColor(mat_cur_scaled, img, COLOR_BGRA2BGR);
|
||||
}
|
||||
|
||||
if (dop != 2)
|
||||
{
|
||||
memcpy(frameNext.getPixels(), frameCur.getPixels(), imagesize);
|
||||
if (dop == 1)
|
||||
for (j = 0; j < h0; j++)
|
||||
memset(frameNext.getRows()[y0 + j] + x0 * img.channels(), 0, w0 * img.channels());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Mat mat_cur_scaled;
|
||||
if (mat_cur.depth() == CV_16U && img.depth() == CV_8U)
|
||||
mat_cur.convertTo(mat_cur_scaled, CV_8U, 1. / 255);
|
||||
else
|
||||
mat_cur_scaled = mat_cur;
|
||||
|
||||
if (img.channels() == 1)
|
||||
cvtColor(mat_cur_scaled, img, COLOR_BGRA2GRAY);
|
||||
else if (img.channels() == 3)
|
||||
cvtColor(mat_cur_scaled, img, COLOR_BGRA2BGR);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (dop != 2)
|
||||
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 (int(x0 + w0) > img.cols || int(y0 + h0) > img.rows || dop > 2 || bop > 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(&m_chunkIHDR.p[8], &chunk.p[12], 8);
|
||||
|
||||
if (m_is_fcTL_loaded)
|
||||
return true;
|
||||
else
|
||||
{
|
||||
m_is_fcTL_loaded = true;
|
||||
ClearPngPtr();
|
||||
if (!processing_start((void*)&frameRaw, mat_cur))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (id == id_IDAT)
|
||||
{
|
||||
m_is_IDAT_loaded = true;
|
||||
png_process_data(m_png_ptr, m_info_ptr, chunk.p.data(), chunk.p.size());
|
||||
}
|
||||
else if (id == id_fdAT && m_is_fcTL_loaded)
|
||||
{
|
||||
m_is_IDAT_loaded = true;
|
||||
png_save_uint_32(&chunk.p[4], static_cast<uint32_t>(chunk.p.size() - 16));
|
||||
memcpy(&chunk.p[8], "IDAT", 4);
|
||||
png_process_data(m_png_ptr, m_info_ptr, &chunk.p[4], chunk.p.size() - 4);
|
||||
}
|
||||
else if (id == id_IEND)
|
||||
{
|
||||
if (processing_finish())
|
||||
{
|
||||
compose_frame(frameCur.getRows(), frameRaw.getRows(), bop, x0, y0, w0, h0, mat_cur);
|
||||
if (!delay_den)
|
||||
delay_den = 100;
|
||||
m_animation.durations.push_back(cvRound(1000.*delay_num/delay_den));
|
||||
|
||||
if (mat_cur.depth() == CV_16U && img.depth() == CV_8U && mat_cur.channels() == img.channels())
|
||||
mat_cur.convertTo(img, CV_8U, 1. / 255);
|
||||
else
|
||||
{
|
||||
memcpy(frameNext.getPixels(), frameCur.getPixels(), imagesize);
|
||||
if (dop == 1)
|
||||
for (j = 0; j < h0; j++)
|
||||
memset(frameNext.getRows()[y0 + j] + x0 * img.channels(), 0, w0 * img.channels());
|
||||
if (mat_cur.depth() == CV_16U && img.depth() == CV_8U)
|
||||
mat_cur.convertTo(mat_cur, CV_8U, 1. / 255);
|
||||
if (mat_cur.channels() == img.channels())
|
||||
mat_cur.copyTo(img);
|
||||
else if (img.channels() == 1)
|
||||
cvtColor(mat_cur, img, COLOR_BGRA2GRAY);
|
||||
else if (img.channels() == 3)
|
||||
cvtColor(mat_cur, img, COLOR_BGRA2BGR);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
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 (int(x0 + w0) > img.cols || int(y0 + h0) > img.rows || dop > 2 || bop > 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(&m_chunkIHDR.p[8], &chunk.p[12], 8);
|
||||
|
||||
if (m_is_fcTL_loaded)
|
||||
return true;
|
||||
else
|
||||
{
|
||||
m_is_fcTL_loaded = true;
|
||||
ClearPngPtr();
|
||||
if (!processing_start((void*)&frameRaw, mat_cur))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (id == id_IDAT)
|
||||
{
|
||||
m_is_IDAT_loaded = true;
|
||||
png_process_data(m_png_ptr, m_info_ptr, chunk.p.data(), chunk.p.size());
|
||||
}
|
||||
else if (id == id_fdAT && m_is_fcTL_loaded)
|
||||
{
|
||||
m_is_IDAT_loaded = true;
|
||||
png_save_uint_32(&chunk.p[4], static_cast<uint32_t>(chunk.p.size() - 16));
|
||||
memcpy(&chunk.p[8], "IDAT", 4);
|
||||
png_process_data(m_png_ptr, m_info_ptr, &chunk.p[4], chunk.p.size() - 4);
|
||||
}
|
||||
else if (id == id_IEND)
|
||||
{
|
||||
if (processing_finish())
|
||||
{
|
||||
compose_frame(frameCur.getRows(), frameRaw.getRows(), bop, x0, y0, w0, h0, mat_cur);
|
||||
if (!delay_den)
|
||||
delay_den = 100;
|
||||
m_animation.durations.push_back(cvRound(1000.*delay_num/delay_den));
|
||||
|
||||
if (mat_cur.depth() == CV_16U && img.depth() == CV_8U && mat_cur.channels() == img.channels())
|
||||
mat_cur.convertTo(img, CV_8U, 1. / 255);
|
||||
else
|
||||
{
|
||||
if (mat_cur.depth() == CV_16U && img.depth() == CV_8U)
|
||||
mat_cur.convertTo(mat_cur, CV_8U, 1. / 255);
|
||||
if (mat_cur.channels() == img.channels())
|
||||
mat_cur.copyTo(img);
|
||||
else if (img.channels() == 1)
|
||||
cvtColor(mat_cur, img, COLOR_BGRA2GRAY);
|
||||
else if (img.channels() == 3)
|
||||
cvtColor(mat_cur, img, COLOR_BGRA2BGR);
|
||||
}
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
return true;
|
||||
png_process_data(m_png_ptr, m_info_ptr, chunk.p.data(), chunk.p.size());
|
||||
}
|
||||
else
|
||||
png_process_data(m_png_ptr, m_info_ptr, chunk.p.data(), chunk.p.size());
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// libpng internal error is detected.
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
volatile bool result = false;
|
||||
@@ -1621,20 +1630,52 @@ bool PngEncoder::writeanimation(const Animation& animation, const std::vector<in
|
||||
|
||||
for (size_t i = 0; i < params.size(); i += 2)
|
||||
{
|
||||
if (params[i] == IMWRITE_PNG_COMPRESSION)
|
||||
const int value = params[i+1];
|
||||
switch (params[i])
|
||||
{
|
||||
case IMWRITE_PNG_COMPRESSION:
|
||||
m_compression_strategy = IMWRITE_PNG_STRATEGY_DEFAULT; // Default strategy
|
||||
m_compression_level = params[i + 1];
|
||||
m_compression_level = MIN(MAX(m_compression_level, 0), Z_BEST_COMPRESSION);
|
||||
}
|
||||
if (params[i] == IMWRITE_PNG_STRATEGY)
|
||||
{
|
||||
m_compression_strategy = params[i + 1];
|
||||
m_compression_strategy = MIN(MAX(m_compression_strategy, 0), Z_FIXED);
|
||||
}
|
||||
if (params[i] == IMWRITE_PNG_BILEVEL)
|
||||
{
|
||||
m_isBilevel = params[i + 1] != 0;
|
||||
m_compression_level = MIN(MAX(value, 0), Z_BEST_COMPRESSION);
|
||||
if(value != m_compression_level) {
|
||||
CV_LOG_WARNING(nullptr, cv::format("The value(%d) for IMWRITE_PNG_COMPRESSION must be between 0 to 9. It is fallbacked to %d", value, m_compression_level));
|
||||
}
|
||||
break;
|
||||
|
||||
case IMWRITE_PNG_STRATEGY:
|
||||
{
|
||||
switch(value) {
|
||||
case IMWRITE_PNG_STRATEGY_DEFAULT:
|
||||
case IMWRITE_PNG_STRATEGY_FILTERED:
|
||||
case IMWRITE_PNG_STRATEGY_HUFFMAN_ONLY:
|
||||
case IMWRITE_PNG_STRATEGY_RLE:
|
||||
case IMWRITE_PNG_STRATEGY_FIXED:
|
||||
m_compression_strategy = value;
|
||||
break;
|
||||
default:
|
||||
m_compression_strategy = IMWRITE_PNG_STRATEGY_RLE;
|
||||
CV_LOG_WARNING(nullptr, cv::format("The value(%d) for IMWRITE_PNG_STRATEGY must be one of ImwritePNGFlags. It is fallbacked to IMWRITE_PNG_STRATEGY_RLE", value));
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case IMWRITE_PNG_BILEVEL:
|
||||
m_isBilevel = value != 0;
|
||||
if((value != 0) && (value != 1)) {
|
||||
CV_LOG_WARNING(nullptr, cv::format("The value(%d) for IMWRITE_PNG_BILEVEL must be 0 or 1. It is fallbacked to 1", value ));
|
||||
}
|
||||
break;
|
||||
|
||||
case IMWRITE_PNG_FILTER:
|
||||
CV_LOG_WARNING(nullptr, "IMWRITE_PNG_BILEVEL parameter is not supported for APNG");
|
||||
break;
|
||||
|
||||
case IMWRITE_PNG_ZLIBBUFFER_SIZE:
|
||||
CV_LOG_WARNING(nullptr, "IMWRITE_PNG_ZLIBBUFFER_SIZE parameter is not supported for APNG");
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ protected:
|
||||
RLByteStream m_strm;
|
||||
PaletteEntry m_palette[256];
|
||||
int m_bpp;
|
||||
int m_offset;
|
||||
int64_t m_offset;
|
||||
bool m_binary;
|
||||
int m_maxval;
|
||||
};
|
||||
|
||||
@@ -540,8 +540,8 @@ bool SPngEncoder::write(const Mat &img, const std::vector<int> ¶ms)
|
||||
{
|
||||
compression_strategy = IMWRITE_PNG_STRATEGY_DEFAULT; // Default strategy
|
||||
compression_level = MIN(MAX(value, 0), Z_BEST_COMPRESSION);
|
||||
if(value != m_compression_level) {
|
||||
CV_LOG_WARNING(nullptr, cv::format("The value(%d) for IMWRITE_PNG_COMPRESSION must be between 0 to 9. It is fallbacked to %d", value, m_compression_level));
|
||||
if(value != compression_level) {
|
||||
CV_LOG_WARNING(nullptr, cv::format("The value(%d) for IMWRITE_PNG_COMPRESSION must be between 0 to 9. It is fallbacked to %d", value, compression_level));
|
||||
}
|
||||
set_compression_level = true;
|
||||
}
|
||||
@@ -556,7 +556,7 @@ bool SPngEncoder::write(const Mat &img, const std::vector<int> ¶ms)
|
||||
compression_strategy = value;
|
||||
break;
|
||||
default:
|
||||
compression_strategy = IMWRITE_PNG_STRATEGY_RLE:
|
||||
compression_strategy = IMWRITE_PNG_STRATEGY_RLE;
|
||||
CV_LOG_WARNING(nullptr, cv::format("The value(%d) for IMWRITE_PNG_STRATEGY must be one of ImwritePNGFlags. It is fallbacked to IMWRITE_PNG_STRATEGY_RLE", value));
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ bool SunRasterDecoder::readHeader()
|
||||
m_type = IsColorPalette( m_palette, m_bpp ) ? CV_8UC3 : CV_8UC1;
|
||||
m_offset = m_strm.getPos();
|
||||
|
||||
CV_Assert(m_offset == 32 + m_maplength);
|
||||
CV_Assert(m_offset == static_cast<int64_t>(32 + m_maplength));
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
@@ -107,7 +107,7 @@ bool SunRasterDecoder::readHeader()
|
||||
|
||||
m_offset = m_strm.getPos();
|
||||
|
||||
CV_Assert(m_offset == 32 + m_maplength);
|
||||
CV_Assert(m_offset == static_cast<int64_t>(32 + m_maplength));
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ protected:
|
||||
RMByteStream m_strm;
|
||||
PaletteEntry m_palette[256];
|
||||
int m_bpp;
|
||||
int m_offset;
|
||||
int64_t m_offset;
|
||||
SunRasType m_encoding;
|
||||
SunRasMapType m_maptype;
|
||||
int m_maplength;
|
||||
|
||||
@@ -511,23 +511,26 @@ bool WebPEncoder::writeanimation(const Animation& animation, const std::vector<i
|
||||
|
||||
anim_config.anim_params.bgcolor = bgvalue;
|
||||
anim_config.anim_params.loop_count = animation.loop_count;
|
||||
anim_config.minimize_size = 0;
|
||||
|
||||
if (params.size() > 1)
|
||||
for(size_t i = 0; i < params.size(); i += 2)
|
||||
{
|
||||
if (params[0] == IMWRITE_WEBP_QUALITY)
|
||||
const int value = params[i+1];
|
||||
if (params[i] == IMWRITE_WEBP_QUALITY)
|
||||
{
|
||||
config.lossless = 0;
|
||||
config.quality = static_cast<float>(params[1]);
|
||||
config.lossless = 0; // false
|
||||
config.quality = static_cast<float>(value);
|
||||
if (config.quality < 1.0f)
|
||||
{
|
||||
config.quality = 1.0f;
|
||||
CV_LOG_WARNING(nullptr, cv::format("The value(%d) for IMWRITE_WEBP_QUALITY must be between 1 to 100(lossy) or more(lossless). It is fallbacked to 1", value));
|
||||
}
|
||||
if (config.quality >= 100.0f)
|
||||
if (config.quality > 100.0f)
|
||||
{
|
||||
config.lossless = 1;
|
||||
config.quality = 100.0f;
|
||||
config.lossless = 1; // true
|
||||
}
|
||||
}
|
||||
anim_config.minimize_size = 0;
|
||||
}
|
||||
|
||||
std::unique_ptr<WebPAnimEncoder, void (*)(WebPAnimEncoder*)> anim_encoder(
|
||||
|
||||
@@ -51,6 +51,13 @@ int validateToInt(size_t sz)
|
||||
return valueInt;
|
||||
}
|
||||
|
||||
int64_t validateToInt64(size_t sz)
|
||||
{
|
||||
int64_t valueInt = static_cast<int64_t>(sz);
|
||||
CV_Assert((size_t)valueInt == sz);
|
||||
return valueInt;
|
||||
}
|
||||
|
||||
#define SCALE 14
|
||||
#define cR (int)(0.299*(1 << SCALE) + 0.5)
|
||||
#define cG (int)(0.587*(1 << SCALE) + 0.5)
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
namespace cv {
|
||||
|
||||
int validateToInt(size_t step);
|
||||
int64_t validateToInt64(size_t step);
|
||||
|
||||
template <typename _Tp> static inline
|
||||
size_t safeCastToSizeT(const _Tp v_origin, const char* msg)
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html
|
||||
#include "test_precomp.hpp"
|
||||
#include "test_common.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
// See https://github.com/opencv/opencv/issues/27789
|
||||
// See https://github.com/opencv/opencv/issues/23233
|
||||
TEST(Imgcodecs_BMP, encode_decode_over1GB_regression27789)
|
||||
{
|
||||
applyTestTag( CV_TEST_TAG_MEMORY_2GB, CV_TEST_TAG_LONG );
|
||||
|
||||
// Create large Mat over 1GB
|
||||
// 20000 px * 18000 px * 24 bpp(3ch) = 1,080,000,000 bytes
|
||||
// 1 GiB = 1,073,741,824 bytes
|
||||
cv::Mat src(20000, 18000, CV_8UC3, cv::Scalar(0,0,0));
|
||||
|
||||
// Encode large BMP file.
|
||||
std::vector<uint8_t> buf;
|
||||
bool ret = false;
|
||||
ASSERT_NO_THROW(ret = cv::imencode(".bmp", src, buf, {}));
|
||||
ASSERT_TRUE(ret);
|
||||
|
||||
src.release(); // To reduce usage memory, it is needed.
|
||||
|
||||
// Decode large BMP file.
|
||||
cv::Mat dst;
|
||||
ASSERT_NO_THROW(dst = cv::imdecode(buf, cv::IMREAD_COLOR));
|
||||
ASSERT_FALSE(dst.empty());
|
||||
}
|
||||
|
||||
TEST(Imgcodecs_BMP, write_read_over1GB_regression27789)
|
||||
{
|
||||
// tag CV_TEST_TAG_VERYLONG applied to skip on CI. The test writes ~1GB file.
|
||||
applyTestTag( CV_TEST_TAG_MEMORY_2GB, CV_TEST_TAG_VERYLONG );
|
||||
string bmpFilename = cv::tempfile(".bmp"); // To remove it, test must use EXPECT_* instead of ASSERT_*.
|
||||
|
||||
// Create large Mat over 1GB
|
||||
// 20000 px * 18000 px * 24 bpp(3ch) = 1,080,000,000 bytes
|
||||
// 1 GiB = 1,073,741,824 bytes
|
||||
cv::Mat src(20000, 18000, CV_8UC3, cv::Scalar(0,0,0));
|
||||
|
||||
// Write large BMP file.
|
||||
bool ret = false;
|
||||
EXPECT_NO_THROW(ret = cv::imwrite(bmpFilename, src, {}));
|
||||
EXPECT_TRUE(ret);
|
||||
|
||||
// Read large BMP file.
|
||||
cv::Mat dst;
|
||||
EXPECT_NO_THROW(dst = cv::imread(bmpFilename, cv::IMREAD_COLOR));
|
||||
EXPECT_FALSE(dst.empty());
|
||||
|
||||
remove(bmpFilename.c_str());
|
||||
}
|
||||
|
||||
|
||||
}} // namespace
|
||||
@@ -157,6 +157,51 @@ TEST(Imgcodecs_Png, decode_regression27295)
|
||||
EXPECT_TRUE(img.empty());
|
||||
}
|
||||
|
||||
// The program must not crash even when decoding a corrupted APNG image.
|
||||
// See https://github.com/opencv/opencv/issues/27744
|
||||
#if defined(HAVE_PNG) // APNG is supported only with using libpng
|
||||
TEST(Imgcodecs_Png, decode_regression27744)
|
||||
{
|
||||
// Create APNG stream
|
||||
Animation anim;
|
||||
for(size_t i = 0 ; i < 3 ; i++) {
|
||||
Mat frame(120, 120, CV_8UC3, Scalar(0,0,0));
|
||||
putText(frame, cv::format("%d", static_cast<int>(i)), Point(5, 28), FONT_HERSHEY_SIMPLEX, .5, Scalar(100, 255, 0, 255), 2);
|
||||
anim.frames.push_back(frame);
|
||||
anim.durations.push_back(30);
|
||||
}
|
||||
bool ret = false;
|
||||
vector<uchar> buff;
|
||||
EXPECT_NO_THROW(ret = imencodeanimation(".png", anim, buff));
|
||||
ASSERT_TRUE(ret) << "imencodeanimation() returns false";
|
||||
|
||||
// Find IDAT chunk
|
||||
const vector<uchar> IDAT = {'I', 'D', 'A', 'T' };
|
||||
std::vector<uchar>::iterator it = std::search(buff.begin(), buff.end(), IDAT.begin(), IDAT.end());
|
||||
ASSERT_FALSE(it == buff.end()) << "IDAT chunk not found";
|
||||
|
||||
// Determine the range to test
|
||||
// APNG stream contains as { len0, len1, len2, len3, 'I', 'D', 'A' 'T', ... }
|
||||
size_t idx = std::distance(buff.begin(), it); // 'I' position
|
||||
size_t len = (buff[idx-4] << 24) + (buff[idx-3] << 16) +
|
||||
(buff[idx-2] << 8) + (buff[idx-1]); // IDAT chunk length
|
||||
idx = idx + 4; // Move to IDAT body
|
||||
|
||||
// Test
|
||||
for(size_t i = 0; i < len; i++, idx++) {
|
||||
vector<uint8_t> work = buff;
|
||||
work[idx] = static_cast<uint8_t>((static_cast<uint32_t>(work[idx]) + 1) & 0xff);
|
||||
|
||||
Mat dst;
|
||||
EXPECT_NO_THROW(dst = imdecode(work, cv::IMREAD_COLOR));
|
||||
if(dst.empty()) {
|
||||
// libpng detects some error, but the program is not crashed. Test is passed.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
typedef testing::TestWithParam<string> Imgcodecs_Png_PngSuite;
|
||||
|
||||
// Parameterized test for decoding PNG files from the PNGSuite test set
|
||||
|
||||
@@ -619,4 +619,13 @@ TEST(Imgcodecs_Params, imencode_regression_22752)
|
||||
EXPECT_ANY_THROW(cv::imencode("test.jpg", img, buf, params)); // parameters size or missing JPEG codec
|
||||
}
|
||||
|
||||
TEST(Imgcodecs, decode_over2GB)
|
||||
{
|
||||
applyTestTag(CV_TEST_TAG_MEMORY_6GB);
|
||||
// empty buffer more than 2GB size
|
||||
std::vector<uint8_t> buf(size_t(INT_MAX) + 4096);
|
||||
cv::Mat dst;
|
||||
EXPECT_THROW(dst = cv::imdecode(buf, cv::IMREAD_COLOR), cv::Exception);
|
||||
}
|
||||
|
||||
}} // namespace
|
||||
|
||||
Reference in New Issue
Block a user