*/
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.
The function imencode compresses the image and stores it in the memory buffer that is resized to fit the
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,
std::vector<uchar>& buf, const std::vector<int>& params )
{
}
}
+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[] =
{
IMREAD_UNCHANGED,