|
|
|
@ -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) |
|
|
|
|
) |
|
|
|
|
{ |
|
|
|
|
TIFFClose(pTiffHandle); |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (compression != COMPRESSION_NONE && !TIFFSetField(pTiffHandle, TIFFTAG_PREDICTOR, predictor) ) |
|
|
|
|
//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; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 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; |
|
|
|
|
} |
|
|
|
|
const Mat& img = img_vec[page]; |
|
|
|
|
int channels = img.channels(); |
|
|
|
|
int width = img.cols, height = img.rows; |
|
|
|
|
int depth = img.depth(); |
|
|
|
|
|
|
|
|
|
for (int y = 0; y < height; ++y) |
|
|
|
|
{ |
|
|
|
|
switch(channels) |
|
|
|
|
int bitsPerChannel = -1; |
|
|
|
|
switch (depth) |
|
|
|
|
{ |
|
|
|
|
case 1: |
|
|
|
|
{ |
|
|
|
|
memcpy(buffer, img.ptr(y), scanlineSize); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
case 3: |
|
|
|
|
case CV_8U: |
|
|
|
|
{ |
|
|
|
|
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 = 8; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
case 4: |
|
|
|
|
case CV_16U: |
|
|
|
|
{ |
|
|
|
|
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) ); |
|
|
|
|
bitsPerChannel = 16; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
default: |
|
|
|
|
{ |
|
|
|
|
TIFFClose(pTiffHandle); |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int writeResult = TIFFWriteScanline(pTiffHandle, buffer, y, 0); |
|
|
|
|
if (writeResult != 1) |
|
|
|
|
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; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|