Merge pull request #21966 from Harvey-Huang:Unicode_Path

Support use memory buffer to read multi-page image
pull/22629/head
Harvey Huang 2 years ago committed by GitHub
parent ec26541771
commit 8b0aa6a64d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 14
      modules/imgcodecs/include/opencv2/imgcodecs.hpp
  2. 151
      modules/imgcodecs/src/loadsave.cpp
  3. 37
      modules/imgcodecs/test/test_tiff.cpp

@ -306,6 +306,20 @@ reallocations when the function is called repeatedly for images of the same size
*/ */
CV_EXPORTS Mat imdecode( InputArray buf, int flags, Mat* dst); CV_EXPORTS Mat imdecode( InputArray buf, int flags, Mat* dst);
/** @brief Reads a multi-page image from a buffer in memory.
The function imdecodemulti reads a multi-page image from the specified buffer in the memory. If the buffer is too short or
contains invalid data, the function returns false.
See cv::imreadmulti for the list of supported formats and flags description.
@note In the case of color images, the decoded images will have the channels stored in **B G R** order.
@param buf Input array or vector of bytes.
@param flags The same flags as in cv::imread, see cv::ImreadModes.
@param mats A vector of Mat objects holding each page, if more than one.
*/
CV_EXPORTS_W bool imdecodemulti(InputArray buf, int flags, CV_OUT std::vector<Mat>& mats);
/** @brief Encodes an image into a memory buffer. /** @brief Encodes an image into a memory buffer.
The function imencode compresses the image and stores it in the memory buffer that is resized to fit the The function imencode compresses the image and stores it in the memory buffer that is resized to fit the

@ -929,6 +929,157 @@ Mat imdecode( InputArray _buf, int flags, Mat* dst )
return *dst; return *dst;
} }
static bool
imdecodemulti_(const Mat& buf, int flags, std::vector<Mat>& mats, int start, int count)
{
CV_Assert(!buf.empty());
CV_Assert(buf.isContinuous());
CV_Assert(buf.checkVector(1, CV_8U) > 0);
Mat buf_row = buf.reshape(1, 1); // decoders expects single row, avoid issues with vector columns
String filename;
ImageDecoder decoder = findDecoder(buf_row);
if (!decoder)
return 0;
if (count < 0) {
count = std::numeric_limits<int>::max();
}
if (!decoder->setSource(buf_row))
{
filename = tempfile();
FILE* f = fopen(filename.c_str(), "wb");
if (!f)
return 0;
size_t bufSize = buf_row.total() * buf.elemSize();
if (fwrite(buf_row.ptr(), 1, bufSize, f) != bufSize)
{
fclose(f);
CV_Error(Error::StsError, "failed to write image data to temporary file");
}
if (fclose(f) != 0)
{
CV_Error(Error::StsError, "failed to write image data to temporary file");
}
decoder->setSource(filename);
}
// read the header to make sure it succeeds
bool success = false;
try
{
// read the header to make sure it succeeds
if (decoder->readHeader())
success = true;
}
catch (const cv::Exception& e)
{
std::cerr << "imreadmulti_('" << filename << "'): can't read header: " << e.what() << std::endl << std::flush;
}
catch (...)
{
std::cerr << "imreadmulti_('" << filename << "'): can't read header: unknown exception" << std::endl << std::flush;
}
int current = start;
while (success && current > 0)
{
if (!decoder->nextPage())
{
success = false;
break;
}
--current;
}
if (!success)
{
decoder.release();
if (!filename.empty())
{
if (0 != remove(filename.c_str()))
{
std::cerr << "unable to remove temporary file:" << filename << std::endl << std::flush;
}
}
return 0;
}
while (current < count)
{
// grab the decoded type
int type = decoder->type();
if ((flags & IMREAD_LOAD_GDAL) != IMREAD_LOAD_GDAL && flags != IMREAD_UNCHANGED)
{
if ((flags & IMREAD_ANYDEPTH) == 0)
type = CV_MAKETYPE(CV_8U, CV_MAT_CN(type));
if ((flags & IMREAD_COLOR) != 0 ||
((flags & IMREAD_ANYCOLOR) != 0 && CV_MAT_CN(type) > 1))
type = CV_MAKETYPE(CV_MAT_DEPTH(type), 3);
else
type = CV_MAKETYPE(CV_MAT_DEPTH(type), 1);
}
// established the required input image size
Size size = validateInputImageSize(Size(decoder->width(), decoder->height()));
// read the image data
Mat mat(size.height, size.width, type);
success = false;
try
{
if (decoder->readData(mat))
success = true;
}
catch (const cv::Exception& e)
{
std::cerr << "imreadmulti_('" << filename << "'): can't read data: " << e.what() << std::endl << std::flush;
}
catch (...)
{
std::cerr << "imreadmulti_('" << filename << "'): can't read data: unknown exception" << std::endl << std::flush;
}
if (!success)
break;
// optionally rotate the data if EXIF' orientation flag says so
if ((flags & IMREAD_IGNORE_ORIENTATION) == 0 && flags != IMREAD_UNCHANGED)
{
ApplyExifOrientation(decoder->getExifTag(ORIENTATION), mat);
}
mats.push_back(mat);
if (!decoder->nextPage())
{
break;
}
++current;
}
if (!filename.empty())
{
if (0 != remove(filename.c_str()))
{
std::cerr << "unable to remove temporary file:" << filename << std::endl << std::flush;
}
}
if (!success)
mats.clear();
return !mats.empty();
}
bool imdecodemulti(InputArray _buf, int flags, CV_OUT std::vector<Mat>& mats)
{
CV_TRACE_FUNCTION();
Mat buf = _buf.getMat();
return imdecodemulti_(buf, flags, mats, 0, -1);
}
bool imencode( const String& ext, InputArray _image, bool imencode( const String& ext, InputArray _image,
std::vector<uchar>& buf, const std::vector<int>& params ) std::vector<uchar>& buf, const std::vector<int>& params )
{ {

@ -442,6 +442,43 @@ TEST_P(Imgcodecs_Tiff_Modes, decode_multipage)
} }
} }
TEST_P(Imgcodecs_Tiff_Modes, decode_multipage_use_memory_buffer)
{
const int mode = GetParam();
const string root = cvtest::TS::ptr()->get_data_path();
const string filename = root + "readwrite/multipage.tif";
const string page_files[] = {
"readwrite/multipage_p1.tif",
"readwrite/multipage_p2.tif",
"readwrite/multipage_p3.tif",
"readwrite/multipage_p4.tif",
"readwrite/multipage_p5.tif",
"readwrite/multipage_p6.tif"
};
const size_t page_count = sizeof(page_files) / sizeof(page_files[0]);
vector<Mat> pages;
FILE* fp = fopen(filename.c_str(), "rb");
ASSERT_TRUE(fp != NULL);
fseek(fp, 0, SEEK_END);
long pos = ftell(fp);
std::vector<uchar> buf;
buf.resize((size_t)pos);
fseek(fp, 0, SEEK_SET);
buf.resize(fread(&buf[0], 1, buf.size(), fp));
fclose(fp);
bool res = imdecodemulti(buf, mode, pages);
ASSERT_TRUE(res == true);
ASSERT_EQ(page_count, pages.size());
for (size_t i = 0; i < page_count; i++)
{
const Mat page = imread(root + page_files[i], mode);
EXPECT_PRED_FORMAT2(cvtest::MatComparator(0, 0), page, pages[i]);
}
}
const int all_modes[] = const int all_modes[] =
{ {
IMREAD_UNCHANGED, IMREAD_UNCHANGED,

Loading…
Cancel
Save