diff --git a/modules/imgcodecs/include/opencv2/imgcodecs.hpp b/modules/imgcodecs/include/opencv2/imgcodecs.hpp index 89bd6e1c1b..c01d8568e4 100644 --- a/modules/imgcodecs/include/opencv2/imgcodecs.hpp +++ b/modules/imgcodecs/include/opencv2/imgcodecs.hpp @@ -322,7 +322,8 @@ CV_EXPORTS_W Mat imdecode( InputArray buf, int flags ); @param buf Input array or vector of bytes. @param flags The same flags as in cv::imread, see cv::ImreadModes. @param dst The optional output placeholder for the decoded matrix. It can save the image -reallocations when the function is called repeatedly for images of the same size. +reallocations when the function is called repeatedly for images of the same size. In case of decoder +failure the function returns empty cv::Mat object, but does not release user-provided dst buffer. */ CV_EXPORTS Mat imdecode( InputArray buf, int flags, Mat* dst); diff --git a/modules/imgcodecs/src/loadsave.cpp b/modules/imgcodecs/src/loadsave.cpp index 79db3ac14d..bc28efe49b 100644 --- a/modules/imgcodecs/src/loadsave.cpp +++ b/modules/imgcodecs/src/loadsave.cpp @@ -800,7 +800,7 @@ imdecode_( const Mat& buf, int flags, Mat& mat ) ImageDecoder decoder = findDecoder(buf_row); if( !decoder ) - return 0; + return false; int scale_denom = 1; if( flags > IMREAD_LOAD_GDAL ) @@ -821,7 +821,7 @@ imdecode_( const Mat& buf, int flags, Mat& mat ) filename = tempfile(); FILE* f = fopen( filename.c_str(), "wb" ); if( !f ) - return 0; + return false; size_t bufSize = buf_row.total()*buf.elemSize(); if (fwrite(buf_row.ptr(), 1, bufSize, f) != bufSize) { @@ -859,7 +859,7 @@ imdecode_( const Mat& buf, int flags, Mat& mat ) CV_LOG_WARNING(NULL, "unable to remove temporary file:" << filename); } } - return 0; + return false; } // established the required input image size @@ -905,7 +905,6 @@ imdecode_( const Mat& buf, int flags, Mat& mat ) if (!success) { - mat.release(); return false; } @@ -929,7 +928,8 @@ Mat imdecode( InputArray _buf, int flags ) CV_TRACE_FUNCTION(); Mat buf = _buf.getMat(), img; - imdecode_( buf, flags, img ); + if (!imdecode_(buf, flags, img)) + img.release(); return img; } @@ -940,9 +940,10 @@ Mat imdecode( InputArray _buf, int flags, Mat* dst ) Mat buf = _buf.getMat(), img; dst = dst ? dst : &img; - imdecode_( buf, flags, *dst ); - - return *dst; + if (imdecode_(buf, flags, *dst)) + return *dst; + else + return cv::Mat(); } static bool diff --git a/modules/imgcodecs/test/test_grfmt.cpp b/modules/imgcodecs/test/test_grfmt.cpp index 4ea3716d32..826f3d9836 100644 --- a/modules/imgcodecs/test/test_grfmt.cpp +++ b/modules/imgcodecs/test/test_grfmt.cpp @@ -482,6 +482,19 @@ TEST(Imgcodecs, write_parameter_type) EXPECT_EQ(0, remove(tmp_file.c_str())); } +TEST(Imgcodecs, imdecode_user_buffer) +{ + cv::Mat encoded = cv::Mat::zeros(1, 1024, CV_8UC1); + cv::Mat user_buffer(1, 1024, CV_8UC1); + cv::Mat result = cv::imdecode(encoded, IMREAD_ANYCOLOR, &user_buffer); + EXPECT_TRUE(result.empty()); + // the function does not release user-provided buffer + EXPECT_FALSE(user_buffer.empty()); + + result = cv::imdecode(encoded, IMREAD_ANYCOLOR); + EXPECT_TRUE(result.empty()); +} + }} // namespace #if defined(HAVE_OPENEXR) && defined(OPENCV_IMGCODECS_ENABLE_OPENEXR_TESTS)