Skip to content

Commit cc5da83

Browse files
committed
Merge pull request opencv#9252 from jbms:fix/tiff-in-memory
2 parents 9c14a2f + c515e87 commit cc5da83

File tree

2 files changed

+195
-13
lines changed

2 files changed

+195
-13
lines changed

modules/imgcodecs/src/grfmt_tiff.cpp

Lines changed: 189 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ TiffDecoder::TiffDecoder()
7575
TIFFSetWarningHandler( GrFmtSilentTIFFErrorHandler );
7676
}
7777
m_hdr = false;
78+
m_buf_supported = true;
79+
m_buf_pos = 0;
7880
}
7981

8082

@@ -115,6 +117,76 @@ ImageDecoder TiffDecoder::newDecoder() const
115117
return makePtr<TiffDecoder>();
116118
}
117119

120+
class TiffDecoderBufHelper
121+
{
122+
public:
123+
static tmsize_t read( thandle_t handle, void* buffer, tmsize_t n )
124+
{
125+
TiffDecoder *decoder = reinterpret_cast<TiffDecoder*>(handle);
126+
const Mat& buf = decoder->m_buf;
127+
const tmsize_t size = buf.cols*buf.rows*buf.elemSize();
128+
tmsize_t pos = decoder->m_buf_pos;
129+
if ( n > (size - pos) )
130+
{
131+
n = size - pos;
132+
}
133+
memcpy(buffer, buf.ptr() + pos, n);
134+
decoder->m_buf_pos += n;
135+
return n;
136+
}
137+
138+
static tmsize_t write( thandle_t /*handle*/, void* /*buffer*/, tmsize_t /*n*/ )
139+
{
140+
// Not used for decoding.
141+
return 0;
142+
}
143+
144+
static toff_t seek( thandle_t handle, toff_t offset, int whence )
145+
{
146+
TiffDecoder *decoder = reinterpret_cast<TiffDecoder*>(handle);
147+
const Mat& buf = decoder->m_buf;
148+
const toff_t size = buf.cols*buf.rows*buf.elemSize();
149+
toff_t new_pos = decoder->m_buf_pos;
150+
switch (whence)
151+
{
152+
case SEEK_SET:
153+
new_pos = offset;
154+
break;
155+
case SEEK_CUR:
156+
new_pos += offset;
157+
break;
158+
case SEEK_END:
159+
new_pos = size + offset;
160+
break;
161+
}
162+
new_pos = std::min(new_pos, size);
163+
decoder->m_buf_pos = (size_t)new_pos;
164+
return new_pos;
165+
}
166+
167+
static int map( thandle_t handle, void** base, toff_t* size )
168+
{
169+
TiffDecoder *decoder = reinterpret_cast<TiffDecoder*>(handle);
170+
Mat& buf = decoder->m_buf;
171+
*base = buf.ptr();
172+
*size = buf.cols*buf.rows*buf.elemSize();
173+
return 0;
174+
}
175+
176+
static toff_t size( thandle_t handle )
177+
{
178+
TiffDecoder *decoder = reinterpret_cast<TiffDecoder*>(handle);
179+
const Mat& buf = decoder->m_buf;
180+
return buf.cols*buf.rows*buf.elemSize();
181+
}
182+
183+
static int close( thandle_t /*handle*/ )
184+
{
185+
// Do nothing.
186+
return 0;
187+
}
188+
};
189+
118190
bool TiffDecoder::readHeader()
119191
{
120192
bool result = false;
@@ -124,7 +196,18 @@ bool TiffDecoder::readHeader()
124196
{
125197
// TIFFOpen() mode flags are different to fopen(). A 'b' in mode "rb" has no effect when reading.
126198
// http://www.remotesensing.org/libtiff/man/TIFFOpen.3tiff.html
127-
tif = TIFFOpen(m_filename.c_str(), "r");
199+
if ( !m_buf.empty() )
200+
{
201+
m_buf_pos = 0;
202+
tif = TIFFClientOpen( "", "r", reinterpret_cast<thandle_t>(this), &TiffDecoderBufHelper::read,
203+
&TiffDecoderBufHelper::write, &TiffDecoderBufHelper::seek,
204+
&TiffDecoderBufHelper::close, &TiffDecoderBufHelper::size,
205+
&TiffDecoderBufHelper::map, /*unmap=*/0 );
206+
}
207+
else
208+
{
209+
tif = TIFFOpen(m_filename.c_str(), "r");
210+
}
128211
}
129212

130213
if( tif )
@@ -472,11 +555,7 @@ bool TiffDecoder::readHdrData(Mat& img)
472555
TiffEncoder::TiffEncoder()
473556
{
474557
m_description = "TIFF Files (*.tiff;*.tif)";
475-
#ifdef HAVE_TIFF
476-
m_buf_supported = false;
477-
#else
478558
m_buf_supported = true;
479-
#endif
480559
}
481560

482561
TiffEncoder::~TiffEncoder()
@@ -509,6 +588,81 @@ void TiffEncoder::writeTag( WLByteStream& strm, TiffTag tag,
509588

510589
#ifdef HAVE_TIFF
511590

591+
class TiffEncoderBufHelper
592+
{
593+
public:
594+
595+
TiffEncoderBufHelper(std::vector<uchar> *buf)
596+
: m_buf(buf), m_buf_pos(0)
597+
{}
598+
599+
TIFF* open ()
600+
{
601+
return TIFFClientOpen( "", "w", reinterpret_cast<thandle_t>(this), &TiffEncoderBufHelper::read,
602+
&TiffEncoderBufHelper::write, &TiffEncoderBufHelper::seek,
603+
&TiffEncoderBufHelper::close, &TiffEncoderBufHelper::size,
604+
/*map=*/0, /*unmap=*/0 );
605+
}
606+
607+
static tmsize_t read( thandle_t /*handle*/, void* /*buffer*/, tmsize_t /*n*/ )
608+
{
609+
// Not used for encoding.
610+
return 0;
611+
}
612+
613+
static tmsize_t write( thandle_t handle, void* buffer, tmsize_t n )
614+
{
615+
TiffEncoderBufHelper *helper = reinterpret_cast<TiffEncoderBufHelper*>(handle);
616+
size_t begin = (size_t)helper->m_buf_pos;
617+
size_t end = begin + n;
618+
if ( helper->m_buf->size() < end )
619+
{
620+
helper->m_buf->resize(end);
621+
}
622+
memcpy(&(*helper->m_buf)[begin], buffer, n);
623+
helper->m_buf_pos = end;
624+
return n;
625+
}
626+
627+
static toff_t seek( thandle_t handle, toff_t offset, int whence )
628+
{
629+
TiffEncoderBufHelper *helper = reinterpret_cast<TiffEncoderBufHelper*>(handle);
630+
const toff_t size = helper->m_buf->size();
631+
toff_t new_pos = helper->m_buf_pos;
632+
switch (whence)
633+
{
634+
case SEEK_SET:
635+
new_pos = offset;
636+
break;
637+
case SEEK_CUR:
638+
new_pos += offset;
639+
break;
640+
case SEEK_END:
641+
new_pos = size + offset;
642+
break;
643+
}
644+
helper->m_buf_pos = new_pos;
645+
return new_pos;
646+
}
647+
648+
static toff_t size( thandle_t handle )
649+
{
650+
TiffEncoderBufHelper *helper = reinterpret_cast<TiffEncoderBufHelper*>(handle);
651+
return helper->m_buf->size();
652+
}
653+
654+
static int close( thandle_t /*handle*/ )
655+
{
656+
// Do nothing.
657+
return 0;
658+
}
659+
660+
private:
661+
662+
std::vector<uchar>* m_buf;
663+
toff_t m_buf_pos;
664+
};
665+
512666
static void readParam(const std::vector<int>& params, int key, int& value)
513667
{
514668
for(size_t i = 0; i + 1 < params.size(); i += 2)
@@ -559,7 +713,17 @@ bool TiffEncoder::writeLibTiff( const Mat& img, const std::vector<int>& params)
559713

560714
// do NOT put "wb" as the mode, because the b means "big endian" mode, not "binary" mode.
561715
// http://www.remotesensing.org/libtiff/man/TIFFOpen.3tiff.html
562-
TIFF* pTiffHandle = TIFFOpen(m_filename.c_str(), "w");
716+
TIFF* pTiffHandle;
717+
718+
TiffEncoderBufHelper buf_helper(m_buf);
719+
if ( m_buf )
720+
{
721+
pTiffHandle = buf_helper.open();
722+
}
723+
else
724+
{
725+
pTiffHandle = TIFFOpen(m_filename.c_str(), "w");
726+
}
563727
if (!pTiffHandle)
564728
{
565729
return false;
@@ -655,7 +819,19 @@ bool TiffEncoder::writeHdr(const Mat& _img)
655819
{
656820
Mat img;
657821
cvtColor(_img, img, COLOR_BGR2XYZ);
658-
TIFF* tif = TIFFOpen(m_filename.c_str(), "w");
822+
823+
TIFF* tif;
824+
825+
TiffEncoderBufHelper buf_helper(m_buf);
826+
if ( m_buf )
827+
{
828+
tif = buf_helper.open();
829+
}
830+
else
831+
{
832+
tif = TIFFOpen(m_filename.c_str(), "w");
833+
}
834+
659835
if (!tif)
660836
{
661837
return false;
@@ -686,8 +862,6 @@ bool TiffEncoder::write( const Mat& img, const std::vector<int>& params)
686862
bool TiffEncoder::write( const Mat& img, const std::vector<int>& /*params*/)
687863
#endif
688864
{
689-
int channels = img.channels();
690-
int width = img.cols, height = img.rows;
691865
int depth = img.depth();
692866
#ifdef HAVE_TIFF
693867
if(img.type() == CV_32FC3)
@@ -699,6 +873,11 @@ bool TiffEncoder::write( const Mat& img, const std::vector<int>& /*params*/)
699873
if (depth != CV_8U && depth != CV_16U)
700874
return false;
701875

876+
#ifdef HAVE_TIFF
877+
return writeLibTiff(img, params);
878+
#else
879+
int channels = img.channels();
880+
int width = img.cols, height = img.rows;
702881
int bytesPerChannel = depth == CV_8U ? 1 : 2;
703882
int fileStep = width * channels * bytesPerChannel;
704883

@@ -711,12 +890,8 @@ bool TiffEncoder::write( const Mat& img, const std::vector<int>& /*params*/)
711890
}
712891
else
713892
{
714-
#ifdef HAVE_TIFF
715-
return writeLibTiff(img, params);
716-
#else
717893
if( !strm.open(m_filename) )
718894
return false;
719-
#endif
720895
}
721896

722897
int rowsPerStrip = (1 << 13)/fileStep;
@@ -876,6 +1051,7 @@ bool TiffEncoder::write( const Mat& img, const std::vector<int>& /*params*/)
8761051
}
8771052

8781053
return true;
1054+
#endif
8791055
}
8801056

8811057
}

modules/imgcodecs/src/grfmt_tiff.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ enum TiffFieldType
9191

9292
// libtiff based TIFF codec
9393

94+
class TiffDecoderBufHelper;
95+
9496
class TiffDecoder : public BaseImageDecoder
9597
{
9698
public:
@@ -107,10 +109,14 @@ class TiffDecoder : public BaseImageDecoder
107109
ImageDecoder newDecoder() const;
108110

109111
protected:
112+
113+
friend class TiffDecoderBufHelper;
114+
110115
void* m_tif;
111116
int normalizeChannelsNumber(int channels) const;
112117
bool readHdrData(Mat& img);
113118
bool m_hdr;
119+
size_t m_buf_pos;
114120
};
115121

116122
#endif

0 commit comments

Comments
 (0)