1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-30 07:43:03 +04:00

imwrite for multipage images implemented

This commit is contained in:
Rostislav Vasilikhin
2017-12-20 23:14:10 +03:00
parent c6e1e3acdc
commit 27b1f8f446
6 changed files with 193 additions and 116 deletions
+115 -98
View File
@@ -539,7 +539,6 @@ bool TiffDecoder::readData( Mat& img )
bool TiffDecoder::readData_32FC3(Mat& img)
{
int rows_per_strip = 0, photometric = 0;
if(!m_tif)
{
@@ -724,44 +723,8 @@ static void readParam(const std::vector<int>& params, int key, int& value)
}
}
bool TiffEncoder::writeLibTiff( const Mat& img, const std::vector<int>& params)
bool TiffEncoder::writeLibTiff( const std::vector<Mat>& img_vec, const std::vector<int>& params)
{
int channels = img.channels();
int width = img.cols, height = img.rows;
int depth = img.depth();
int bitsPerChannel = -1;
switch (depth)
{
case CV_8U:
{
bitsPerChannel = 8;
break;
}
case CV_16U:
{
bitsPerChannel = 16;
break;
}
default:
{
return false;
}
}
const int bitsPerByte = 8;
size_t fileStep = (width * channels * bitsPerChannel) / bitsPerByte;
int rowsPerStrip = (int)((1 << 13)/fileStep);
readParam(params, TIFFTAG_ROWSPERSTRIP, rowsPerStrip);
if( rowsPerStrip < 1 )
rowsPerStrip = 1;
if( rowsPerStrip > height )
rowsPerStrip = height;
// do NOT put "wb" as the mode, because the b means "big endian" mode, not "binary" mode.
// http://www.remotesensing.org/libtiff/man/TIFFOpen.3tiff.html
TIFF* pTiffHandle;
@@ -780,86 +743,133 @@ bool TiffEncoder::writeLibTiff( const Mat& img, const std::vector<int>& params)
return false;
}
//Settings that matter to all images
// defaults for now, maybe base them on params in the future
int compression = COMPRESSION_LZW;
int predictor = PREDICTOR_HORIZONTAL;
int compression = COMPRESSION_LZW;
int predictor = PREDICTOR_HORIZONTAL;
readParam(params, TIFFTAG_COMPRESSION, compression);
readParam(params, TIFFTAG_PREDICTOR, predictor);
int colorspace = channels > 1 ? PHOTOMETRIC_RGB : PHOTOMETRIC_MINISBLACK;
if ( !TIFFSetField(pTiffHandle, TIFFTAG_IMAGEWIDTH, width)
|| !TIFFSetField(pTiffHandle, TIFFTAG_IMAGELENGTH, height)
|| !TIFFSetField(pTiffHandle, TIFFTAG_BITSPERSAMPLE, bitsPerChannel)
|| !TIFFSetField(pTiffHandle, TIFFTAG_COMPRESSION, compression)
|| !TIFFSetField(pTiffHandle, TIFFTAG_PHOTOMETRIC, colorspace)
|| !TIFFSetField(pTiffHandle, TIFFTAG_SAMPLESPERPIXEL, channels)
|| !TIFFSetField(pTiffHandle, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG)
|| !TIFFSetField(pTiffHandle, TIFFTAG_ROWSPERSTRIP, rowsPerStrip)
)
//Iterate through each image in the vector and write them out as Tiff directories
for (size_t page = 0; page < img_vec.size(); page++)
{
TIFFClose(pTiffHandle);
return false;
}
const Mat& img = img_vec[page];
int channels = img.channels();
int width = img.cols, height = img.rows;
int depth = img.depth();
if (compression != COMPRESSION_NONE && !TIFFSetField(pTiffHandle, TIFFTAG_PREDICTOR, predictor) )
{
TIFFClose(pTiffHandle);
return false;
}
// row buffer, because TIFFWriteScanline modifies the original data!
size_t scanlineSize = TIFFScanlineSize(pTiffHandle);
AutoBuffer<uchar> _buffer(scanlineSize+32);
uchar* buffer = _buffer;
if (!buffer)
{
TIFFClose(pTiffHandle);
return false;
}
for (int y = 0; y < height; ++y)
{
switch(channels)
int bitsPerChannel = -1;
switch (depth)
{
case 1:
case CV_8U:
{
memcpy(buffer, img.ptr(y), scanlineSize);
bitsPerChannel = 8;
break;
}
case 3:
case CV_16U:
{
if (depth == CV_8U)
icvCvt_BGR2RGB_8u_C3R( img.ptr(y), 0, buffer, 0, cvSize(width,1) );
else
icvCvt_BGR2RGB_16u_C3R( img.ptr<ushort>(y), 0, (ushort*)buffer, 0, cvSize(width,1) );
bitsPerChannel = 16;
break;
}
case 4:
{
if (depth == CV_8U)
icvCvt_BGRA2RGBA_8u_C4R( img.ptr(y), 0, buffer, 0, cvSize(width,1) );
else
icvCvt_BGRA2RGBA_16u_C4R( img.ptr<ushort>(y), 0, (ushort*)buffer, 0, cvSize(width,1) );
break;
}
default:
{
return false;
}
}
const int bitsPerByte = 8;
size_t fileStep = (width * channels * bitsPerChannel) / bitsPerByte;
int rowsPerStrip = (int)((1 << 13) / fileStep);
readParam(params, TIFFTAG_ROWSPERSTRIP, rowsPerStrip);
if (rowsPerStrip < 1)
rowsPerStrip = 1;
if (rowsPerStrip > height)
rowsPerStrip = height;
int colorspace = channels > 1 ? PHOTOMETRIC_RGB : PHOTOMETRIC_MINISBLACK;
if (!TIFFSetField(pTiffHandle, TIFFTAG_IMAGEWIDTH, width)
|| !TIFFSetField(pTiffHandle, TIFFTAG_IMAGELENGTH, height)
|| !TIFFSetField(pTiffHandle, TIFFTAG_BITSPERSAMPLE, bitsPerChannel)
|| !TIFFSetField(pTiffHandle, TIFFTAG_COMPRESSION, compression)
|| !TIFFSetField(pTiffHandle, TIFFTAG_PHOTOMETRIC, colorspace)
|| !TIFFSetField(pTiffHandle, TIFFTAG_SAMPLESPERPIXEL, channels)
|| !TIFFSetField(pTiffHandle, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG)
|| !TIFFSetField(pTiffHandle, TIFFTAG_ROWSPERSTRIP, rowsPerStrip)
|| (img_vec.size() > 1 && (
!TIFFSetField(pTiffHandle, TIFFTAG_SUBFILETYPE, FILETYPE_PAGE)
|| !TIFFSetField(pTiffHandle, TIFFTAG_PAGENUMBER, page, img_vec.size() )))
)
{
TIFFClose(pTiffHandle);
return false;
}
if (compression != COMPRESSION_NONE && !TIFFSetField(pTiffHandle, TIFFTAG_PREDICTOR, predictor))
{
TIFFClose(pTiffHandle);
return false;
}
// row buffer, because TIFFWriteScanline modifies the original data!
size_t scanlineSize = TIFFScanlineSize(pTiffHandle);
AutoBuffer<uchar> _buffer(scanlineSize + 32);
uchar* buffer = _buffer;
if (!buffer)
{
TIFFClose(pTiffHandle);
return false;
}
for (int y = 0; y < height; ++y)
{
switch (channels)
{
case 1:
{
memcpy(buffer, img.ptr(y), scanlineSize);
break;
}
case 3:
{
if (depth == CV_8U)
icvCvt_BGR2RGB_8u_C3R( img.ptr(y), 0, buffer, 0, cvSize(width, 1));
else
icvCvt_BGR2RGB_16u_C3R( img.ptr<ushort>(y), 0, (ushort*)buffer, 0, cvSize(width, 1));
break;
}
case 4:
{
if (depth == CV_8U)
icvCvt_BGRA2RGBA_8u_C4R( img.ptr(y), 0, buffer, 0, cvSize(width, 1));
else
icvCvt_BGRA2RGBA_16u_C4R( img.ptr<ushort>(y), 0, (ushort*)buffer, 0, cvSize(width, 1));
break;
}
default:
{
TIFFClose(pTiffHandle);
return false;
}
}
int writeResult = TIFFWriteScanline(pTiffHandle, buffer, y, 0);
if (writeResult != 1)
{
TIFFClose(pTiffHandle);
return false;
}
}
int writeResult = TIFFWriteScanline(pTiffHandle, buffer, y, 0);
if (writeResult != 1)
{
TIFFClose(pTiffHandle);
return false;
}
TIFFWriteDirectory(pTiffHandle);
}
TIFFClose(pTiffHandle);
@@ -946,6 +956,11 @@ bool TiffEncoder::write_32FC1(const Mat& _img)
return true;
}
bool TiffEncoder::writemulti(const std::vector<Mat>& img_vec, const std::vector<int>& params)
{
return writeLibTiff(img_vec, params);
}
bool TiffEncoder::write( const Mat& img, const std::vector<int>& params)
{
int depth = img.depth();
@@ -961,7 +976,9 @@ bool TiffEncoder::write( const Mat& img, const std::vector<int>& params)
CV_Assert(depth == CV_8U || depth == CV_16U);
return writeLibTiff(img, params);
std::vector<Mat> img_vec;
img_vec.push_back(img);
return writeLibTiff(img_vec, params);
}
} // namespace