Path: blob/master/modules/imgcodecs/src/grfmt_tiff.cpp
16337 views
/*M///////////////////////////////////////////////////////////////////////////////////////1//2// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.3//4// By downloading, copying, installing or using the software you agree to this license.5// If you do not agree to this license, do not download, install,6// copy or use the software.7//8//9// License Agreement10// For Open Source Computer Vision Library11//12// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.13// Copyright (C) 2009, Willow Garage Inc., all rights reserved.14// Third party copyrights are property of their respective owners.15//16// Redistribution and use in source and binary forms, with or without modification,17// are permitted provided that the following conditions are met:18//19// * Redistribution's of source code must retain the above copyright notice,20// this list of conditions and the following disclaimer.21//22// * Redistribution's in binary form must reproduce the above copyright notice,23// this list of conditions and the following disclaimer in the documentation24// and/or other materials provided with the distribution.25//26// * The name of the copyright holders may not be used to endorse or promote products27// derived from this software without specific prior written permission.28//29// This software is provided by the copyright holders and contributors "as is" and30// any express or implied warranties, including, but not limited to, the implied31// warranties of merchantability and fitness for a particular purpose are disclaimed.32// In no event shall the Intel Corporation or contributors be liable for any direct,33// indirect, incidental, special, exemplary, or consequential damages34// (including, but not limited to, procurement of substitute goods or services;35// loss of use, data, or profits; or business interruption) however caused36// and on any theory of liability, whether in contract, strict liability,37// or tort (including negligence or otherwise) arising in any way out of38// the use of this software, even if advised of the possibility of such damage.39//40//M*/4142/****************************************************************************************\43A part of the file implements TIFF reader on base of libtiff library44(see otherlibs/_graphics/readme.txt for copyright notice)45\****************************************************************************************/4647#include "precomp.hpp"4849#ifdef HAVE_TIFF50#include "grfmt_tiff.hpp"51#include <limits>5253// TODO FIXIT Conflict declarations for common types like int64/uint6454namespace tiff_dummy_namespace {55#include "tiff.h"56#include "tiffio.h"57}58using namespace tiff_dummy_namespace;5960namespace cv61{626364static const char fmtSignTiffII[] = "II\x2a\x00";65static const char fmtSignTiffMM[] = "MM\x00\x2a";6667static int grfmt_tiff_err_handler_init = 0;68static void GrFmtSilentTIFFErrorHandler( const char*, const char*, va_list ) {}6970TiffDecoder::TiffDecoder()71{72m_tif = 0;73if( !grfmt_tiff_err_handler_init )74{75grfmt_tiff_err_handler_init = 1;7677TIFFSetErrorHandler( GrFmtSilentTIFFErrorHandler );78TIFFSetWarningHandler( GrFmtSilentTIFFErrorHandler );79}80m_hdr = false;81m_buf_supported = true;82m_buf_pos = 0;83}848586void TiffDecoder::close()87{88if( m_tif )89{90TIFF* tif = (TIFF*)m_tif;91TIFFClose( tif );92m_tif = 0;93}94}9596TiffDecoder::~TiffDecoder()97{98close();99}100101size_t TiffDecoder::signatureLength() const102{103return 4;104}105106bool TiffDecoder::checkSignature( const String& signature ) const107{108return signature.size() >= 4 &&109(memcmp(signature.c_str(), fmtSignTiffII, 4) == 0 ||110memcmp(signature.c_str(), fmtSignTiffMM, 4) == 0);111}112113int TiffDecoder::normalizeChannelsNumber(int channels) const114{115return channels > 4 ? 4 : channels;116}117118ImageDecoder TiffDecoder::newDecoder() const119{120return makePtr<TiffDecoder>();121}122123class TiffDecoderBufHelper124{125Mat& m_buf;126size_t& m_buf_pos;127public:128TiffDecoderBufHelper(Mat& buf, size_t& buf_pos) :129m_buf(buf), m_buf_pos(buf_pos)130{}131static tmsize_t read( thandle_t handle, void* buffer, tmsize_t n )132{133TiffDecoderBufHelper *helper = reinterpret_cast<TiffDecoderBufHelper*>(handle);134const Mat& buf = helper->m_buf;135const tmsize_t size = buf.cols*buf.rows*buf.elemSize();136tmsize_t pos = helper->m_buf_pos;137if ( n > (size - pos) )138{139n = size - pos;140}141memcpy(buffer, buf.ptr() + pos, n);142helper->m_buf_pos += n;143return n;144}145146static tmsize_t write( thandle_t /*handle*/, void* /*buffer*/, tmsize_t /*n*/ )147{148// Not used for decoding.149return 0;150}151152static toff_t seek( thandle_t handle, toff_t offset, int whence )153{154TiffDecoderBufHelper *helper = reinterpret_cast<TiffDecoderBufHelper*>(handle);155const Mat& buf = helper->m_buf;156const toff_t size = buf.cols*buf.rows*buf.elemSize();157toff_t new_pos = helper->m_buf_pos;158switch (whence)159{160case SEEK_SET:161new_pos = offset;162break;163case SEEK_CUR:164new_pos += offset;165break;166case SEEK_END:167new_pos = size + offset;168break;169}170new_pos = std::min(new_pos, size);171helper->m_buf_pos = (size_t)new_pos;172return new_pos;173}174175static int map( thandle_t handle, void** base, toff_t* size )176{177TiffDecoderBufHelper *helper = reinterpret_cast<TiffDecoderBufHelper*>(handle);178Mat& buf = helper->m_buf;179*base = buf.ptr();180*size = buf.cols*buf.rows*buf.elemSize();181return 0;182}183184static toff_t size( thandle_t handle )185{186TiffDecoderBufHelper *helper = reinterpret_cast<TiffDecoderBufHelper*>(handle);187const Mat& buf = helper->m_buf;188return buf.cols*buf.rows*buf.elemSize();189}190191static int close( thandle_t handle )192{193TiffDecoderBufHelper *helper = reinterpret_cast<TiffDecoderBufHelper*>(handle);194delete helper;195return 0;196}197};198199bool TiffDecoder::readHeader()200{201bool result = false;202203TIFF* tif = static_cast<TIFF*>(m_tif);204if (!m_tif)205{206// TIFFOpen() mode flags are different to fopen(). A 'b' in mode "rb" has no effect when reading.207// http://www.remotesensing.org/libtiff/man/TIFFOpen.3tiff.html208if ( !m_buf.empty() )209{210m_buf_pos = 0;211TiffDecoderBufHelper* buf_helper = new TiffDecoderBufHelper(this->m_buf, this->m_buf_pos);212tif = TIFFClientOpen( "", "r", reinterpret_cast<thandle_t>(buf_helper), &TiffDecoderBufHelper::read,213&TiffDecoderBufHelper::write, &TiffDecoderBufHelper::seek,214&TiffDecoderBufHelper::close, &TiffDecoderBufHelper::size,215&TiffDecoderBufHelper::map, /*unmap=*/0 );216}217else218{219tif = TIFFOpen(m_filename.c_str(), "r");220}221}222223if( tif )224{225uint32 wdth = 0, hght = 0;226uint16 photometric = 0;227m_tif = tif;228229if( TIFFGetField( tif, TIFFTAG_IMAGEWIDTH, &wdth ) &&230TIFFGetField( tif, TIFFTAG_IMAGELENGTH, &hght ) &&231TIFFGetField( tif, TIFFTAG_PHOTOMETRIC, &photometric ))232{233uint16 bpp=8, ncn = photometric > 1 ? 3 : 1;234TIFFGetField( tif, TIFFTAG_BITSPERSAMPLE, &bpp );235TIFFGetField( tif, TIFFTAG_SAMPLESPERPIXEL, &ncn );236237m_width = wdth;238m_height = hght;239if((bpp == 32 && ncn == 3) || photometric == PHOTOMETRIC_LOGLUV)240{241m_type = CV_32FC3;242m_hdr = true;243return true;244}245m_hdr = false;246247if( bpp > 8 &&248((photometric > 2) ||249(ncn != 1 && ncn != 3 && ncn != 4)))250bpp = 8;251252int wanted_channels = normalizeChannelsNumber(ncn);253switch(bpp)254{255case 8:256m_type = CV_MAKETYPE(CV_8U, photometric > 1 ? wanted_channels : 1);257result = true;258break;259case 16:260m_type = CV_MAKETYPE(CV_16U, photometric > 1 ? wanted_channels : 1);261result = true;262break;263case 32:264m_type = CV_MAKETYPE(CV_32F, photometric > 1 ? 3 : 1);265result = true;266break;267case 64:268m_type = CV_MAKETYPE(CV_64F, photometric > 1 ? 3 : 1);269result = true;270break;271}272}273}274275if( !result )276close();277278return result;279}280281bool TiffDecoder::nextPage()282{283// Prepare the next page, if any.284return m_tif &&285TIFFReadDirectory(static_cast<TIFF*>(m_tif)) &&286readHeader();287}288289bool TiffDecoder::readData( Mat& img )290{291if(m_hdr && img.type() == CV_32FC3)292{293return readData_32FC3(img);294}295if(img.type() == CV_32FC1)296{297return readData_32FC1(img);298}299bool result = false;300bool color = img.channels() > 1;301302if( img.depth() != CV_8U && img.depth() != CV_16U && img.depth() != CV_32F && img.depth() != CV_64F )303return false;304305if( m_tif && m_width && m_height )306{307TIFF* tif = (TIFF*)m_tif;308uint32 tile_width0 = m_width, tile_height0 = 0;309int x, y, i;310int is_tiled = TIFFIsTiled(tif);311uint16 photometric;312TIFFGetField( tif, TIFFTAG_PHOTOMETRIC, &photometric );313uint16 bpp = 8, ncn = photometric > 1 ? 3 : 1;314TIFFGetField( tif, TIFFTAG_BITSPERSAMPLE, &bpp );315TIFFGetField( tif, TIFFTAG_SAMPLESPERPIXEL, &ncn );316uint16 img_orientation = ORIENTATION_TOPLEFT;317TIFFGetField( tif, TIFFTAG_ORIENTATION, &img_orientation);318bool vert_flip = (img_orientation == ORIENTATION_BOTRIGHT) || (img_orientation == ORIENTATION_RIGHTBOT) ||319(img_orientation == ORIENTATION_BOTLEFT) || (img_orientation == ORIENTATION_LEFTBOT);320const int bitsPerByte = 8;321int dst_bpp = (int)(img.elemSize1() * bitsPerByte);322int wanted_channels = normalizeChannelsNumber(img.channels());323324if(dst_bpp == 8)325{326char errmsg[1024];327if(!TIFFRGBAImageOK( tif, errmsg ))328{329close();330return false;331}332}333334if( (!is_tiled) ||335(is_tiled &&336TIFFGetField( tif, TIFFTAG_TILEWIDTH, &tile_width0 ) &&337TIFFGetField( tif, TIFFTAG_TILELENGTH, &tile_height0 )))338{339if(!is_tiled)340TIFFGetField( tif, TIFFTAG_ROWSPERSTRIP, &tile_height0 );341342if( tile_width0 <= 0 )343tile_width0 = m_width;344345if( tile_height0 <= 0 ||346(!is_tiled && tile_height0 == std::numeric_limits<uint32>::max()) )347tile_height0 = m_height;348349if(dst_bpp == 8) {350// we will use TIFFReadRGBA* functions, so allocate temporary buffer for 32bit RGBA351bpp = 8;352ncn = 4;353}354const size_t buffer_size = (bpp/bitsPerByte) * ncn * tile_height0 * tile_width0;355AutoBuffer<uchar> _buffer( buffer_size );356uchar* buffer = _buffer.data();357ushort* buffer16 = (ushort*)buffer;358float* buffer32 = (float*)buffer;359double* buffer64 = (double*)buffer;360int tileidx = 0;361362for( y = 0; y < m_height; y += tile_height0 )363{364int tile_height = tile_height0;365366if( y + tile_height > m_height )367tile_height = m_height - y;368369uchar* data = img.ptr(vert_flip ? m_height - y - tile_height : y);370371for( x = 0; x < m_width; x += tile_width0, tileidx++ )372{373int tile_width = tile_width0, ok;374375if( x + tile_width > m_width )376tile_width = m_width - x;377378switch(dst_bpp)379{380case 8:381{382uchar * bstart = buffer;383if( !is_tiled )384ok = TIFFReadRGBAStrip( tif, y, (uint32*)buffer );385else386{387ok = TIFFReadRGBATile( tif, x, y, (uint32*)buffer );388//Tiles fill the buffer from the bottom up389bstart += (tile_height0 - tile_height) * tile_width0 * 4;390}391if( !ok )392{393close();394return false;395}396397for( i = 0; i < tile_height; i++ )398if( color )399{400if (wanted_channels == 4)401{402icvCvt_BGRA2RGBA_8u_C4R( bstart + i*tile_width0*4, 0,403data + x*4 + img.step*(tile_height - i - 1), 0,404cvSize(tile_width,1) );405}406else407{408icvCvt_BGRA2BGR_8u_C4C3R( bstart + i*tile_width0*4, 0,409data + x*3 + img.step*(tile_height - i - 1), 0,410cvSize(tile_width,1), 2 );411}412}413else414icvCvt_BGRA2Gray_8u_C4C1R( bstart + i*tile_width0*4, 0,415data + x + img.step*(tile_height - i - 1), 0,416cvSize(tile_width,1), 2 );417break;418}419420case 16:421{422if( !is_tiled )423ok = (int)TIFFReadEncodedStrip( tif, tileidx, (uint32*)buffer, buffer_size ) >= 0;424else425ok = (int)TIFFReadEncodedTile( tif, tileidx, (uint32*)buffer, buffer_size ) >= 0;426427if( !ok )428{429close();430return false;431}432433for( i = 0; i < tile_height; i++ )434{435if( color )436{437if( ncn == 1 )438{439icvCvt_Gray2BGR_16u_C1C3R(buffer16 + i*tile_width0*ncn, 0,440(ushort*)(data + img.step*i) + x*3, 0,441cvSize(tile_width,1) );442}443else if( ncn == 3 )444{445icvCvt_RGB2BGR_16u_C3R(buffer16 + i*tile_width0*ncn, 0,446(ushort*)(data + img.step*i) + x*3, 0,447cvSize(tile_width,1) );448}449else if (ncn == 4)450{451if (wanted_channels == 4)452{453icvCvt_BGRA2RGBA_16u_C4R(buffer16 + i*tile_width0*ncn, 0,454(ushort*)(data + img.step*i) + x * 4, 0,455cvSize(tile_width, 1));456}457else458{459icvCvt_BGRA2BGR_16u_C4C3R(buffer16 + i*tile_width0*ncn, 0,460(ushort*)(data + img.step*i) + x * 3, 0,461cvSize(tile_width, 1), 2);462}463}464else465{466icvCvt_BGRA2BGR_16u_C4C3R(buffer16 + i*tile_width0*ncn, 0,467(ushort*)(data + img.step*i) + x*3, 0,468cvSize(tile_width,1), 2 );469}470}471else472{473if( ncn == 1 )474{475memcpy((ushort*)(data + img.step*i)+x,476buffer16 + i*tile_width0*ncn,477tile_width*sizeof(buffer16[0]));478}479else480{481icvCvt_BGRA2Gray_16u_CnC1R(buffer16 + i*tile_width0*ncn, 0,482(ushort*)(data + img.step*i) + x, 0,483cvSize(tile_width,1), ncn, 2 );484}485}486}487break;488}489490case 32:491case 64:492{493if( !is_tiled )494ok = (int)TIFFReadEncodedStrip( tif, tileidx, buffer, buffer_size ) >= 0;495else496ok = (int)TIFFReadEncodedTile( tif, tileidx, buffer, buffer_size ) >= 0;497498if( !ok || ncn != 1 )499{500close();501return false;502}503504for( i = 0; i < tile_height; i++ )505{506if(dst_bpp == 32)507{508memcpy((float*)(data + img.step*i)+x,509buffer32 + i*tile_width0*ncn,510tile_width*sizeof(buffer32[0]));511}512else513{514memcpy((double*)(data + img.step*i)+x,515buffer64 + i*tile_width0*ncn,516tile_width*sizeof(buffer64[0]));517}518}519520break;521}522default:523{524close();525return false;526}527}528}529}530531result = true;532}533}534535return result;536}537538bool TiffDecoder::readData_32FC3(Mat& img)539{540int rows_per_strip = 0, photometric = 0;541if(!m_tif)542{543return false;544}545TIFF *tif = static_cast<TIFF*>(m_tif);546TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rows_per_strip);547TIFFGetField( tif, TIFFTAG_PHOTOMETRIC, &photometric );548TIFFSetField(tif, TIFFTAG_SGILOGDATAFMT, SGILOGDATAFMT_FLOAT);549int size = 3 * m_width * m_height * sizeof (float);550tstrip_t strip_size = 3 * m_width * rows_per_strip;551float *ptr = img.ptr<float>();552for (tstrip_t i = 0; i < TIFFNumberOfStrips(tif); i++, ptr += strip_size)553{554TIFFReadEncodedStrip(tif, i, ptr, size);555size -= strip_size * sizeof(float);556}557close();558if(photometric == PHOTOMETRIC_LOGLUV)559{560cvtColor(img, img, COLOR_XYZ2BGR);561}562else563{564cvtColor(img, img, COLOR_RGB2BGR);565}566return true;567}568569bool TiffDecoder::readData_32FC1(Mat& img)570{571if(!m_tif)572{573return false;574}575TIFF *tif = static_cast<TIFF*>(m_tif);576577uint32 img_width, img_height;578TIFFGetField(tif,TIFFTAG_IMAGEWIDTH, &img_width);579TIFFGetField(tif,TIFFTAG_IMAGELENGTH, &img_height);580if(img.size() != Size(img_width,img_height))581{582close();583return false;584}585tsize_t scanlength = TIFFScanlineSize(tif);586tdata_t buf = _TIFFmalloc(scanlength);587float* data;588bool result = true;589for (uint32 row = 0; row < img_height; row++)590{591if (TIFFReadScanline(tif, buf, row) != 1)592{593result = false;594break;595}596data=(float*)buf;597for (uint32 i=0; i<img_width; i++)598{599img.at<float>(row,i) = data[i];600}601}602_TIFFfree(buf);603close();604605return result;606}607608//////////////////////////////////////////////////////////////////////////////////////////609610TiffEncoder::TiffEncoder()611{612m_description = "TIFF Files (*.tiff;*.tif)";613m_buf_supported = true;614}615616TiffEncoder::~TiffEncoder()617{618}619620ImageEncoder TiffEncoder::newEncoder() const621{622return makePtr<TiffEncoder>();623}624625bool TiffEncoder::isFormatSupported( int depth ) const626{627return depth == CV_8U || depth == CV_16U || depth == CV_32F;628}629630void TiffEncoder::writeTag( WLByteStream& strm, TiffTag tag,631TiffFieldType fieldType,632int count, int value )633{634strm.putWord( tag );635strm.putWord( fieldType );636strm.putDWord( count );637strm.putDWord( value );638}639640class TiffEncoderBufHelper641{642public:643644TiffEncoderBufHelper(std::vector<uchar> *buf)645: m_buf(buf), m_buf_pos(0)646{}647648TIFF* open ()649{650return TIFFClientOpen( "", "w", reinterpret_cast<thandle_t>(this), &TiffEncoderBufHelper::read,651&TiffEncoderBufHelper::write, &TiffEncoderBufHelper::seek,652&TiffEncoderBufHelper::close, &TiffEncoderBufHelper::size,653/*map=*/0, /*unmap=*/0 );654}655656static tmsize_t read( thandle_t /*handle*/, void* /*buffer*/, tmsize_t /*n*/ )657{658// Not used for encoding.659return 0;660}661662static tmsize_t write( thandle_t handle, void* buffer, tmsize_t n )663{664TiffEncoderBufHelper *helper = reinterpret_cast<TiffEncoderBufHelper*>(handle);665size_t begin = (size_t)helper->m_buf_pos;666size_t end = begin + n;667if ( helper->m_buf->size() < end )668{669helper->m_buf->resize(end);670}671memcpy(&(*helper->m_buf)[begin], buffer, n);672helper->m_buf_pos = end;673return n;674}675676static toff_t seek( thandle_t handle, toff_t offset, int whence )677{678TiffEncoderBufHelper *helper = reinterpret_cast<TiffEncoderBufHelper*>(handle);679const toff_t size = helper->m_buf->size();680toff_t new_pos = helper->m_buf_pos;681switch (whence)682{683case SEEK_SET:684new_pos = offset;685break;686case SEEK_CUR:687new_pos += offset;688break;689case SEEK_END:690new_pos = size + offset;691break;692}693helper->m_buf_pos = new_pos;694return new_pos;695}696697static toff_t size( thandle_t handle )698{699TiffEncoderBufHelper *helper = reinterpret_cast<TiffEncoderBufHelper*>(handle);700return helper->m_buf->size();701}702703static int close( thandle_t /*handle*/ )704{705// Do nothing.706return 0;707}708709private:710711std::vector<uchar>* m_buf;712toff_t m_buf_pos;713};714715static void readParam(const std::vector<int>& params, int key, int& value)716{717for(size_t i = 0; i + 1 < params.size(); i += 2)718if(params[i] == key)719{720value = params[i+1];721break;722}723}724725bool TiffEncoder::writeLibTiff( const std::vector<Mat>& img_vec, const std::vector<int>& params)726{727// do NOT put "wb" as the mode, because the b means "big endian" mode, not "binary" mode.728// http://www.remotesensing.org/libtiff/man/TIFFOpen.3tiff.html729TIFF* pTiffHandle;730731TiffEncoderBufHelper buf_helper(m_buf);732if ( m_buf )733{734pTiffHandle = buf_helper.open();735}736else737{738pTiffHandle = TIFFOpen(m_filename.c_str(), "w");739}740if (!pTiffHandle)741{742return false;743}744745//Settings that matter to all images746// defaults for now, maybe base them on params in the future747int compression = COMPRESSION_LZW;748int predictor = PREDICTOR_HORIZONTAL;749int resUnit = -1, dpiX = -1, dpiY = -1;750751readParam(params, TIFFTAG_COMPRESSION, compression);752readParam(params, TIFFTAG_PREDICTOR, predictor);753readParam(params, IMWRITE_TIFF_RESUNIT, resUnit);754readParam(params, IMWRITE_TIFF_XDPI, dpiX);755readParam(params, IMWRITE_TIFF_YDPI, dpiY);756757//Iterate through each image in the vector and write them out as Tiff directories758for (size_t page = 0; page < img_vec.size(); page++)759{760const Mat& img = img_vec[page];761int channels = img.channels();762int width = img.cols, height = img.rows;763int depth = img.depth();764765int bitsPerChannel = -1;766switch (depth)767{768case CV_8U:769{770bitsPerChannel = 8;771break;772}773case CV_16U:774{775bitsPerChannel = 16;776break;777}778default:779{780TIFFClose(pTiffHandle);781return false;782}783}784785const int bitsPerByte = 8;786size_t fileStep = (width * channels * bitsPerChannel) / bitsPerByte;787788int rowsPerStrip = (int)((1 << 13) / fileStep);789readParam(params, TIFFTAG_ROWSPERSTRIP, rowsPerStrip);790791if (rowsPerStrip < 1)792rowsPerStrip = 1;793794if (rowsPerStrip > height)795rowsPerStrip = height;796797int colorspace = channels > 1 ? PHOTOMETRIC_RGB : PHOTOMETRIC_MINISBLACK;798799if (!TIFFSetField(pTiffHandle, TIFFTAG_IMAGEWIDTH, width)800|| !TIFFSetField(pTiffHandle, TIFFTAG_IMAGELENGTH, height)801|| !TIFFSetField(pTiffHandle, TIFFTAG_BITSPERSAMPLE, bitsPerChannel)802|| !TIFFSetField(pTiffHandle, TIFFTAG_COMPRESSION, compression)803|| !TIFFSetField(pTiffHandle, TIFFTAG_PHOTOMETRIC, colorspace)804|| !TIFFSetField(pTiffHandle, TIFFTAG_SAMPLESPERPIXEL, channels)805|| !TIFFSetField(pTiffHandle, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG)806|| !TIFFSetField(pTiffHandle, TIFFTAG_ROWSPERSTRIP, rowsPerStrip)807|| (img_vec.size() > 1 && (808!TIFFSetField(pTiffHandle, TIFFTAG_SUBFILETYPE, FILETYPE_PAGE)809|| !TIFFSetField(pTiffHandle, TIFFTAG_PAGENUMBER, page, img_vec.size() )))810)811{812TIFFClose(pTiffHandle);813return false;814}815816if (compression != COMPRESSION_NONE && !TIFFSetField(pTiffHandle, TIFFTAG_PREDICTOR, predictor))817{818TIFFClose(pTiffHandle);819return false;820}821822if (((resUnit >= RESUNIT_NONE && resUnit <= RESUNIT_CENTIMETER) && !TIFFSetField(pTiffHandle, TIFFTAG_RESOLUTIONUNIT, resUnit))823|| (dpiX >= 0 && !TIFFSetField(pTiffHandle, TIFFTAG_XRESOLUTION, (float)dpiX))824|| (dpiY >= 0 && !TIFFSetField(pTiffHandle, TIFFTAG_YRESOLUTION, (float)dpiY))825)826{827TIFFClose(pTiffHandle);828return false;829}830831832// row buffer, because TIFFWriteScanline modifies the original data!833size_t scanlineSize = TIFFScanlineSize(pTiffHandle);834AutoBuffer<uchar> _buffer(scanlineSize + 32);835uchar* buffer = _buffer.data();836if (!buffer)837{838TIFFClose(pTiffHandle);839return false;840}841842for (int y = 0; y < height; ++y)843{844switch (channels)845{846case 1:847{848memcpy(buffer, img.ptr(y), scanlineSize);849break;850}851852case 3:853{854if (depth == CV_8U)855icvCvt_BGR2RGB_8u_C3R( img.ptr(y), 0, buffer, 0, cvSize(width, 1));856else857icvCvt_BGR2RGB_16u_C3R( img.ptr<ushort>(y), 0, (ushort*)buffer, 0, cvSize(width, 1));858break;859}860861case 4:862{863if (depth == CV_8U)864icvCvt_BGRA2RGBA_8u_C4R( img.ptr(y), 0, buffer, 0, cvSize(width, 1));865else866icvCvt_BGRA2RGBA_16u_C4R( img.ptr<ushort>(y), 0, (ushort*)buffer, 0, cvSize(width, 1));867break;868}869870default:871{872TIFFClose(pTiffHandle);873return false;874}875}876877int writeResult = TIFFWriteScanline(pTiffHandle, buffer, y, 0);878if (writeResult != 1)879{880TIFFClose(pTiffHandle);881return false;882}883}884885TIFFWriteDirectory(pTiffHandle);886887}888889TIFFClose(pTiffHandle);890return true;891}892893bool TiffEncoder::write_32FC3(const Mat& _img)894{895Mat img;896cvtColor(_img, img, COLOR_BGR2XYZ);897898TIFF* tif;899900TiffEncoderBufHelper buf_helper(m_buf);901if ( m_buf )902{903tif = buf_helper.open();904}905else906{907tif = TIFFOpen(m_filename.c_str(), "w");908}909910if (!tif)911{912return false;913}914TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, img.cols);915TIFFSetField(tif, TIFFTAG_IMAGELENGTH, img.rows);916TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3);917TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_SGILOG);918TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_LOGLUV);919TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);920TIFFSetField(tif, TIFFTAG_SGILOGDATAFMT, SGILOGDATAFMT_FLOAT);921TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, 1);922int strip_size = 3 * img.cols;923float *ptr = const_cast<float*>(img.ptr<float>());924for (int i = 0; i < img.rows; i++, ptr += strip_size)925{926TIFFWriteEncodedStrip(tif, i, ptr, strip_size * sizeof(float));927}928TIFFClose(tif);929return true;930}931932bool TiffEncoder::write_32FC1(const Mat& _img)933{934935TIFF* tif;936937TiffEncoderBufHelper buf_helper(m_buf);938if ( m_buf )939{940tif = buf_helper.open();941}942else943{944tif = TIFFOpen(m_filename.c_str(), "w");945}946947if (!tif)948{949return false;950}951952TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, _img.cols);953TIFFSetField(tif, TIFFTAG_IMAGELENGTH, _img.rows);954TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1);955TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 32);956TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);957TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_IEEEFP);958TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);959for (uint32 row = 0; row < (uint32)_img.rows; row++)960{961if (TIFFWriteScanline(tif, (tdata_t)_img.ptr<float>(row), row, 1) != 1)962{963TIFFClose(tif);964return false;965}966}967TIFFWriteDirectory(tif);968TIFFClose(tif);969970return true;971}972973bool TiffEncoder::writemulti(const std::vector<Mat>& img_vec, const std::vector<int>& params)974{975return writeLibTiff(img_vec, params);976}977978bool TiffEncoder::write( const Mat& img, const std::vector<int>& params)979{980int depth = img.depth();981982if(img.type() == CV_32FC3)983{984return write_32FC3(img);985}986if(img.type() == CV_32FC1)987{988return write_32FC1(img);989}990991CV_Assert(depth == CV_8U || depth == CV_16U);992993std::vector<Mat> img_vec;994img_vec.push_back(img);995return writeLibTiff(img_vec, params);996}997998} // namespace9991000#endif100110021003