Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Tetragramm
GitHub Repository: Tetragramm/opencv
Path: blob/master/modules/imgcodecs/src/grfmt_tiff.cpp
16337 views
1
/*M///////////////////////////////////////////////////////////////////////////////////////
2
//
3
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4
//
5
// By downloading, copying, installing or using the software you agree to this license.
6
// If you do not agree to this license, do not download, install,
7
// copy or use the software.
8
//
9
//
10
// License Agreement
11
// For Open Source Computer Vision Library
12
//
13
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
14
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
15
// Third party copyrights are property of their respective owners.
16
//
17
// Redistribution and use in source and binary forms, with or without modification,
18
// are permitted provided that the following conditions are met:
19
//
20
// * Redistribution's of source code must retain the above copyright notice,
21
// this list of conditions and the following disclaimer.
22
//
23
// * Redistribution's in binary form must reproduce the above copyright notice,
24
// this list of conditions and the following disclaimer in the documentation
25
// and/or other materials provided with the distribution.
26
//
27
// * The name of the copyright holders may not be used to endorse or promote products
28
// derived from this software without specific prior written permission.
29
//
30
// This software is provided by the copyright holders and contributors "as is" and
31
// any express or implied warranties, including, but not limited to, the implied
32
// warranties of merchantability and fitness for a particular purpose are disclaimed.
33
// In no event shall the Intel Corporation or contributors be liable for any direct,
34
// indirect, incidental, special, exemplary, or consequential damages
35
// (including, but not limited to, procurement of substitute goods or services;
36
// loss of use, data, or profits; or business interruption) however caused
37
// and on any theory of liability, whether in contract, strict liability,
38
// or tort (including negligence or otherwise) arising in any way out of
39
// the use of this software, even if advised of the possibility of such damage.
40
//
41
//M*/
42
43
/****************************************************************************************\
44
A part of the file implements TIFF reader on base of libtiff library
45
(see otherlibs/_graphics/readme.txt for copyright notice)
46
\****************************************************************************************/
47
48
#include "precomp.hpp"
49
50
#ifdef HAVE_TIFF
51
#include "grfmt_tiff.hpp"
52
#include <limits>
53
54
// TODO FIXIT Conflict declarations for common types like int64/uint64
55
namespace tiff_dummy_namespace {
56
#include "tiff.h"
57
#include "tiffio.h"
58
}
59
using namespace tiff_dummy_namespace;
60
61
namespace cv
62
{
63
64
65
static const char fmtSignTiffII[] = "II\x2a\x00";
66
static const char fmtSignTiffMM[] = "MM\x00\x2a";
67
68
static int grfmt_tiff_err_handler_init = 0;
69
static void GrFmtSilentTIFFErrorHandler( const char*, const char*, va_list ) {}
70
71
TiffDecoder::TiffDecoder()
72
{
73
m_tif = 0;
74
if( !grfmt_tiff_err_handler_init )
75
{
76
grfmt_tiff_err_handler_init = 1;
77
78
TIFFSetErrorHandler( GrFmtSilentTIFFErrorHandler );
79
TIFFSetWarningHandler( GrFmtSilentTIFFErrorHandler );
80
}
81
m_hdr = false;
82
m_buf_supported = true;
83
m_buf_pos = 0;
84
}
85
86
87
void TiffDecoder::close()
88
{
89
if( m_tif )
90
{
91
TIFF* tif = (TIFF*)m_tif;
92
TIFFClose( tif );
93
m_tif = 0;
94
}
95
}
96
97
TiffDecoder::~TiffDecoder()
98
{
99
close();
100
}
101
102
size_t TiffDecoder::signatureLength() const
103
{
104
return 4;
105
}
106
107
bool TiffDecoder::checkSignature( const String& signature ) const
108
{
109
return signature.size() >= 4 &&
110
(memcmp(signature.c_str(), fmtSignTiffII, 4) == 0 ||
111
memcmp(signature.c_str(), fmtSignTiffMM, 4) == 0);
112
}
113
114
int TiffDecoder::normalizeChannelsNumber(int channels) const
115
{
116
return channels > 4 ? 4 : channels;
117
}
118
119
ImageDecoder TiffDecoder::newDecoder() const
120
{
121
return makePtr<TiffDecoder>();
122
}
123
124
class TiffDecoderBufHelper
125
{
126
Mat& m_buf;
127
size_t& m_buf_pos;
128
public:
129
TiffDecoderBufHelper(Mat& buf, size_t& buf_pos) :
130
m_buf(buf), m_buf_pos(buf_pos)
131
{}
132
static tmsize_t read( thandle_t handle, void* buffer, tmsize_t n )
133
{
134
TiffDecoderBufHelper *helper = reinterpret_cast<TiffDecoderBufHelper*>(handle);
135
const Mat& buf = helper->m_buf;
136
const tmsize_t size = buf.cols*buf.rows*buf.elemSize();
137
tmsize_t pos = helper->m_buf_pos;
138
if ( n > (size - pos) )
139
{
140
n = size - pos;
141
}
142
memcpy(buffer, buf.ptr() + pos, n);
143
helper->m_buf_pos += n;
144
return n;
145
}
146
147
static tmsize_t write( thandle_t /*handle*/, void* /*buffer*/, tmsize_t /*n*/ )
148
{
149
// Not used for decoding.
150
return 0;
151
}
152
153
static toff_t seek( thandle_t handle, toff_t offset, int whence )
154
{
155
TiffDecoderBufHelper *helper = reinterpret_cast<TiffDecoderBufHelper*>(handle);
156
const Mat& buf = helper->m_buf;
157
const toff_t size = buf.cols*buf.rows*buf.elemSize();
158
toff_t new_pos = helper->m_buf_pos;
159
switch (whence)
160
{
161
case SEEK_SET:
162
new_pos = offset;
163
break;
164
case SEEK_CUR:
165
new_pos += offset;
166
break;
167
case SEEK_END:
168
new_pos = size + offset;
169
break;
170
}
171
new_pos = std::min(new_pos, size);
172
helper->m_buf_pos = (size_t)new_pos;
173
return new_pos;
174
}
175
176
static int map( thandle_t handle, void** base, toff_t* size )
177
{
178
TiffDecoderBufHelper *helper = reinterpret_cast<TiffDecoderBufHelper*>(handle);
179
Mat& buf = helper->m_buf;
180
*base = buf.ptr();
181
*size = buf.cols*buf.rows*buf.elemSize();
182
return 0;
183
}
184
185
static toff_t size( thandle_t handle )
186
{
187
TiffDecoderBufHelper *helper = reinterpret_cast<TiffDecoderBufHelper*>(handle);
188
const Mat& buf = helper->m_buf;
189
return buf.cols*buf.rows*buf.elemSize();
190
}
191
192
static int close( thandle_t handle )
193
{
194
TiffDecoderBufHelper *helper = reinterpret_cast<TiffDecoderBufHelper*>(handle);
195
delete helper;
196
return 0;
197
}
198
};
199
200
bool TiffDecoder::readHeader()
201
{
202
bool result = false;
203
204
TIFF* tif = static_cast<TIFF*>(m_tif);
205
if (!m_tif)
206
{
207
// TIFFOpen() mode flags are different to fopen(). A 'b' in mode "rb" has no effect when reading.
208
// http://www.remotesensing.org/libtiff/man/TIFFOpen.3tiff.html
209
if ( !m_buf.empty() )
210
{
211
m_buf_pos = 0;
212
TiffDecoderBufHelper* buf_helper = new TiffDecoderBufHelper(this->m_buf, this->m_buf_pos);
213
tif = TIFFClientOpen( "", "r", reinterpret_cast<thandle_t>(buf_helper), &TiffDecoderBufHelper::read,
214
&TiffDecoderBufHelper::write, &TiffDecoderBufHelper::seek,
215
&TiffDecoderBufHelper::close, &TiffDecoderBufHelper::size,
216
&TiffDecoderBufHelper::map, /*unmap=*/0 );
217
}
218
else
219
{
220
tif = TIFFOpen(m_filename.c_str(), "r");
221
}
222
}
223
224
if( tif )
225
{
226
uint32 wdth = 0, hght = 0;
227
uint16 photometric = 0;
228
m_tif = tif;
229
230
if( TIFFGetField( tif, TIFFTAG_IMAGEWIDTH, &wdth ) &&
231
TIFFGetField( tif, TIFFTAG_IMAGELENGTH, &hght ) &&
232
TIFFGetField( tif, TIFFTAG_PHOTOMETRIC, &photometric ))
233
{
234
uint16 bpp=8, ncn = photometric > 1 ? 3 : 1;
235
TIFFGetField( tif, TIFFTAG_BITSPERSAMPLE, &bpp );
236
TIFFGetField( tif, TIFFTAG_SAMPLESPERPIXEL, &ncn );
237
238
m_width = wdth;
239
m_height = hght;
240
if((bpp == 32 && ncn == 3) || photometric == PHOTOMETRIC_LOGLUV)
241
{
242
m_type = CV_32FC3;
243
m_hdr = true;
244
return true;
245
}
246
m_hdr = false;
247
248
if( bpp > 8 &&
249
((photometric > 2) ||
250
(ncn != 1 && ncn != 3 && ncn != 4)))
251
bpp = 8;
252
253
int wanted_channels = normalizeChannelsNumber(ncn);
254
switch(bpp)
255
{
256
case 8:
257
m_type = CV_MAKETYPE(CV_8U, photometric > 1 ? wanted_channels : 1);
258
result = true;
259
break;
260
case 16:
261
m_type = CV_MAKETYPE(CV_16U, photometric > 1 ? wanted_channels : 1);
262
result = true;
263
break;
264
case 32:
265
m_type = CV_MAKETYPE(CV_32F, photometric > 1 ? 3 : 1);
266
result = true;
267
break;
268
case 64:
269
m_type = CV_MAKETYPE(CV_64F, photometric > 1 ? 3 : 1);
270
result = true;
271
break;
272
}
273
}
274
}
275
276
if( !result )
277
close();
278
279
return result;
280
}
281
282
bool TiffDecoder::nextPage()
283
{
284
// Prepare the next page, if any.
285
return m_tif &&
286
TIFFReadDirectory(static_cast<TIFF*>(m_tif)) &&
287
readHeader();
288
}
289
290
bool TiffDecoder::readData( Mat& img )
291
{
292
if(m_hdr && img.type() == CV_32FC3)
293
{
294
return readData_32FC3(img);
295
}
296
if(img.type() == CV_32FC1)
297
{
298
return readData_32FC1(img);
299
}
300
bool result = false;
301
bool color = img.channels() > 1;
302
303
if( img.depth() != CV_8U && img.depth() != CV_16U && img.depth() != CV_32F && img.depth() != CV_64F )
304
return false;
305
306
if( m_tif && m_width && m_height )
307
{
308
TIFF* tif = (TIFF*)m_tif;
309
uint32 tile_width0 = m_width, tile_height0 = 0;
310
int x, y, i;
311
int is_tiled = TIFFIsTiled(tif);
312
uint16 photometric;
313
TIFFGetField( tif, TIFFTAG_PHOTOMETRIC, &photometric );
314
uint16 bpp = 8, ncn = photometric > 1 ? 3 : 1;
315
TIFFGetField( tif, TIFFTAG_BITSPERSAMPLE, &bpp );
316
TIFFGetField( tif, TIFFTAG_SAMPLESPERPIXEL, &ncn );
317
uint16 img_orientation = ORIENTATION_TOPLEFT;
318
TIFFGetField( tif, TIFFTAG_ORIENTATION, &img_orientation);
319
bool vert_flip = (img_orientation == ORIENTATION_BOTRIGHT) || (img_orientation == ORIENTATION_RIGHTBOT) ||
320
(img_orientation == ORIENTATION_BOTLEFT) || (img_orientation == ORIENTATION_LEFTBOT);
321
const int bitsPerByte = 8;
322
int dst_bpp = (int)(img.elemSize1() * bitsPerByte);
323
int wanted_channels = normalizeChannelsNumber(img.channels());
324
325
if(dst_bpp == 8)
326
{
327
char errmsg[1024];
328
if(!TIFFRGBAImageOK( tif, errmsg ))
329
{
330
close();
331
return false;
332
}
333
}
334
335
if( (!is_tiled) ||
336
(is_tiled &&
337
TIFFGetField( tif, TIFFTAG_TILEWIDTH, &tile_width0 ) &&
338
TIFFGetField( tif, TIFFTAG_TILELENGTH, &tile_height0 )))
339
{
340
if(!is_tiled)
341
TIFFGetField( tif, TIFFTAG_ROWSPERSTRIP, &tile_height0 );
342
343
if( tile_width0 <= 0 )
344
tile_width0 = m_width;
345
346
if( tile_height0 <= 0 ||
347
(!is_tiled && tile_height0 == std::numeric_limits<uint32>::max()) )
348
tile_height0 = m_height;
349
350
if(dst_bpp == 8) {
351
// we will use TIFFReadRGBA* functions, so allocate temporary buffer for 32bit RGBA
352
bpp = 8;
353
ncn = 4;
354
}
355
const size_t buffer_size = (bpp/bitsPerByte) * ncn * tile_height0 * tile_width0;
356
AutoBuffer<uchar> _buffer( buffer_size );
357
uchar* buffer = _buffer.data();
358
ushort* buffer16 = (ushort*)buffer;
359
float* buffer32 = (float*)buffer;
360
double* buffer64 = (double*)buffer;
361
int tileidx = 0;
362
363
for( y = 0; y < m_height; y += tile_height0 )
364
{
365
int tile_height = tile_height0;
366
367
if( y + tile_height > m_height )
368
tile_height = m_height - y;
369
370
uchar* data = img.ptr(vert_flip ? m_height - y - tile_height : y);
371
372
for( x = 0; x < m_width; x += tile_width0, tileidx++ )
373
{
374
int tile_width = tile_width0, ok;
375
376
if( x + tile_width > m_width )
377
tile_width = m_width - x;
378
379
switch(dst_bpp)
380
{
381
case 8:
382
{
383
uchar * bstart = buffer;
384
if( !is_tiled )
385
ok = TIFFReadRGBAStrip( tif, y, (uint32*)buffer );
386
else
387
{
388
ok = TIFFReadRGBATile( tif, x, y, (uint32*)buffer );
389
//Tiles fill the buffer from the bottom up
390
bstart += (tile_height0 - tile_height) * tile_width0 * 4;
391
}
392
if( !ok )
393
{
394
close();
395
return false;
396
}
397
398
for( i = 0; i < tile_height; i++ )
399
if( color )
400
{
401
if (wanted_channels == 4)
402
{
403
icvCvt_BGRA2RGBA_8u_C4R( bstart + i*tile_width0*4, 0,
404
data + x*4 + img.step*(tile_height - i - 1), 0,
405
cvSize(tile_width,1) );
406
}
407
else
408
{
409
icvCvt_BGRA2BGR_8u_C4C3R( bstart + i*tile_width0*4, 0,
410
data + x*3 + img.step*(tile_height - i - 1), 0,
411
cvSize(tile_width,1), 2 );
412
}
413
}
414
else
415
icvCvt_BGRA2Gray_8u_C4C1R( bstart + i*tile_width0*4, 0,
416
data + x + img.step*(tile_height - i - 1), 0,
417
cvSize(tile_width,1), 2 );
418
break;
419
}
420
421
case 16:
422
{
423
if( !is_tiled )
424
ok = (int)TIFFReadEncodedStrip( tif, tileidx, (uint32*)buffer, buffer_size ) >= 0;
425
else
426
ok = (int)TIFFReadEncodedTile( tif, tileidx, (uint32*)buffer, buffer_size ) >= 0;
427
428
if( !ok )
429
{
430
close();
431
return false;
432
}
433
434
for( i = 0; i < tile_height; i++ )
435
{
436
if( color )
437
{
438
if( ncn == 1 )
439
{
440
icvCvt_Gray2BGR_16u_C1C3R(buffer16 + i*tile_width0*ncn, 0,
441
(ushort*)(data + img.step*i) + x*3, 0,
442
cvSize(tile_width,1) );
443
}
444
else if( ncn == 3 )
445
{
446
icvCvt_RGB2BGR_16u_C3R(buffer16 + i*tile_width0*ncn, 0,
447
(ushort*)(data + img.step*i) + x*3, 0,
448
cvSize(tile_width,1) );
449
}
450
else if (ncn == 4)
451
{
452
if (wanted_channels == 4)
453
{
454
icvCvt_BGRA2RGBA_16u_C4R(buffer16 + i*tile_width0*ncn, 0,
455
(ushort*)(data + img.step*i) + x * 4, 0,
456
cvSize(tile_width, 1));
457
}
458
else
459
{
460
icvCvt_BGRA2BGR_16u_C4C3R(buffer16 + i*tile_width0*ncn, 0,
461
(ushort*)(data + img.step*i) + x * 3, 0,
462
cvSize(tile_width, 1), 2);
463
}
464
}
465
else
466
{
467
icvCvt_BGRA2BGR_16u_C4C3R(buffer16 + i*tile_width0*ncn, 0,
468
(ushort*)(data + img.step*i) + x*3, 0,
469
cvSize(tile_width,1), 2 );
470
}
471
}
472
else
473
{
474
if( ncn == 1 )
475
{
476
memcpy((ushort*)(data + img.step*i)+x,
477
buffer16 + i*tile_width0*ncn,
478
tile_width*sizeof(buffer16[0]));
479
}
480
else
481
{
482
icvCvt_BGRA2Gray_16u_CnC1R(buffer16 + i*tile_width0*ncn, 0,
483
(ushort*)(data + img.step*i) + x, 0,
484
cvSize(tile_width,1), ncn, 2 );
485
}
486
}
487
}
488
break;
489
}
490
491
case 32:
492
case 64:
493
{
494
if( !is_tiled )
495
ok = (int)TIFFReadEncodedStrip( tif, tileidx, buffer, buffer_size ) >= 0;
496
else
497
ok = (int)TIFFReadEncodedTile( tif, tileidx, buffer, buffer_size ) >= 0;
498
499
if( !ok || ncn != 1 )
500
{
501
close();
502
return false;
503
}
504
505
for( i = 0; i < tile_height; i++ )
506
{
507
if(dst_bpp == 32)
508
{
509
memcpy((float*)(data + img.step*i)+x,
510
buffer32 + i*tile_width0*ncn,
511
tile_width*sizeof(buffer32[0]));
512
}
513
else
514
{
515
memcpy((double*)(data + img.step*i)+x,
516
buffer64 + i*tile_width0*ncn,
517
tile_width*sizeof(buffer64[0]));
518
}
519
}
520
521
break;
522
}
523
default:
524
{
525
close();
526
return false;
527
}
528
}
529
}
530
}
531
532
result = true;
533
}
534
}
535
536
return result;
537
}
538
539
bool TiffDecoder::readData_32FC3(Mat& img)
540
{
541
int rows_per_strip = 0, photometric = 0;
542
if(!m_tif)
543
{
544
return false;
545
}
546
TIFF *tif = static_cast<TIFF*>(m_tif);
547
TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rows_per_strip);
548
TIFFGetField( tif, TIFFTAG_PHOTOMETRIC, &photometric );
549
TIFFSetField(tif, TIFFTAG_SGILOGDATAFMT, SGILOGDATAFMT_FLOAT);
550
int size = 3 * m_width * m_height * sizeof (float);
551
tstrip_t strip_size = 3 * m_width * rows_per_strip;
552
float *ptr = img.ptr<float>();
553
for (tstrip_t i = 0; i < TIFFNumberOfStrips(tif); i++, ptr += strip_size)
554
{
555
TIFFReadEncodedStrip(tif, i, ptr, size);
556
size -= strip_size * sizeof(float);
557
}
558
close();
559
if(photometric == PHOTOMETRIC_LOGLUV)
560
{
561
cvtColor(img, img, COLOR_XYZ2BGR);
562
}
563
else
564
{
565
cvtColor(img, img, COLOR_RGB2BGR);
566
}
567
return true;
568
}
569
570
bool TiffDecoder::readData_32FC1(Mat& img)
571
{
572
if(!m_tif)
573
{
574
return false;
575
}
576
TIFF *tif = static_cast<TIFF*>(m_tif);
577
578
uint32 img_width, img_height;
579
TIFFGetField(tif,TIFFTAG_IMAGEWIDTH, &img_width);
580
TIFFGetField(tif,TIFFTAG_IMAGELENGTH, &img_height);
581
if(img.size() != Size(img_width,img_height))
582
{
583
close();
584
return false;
585
}
586
tsize_t scanlength = TIFFScanlineSize(tif);
587
tdata_t buf = _TIFFmalloc(scanlength);
588
float* data;
589
bool result = true;
590
for (uint32 row = 0; row < img_height; row++)
591
{
592
if (TIFFReadScanline(tif, buf, row) != 1)
593
{
594
result = false;
595
break;
596
}
597
data=(float*)buf;
598
for (uint32 i=0; i<img_width; i++)
599
{
600
img.at<float>(row,i) = data[i];
601
}
602
}
603
_TIFFfree(buf);
604
close();
605
606
return result;
607
}
608
609
//////////////////////////////////////////////////////////////////////////////////////////
610
611
TiffEncoder::TiffEncoder()
612
{
613
m_description = "TIFF Files (*.tiff;*.tif)";
614
m_buf_supported = true;
615
}
616
617
TiffEncoder::~TiffEncoder()
618
{
619
}
620
621
ImageEncoder TiffEncoder::newEncoder() const
622
{
623
return makePtr<TiffEncoder>();
624
}
625
626
bool TiffEncoder::isFormatSupported( int depth ) const
627
{
628
return depth == CV_8U || depth == CV_16U || depth == CV_32F;
629
}
630
631
void TiffEncoder::writeTag( WLByteStream& strm, TiffTag tag,
632
TiffFieldType fieldType,
633
int count, int value )
634
{
635
strm.putWord( tag );
636
strm.putWord( fieldType );
637
strm.putDWord( count );
638
strm.putDWord( value );
639
}
640
641
class TiffEncoderBufHelper
642
{
643
public:
644
645
TiffEncoderBufHelper(std::vector<uchar> *buf)
646
: m_buf(buf), m_buf_pos(0)
647
{}
648
649
TIFF* open ()
650
{
651
return TIFFClientOpen( "", "w", reinterpret_cast<thandle_t>(this), &TiffEncoderBufHelper::read,
652
&TiffEncoderBufHelper::write, &TiffEncoderBufHelper::seek,
653
&TiffEncoderBufHelper::close, &TiffEncoderBufHelper::size,
654
/*map=*/0, /*unmap=*/0 );
655
}
656
657
static tmsize_t read( thandle_t /*handle*/, void* /*buffer*/, tmsize_t /*n*/ )
658
{
659
// Not used for encoding.
660
return 0;
661
}
662
663
static tmsize_t write( thandle_t handle, void* buffer, tmsize_t n )
664
{
665
TiffEncoderBufHelper *helper = reinterpret_cast<TiffEncoderBufHelper*>(handle);
666
size_t begin = (size_t)helper->m_buf_pos;
667
size_t end = begin + n;
668
if ( helper->m_buf->size() < end )
669
{
670
helper->m_buf->resize(end);
671
}
672
memcpy(&(*helper->m_buf)[begin], buffer, n);
673
helper->m_buf_pos = end;
674
return n;
675
}
676
677
static toff_t seek( thandle_t handle, toff_t offset, int whence )
678
{
679
TiffEncoderBufHelper *helper = reinterpret_cast<TiffEncoderBufHelper*>(handle);
680
const toff_t size = helper->m_buf->size();
681
toff_t new_pos = helper->m_buf_pos;
682
switch (whence)
683
{
684
case SEEK_SET:
685
new_pos = offset;
686
break;
687
case SEEK_CUR:
688
new_pos += offset;
689
break;
690
case SEEK_END:
691
new_pos = size + offset;
692
break;
693
}
694
helper->m_buf_pos = new_pos;
695
return new_pos;
696
}
697
698
static toff_t size( thandle_t handle )
699
{
700
TiffEncoderBufHelper *helper = reinterpret_cast<TiffEncoderBufHelper*>(handle);
701
return helper->m_buf->size();
702
}
703
704
static int close( thandle_t /*handle*/ )
705
{
706
// Do nothing.
707
return 0;
708
}
709
710
private:
711
712
std::vector<uchar>* m_buf;
713
toff_t m_buf_pos;
714
};
715
716
static void readParam(const std::vector<int>& params, int key, int& value)
717
{
718
for(size_t i = 0; i + 1 < params.size(); i += 2)
719
if(params[i] == key)
720
{
721
value = params[i+1];
722
break;
723
}
724
}
725
726
bool TiffEncoder::writeLibTiff( const std::vector<Mat>& img_vec, const std::vector<int>& params)
727
{
728
// do NOT put "wb" as the mode, because the b means "big endian" mode, not "binary" mode.
729
// http://www.remotesensing.org/libtiff/man/TIFFOpen.3tiff.html
730
TIFF* pTiffHandle;
731
732
TiffEncoderBufHelper buf_helper(m_buf);
733
if ( m_buf )
734
{
735
pTiffHandle = buf_helper.open();
736
}
737
else
738
{
739
pTiffHandle = TIFFOpen(m_filename.c_str(), "w");
740
}
741
if (!pTiffHandle)
742
{
743
return false;
744
}
745
746
//Settings that matter to all images
747
// defaults for now, maybe base them on params in the future
748
int compression = COMPRESSION_LZW;
749
int predictor = PREDICTOR_HORIZONTAL;
750
int resUnit = -1, dpiX = -1, dpiY = -1;
751
752
readParam(params, TIFFTAG_COMPRESSION, compression);
753
readParam(params, TIFFTAG_PREDICTOR, predictor);
754
readParam(params, IMWRITE_TIFF_RESUNIT, resUnit);
755
readParam(params, IMWRITE_TIFF_XDPI, dpiX);
756
readParam(params, IMWRITE_TIFF_YDPI, dpiY);
757
758
//Iterate through each image in the vector and write them out as Tiff directories
759
for (size_t page = 0; page < img_vec.size(); page++)
760
{
761
const Mat& img = img_vec[page];
762
int channels = img.channels();
763
int width = img.cols, height = img.rows;
764
int depth = img.depth();
765
766
int bitsPerChannel = -1;
767
switch (depth)
768
{
769
case CV_8U:
770
{
771
bitsPerChannel = 8;
772
break;
773
}
774
case CV_16U:
775
{
776
bitsPerChannel = 16;
777
break;
778
}
779
default:
780
{
781
TIFFClose(pTiffHandle);
782
return false;
783
}
784
}
785
786
const int bitsPerByte = 8;
787
size_t fileStep = (width * channels * bitsPerChannel) / bitsPerByte;
788
789
int rowsPerStrip = (int)((1 << 13) / fileStep);
790
readParam(params, TIFFTAG_ROWSPERSTRIP, rowsPerStrip);
791
792
if (rowsPerStrip < 1)
793
rowsPerStrip = 1;
794
795
if (rowsPerStrip > height)
796
rowsPerStrip = height;
797
798
int colorspace = channels > 1 ? PHOTOMETRIC_RGB : PHOTOMETRIC_MINISBLACK;
799
800
if (!TIFFSetField(pTiffHandle, TIFFTAG_IMAGEWIDTH, width)
801
|| !TIFFSetField(pTiffHandle, TIFFTAG_IMAGELENGTH, height)
802
|| !TIFFSetField(pTiffHandle, TIFFTAG_BITSPERSAMPLE, bitsPerChannel)
803
|| !TIFFSetField(pTiffHandle, TIFFTAG_COMPRESSION, compression)
804
|| !TIFFSetField(pTiffHandle, TIFFTAG_PHOTOMETRIC, colorspace)
805
|| !TIFFSetField(pTiffHandle, TIFFTAG_SAMPLESPERPIXEL, channels)
806
|| !TIFFSetField(pTiffHandle, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG)
807
|| !TIFFSetField(pTiffHandle, TIFFTAG_ROWSPERSTRIP, rowsPerStrip)
808
|| (img_vec.size() > 1 && (
809
!TIFFSetField(pTiffHandle, TIFFTAG_SUBFILETYPE, FILETYPE_PAGE)
810
|| !TIFFSetField(pTiffHandle, TIFFTAG_PAGENUMBER, page, img_vec.size() )))
811
)
812
{
813
TIFFClose(pTiffHandle);
814
return false;
815
}
816
817
if (compression != COMPRESSION_NONE && !TIFFSetField(pTiffHandle, TIFFTAG_PREDICTOR, predictor))
818
{
819
TIFFClose(pTiffHandle);
820
return false;
821
}
822
823
if (((resUnit >= RESUNIT_NONE && resUnit <= RESUNIT_CENTIMETER) && !TIFFSetField(pTiffHandle, TIFFTAG_RESOLUTIONUNIT, resUnit))
824
|| (dpiX >= 0 && !TIFFSetField(pTiffHandle, TIFFTAG_XRESOLUTION, (float)dpiX))
825
|| (dpiY >= 0 && !TIFFSetField(pTiffHandle, TIFFTAG_YRESOLUTION, (float)dpiY))
826
)
827
{
828
TIFFClose(pTiffHandle);
829
return false;
830
}
831
832
833
// row buffer, because TIFFWriteScanline modifies the original data!
834
size_t scanlineSize = TIFFScanlineSize(pTiffHandle);
835
AutoBuffer<uchar> _buffer(scanlineSize + 32);
836
uchar* buffer = _buffer.data();
837
if (!buffer)
838
{
839
TIFFClose(pTiffHandle);
840
return false;
841
}
842
843
for (int y = 0; y < height; ++y)
844
{
845
switch (channels)
846
{
847
case 1:
848
{
849
memcpy(buffer, img.ptr(y), scanlineSize);
850
break;
851
}
852
853
case 3:
854
{
855
if (depth == CV_8U)
856
icvCvt_BGR2RGB_8u_C3R( img.ptr(y), 0, buffer, 0, cvSize(width, 1));
857
else
858
icvCvt_BGR2RGB_16u_C3R( img.ptr<ushort>(y), 0, (ushort*)buffer, 0, cvSize(width, 1));
859
break;
860
}
861
862
case 4:
863
{
864
if (depth == CV_8U)
865
icvCvt_BGRA2RGBA_8u_C4R( img.ptr(y), 0, buffer, 0, cvSize(width, 1));
866
else
867
icvCvt_BGRA2RGBA_16u_C4R( img.ptr<ushort>(y), 0, (ushort*)buffer, 0, cvSize(width, 1));
868
break;
869
}
870
871
default:
872
{
873
TIFFClose(pTiffHandle);
874
return false;
875
}
876
}
877
878
int writeResult = TIFFWriteScanline(pTiffHandle, buffer, y, 0);
879
if (writeResult != 1)
880
{
881
TIFFClose(pTiffHandle);
882
return false;
883
}
884
}
885
886
TIFFWriteDirectory(pTiffHandle);
887
888
}
889
890
TIFFClose(pTiffHandle);
891
return true;
892
}
893
894
bool TiffEncoder::write_32FC3(const Mat& _img)
895
{
896
Mat img;
897
cvtColor(_img, img, COLOR_BGR2XYZ);
898
899
TIFF* tif;
900
901
TiffEncoderBufHelper buf_helper(m_buf);
902
if ( m_buf )
903
{
904
tif = buf_helper.open();
905
}
906
else
907
{
908
tif = TIFFOpen(m_filename.c_str(), "w");
909
}
910
911
if (!tif)
912
{
913
return false;
914
}
915
TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, img.cols);
916
TIFFSetField(tif, TIFFTAG_IMAGELENGTH, img.rows);
917
TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3);
918
TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_SGILOG);
919
TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_LOGLUV);
920
TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
921
TIFFSetField(tif, TIFFTAG_SGILOGDATAFMT, SGILOGDATAFMT_FLOAT);
922
TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, 1);
923
int strip_size = 3 * img.cols;
924
float *ptr = const_cast<float*>(img.ptr<float>());
925
for (int i = 0; i < img.rows; i++, ptr += strip_size)
926
{
927
TIFFWriteEncodedStrip(tif, i, ptr, strip_size * sizeof(float));
928
}
929
TIFFClose(tif);
930
return true;
931
}
932
933
bool TiffEncoder::write_32FC1(const Mat& _img)
934
{
935
936
TIFF* tif;
937
938
TiffEncoderBufHelper buf_helper(m_buf);
939
if ( m_buf )
940
{
941
tif = buf_helper.open();
942
}
943
else
944
{
945
tif = TIFFOpen(m_filename.c_str(), "w");
946
}
947
948
if (!tif)
949
{
950
return false;
951
}
952
953
TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, _img.cols);
954
TIFFSetField(tif, TIFFTAG_IMAGELENGTH, _img.rows);
955
TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1);
956
TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 32);
957
TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
958
TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_IEEEFP);
959
TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
960
for (uint32 row = 0; row < (uint32)_img.rows; row++)
961
{
962
if (TIFFWriteScanline(tif, (tdata_t)_img.ptr<float>(row), row, 1) != 1)
963
{
964
TIFFClose(tif);
965
return false;
966
}
967
}
968
TIFFWriteDirectory(tif);
969
TIFFClose(tif);
970
971
return true;
972
}
973
974
bool TiffEncoder::writemulti(const std::vector<Mat>& img_vec, const std::vector<int>& params)
975
{
976
return writeLibTiff(img_vec, params);
977
}
978
979
bool TiffEncoder::write( const Mat& img, const std::vector<int>& params)
980
{
981
int depth = img.depth();
982
983
if(img.type() == CV_32FC3)
984
{
985
return write_32FC3(img);
986
}
987
if(img.type() == CV_32FC1)
988
{
989
return write_32FC1(img);
990
}
991
992
CV_Assert(depth == CV_8U || depth == CV_16U);
993
994
std::vector<Mat> img_vec;
995
img_vec.push_back(img);
996
return writeLibTiff(img_vec, params);
997
}
998
999
} // namespace
1000
1001
#endif
1002
1003