1 | |
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 | #include "grfmt_tiff.hpp"
|
50 |
|
51 | namespace cv
|
52 | {
|
53 | static const char fmtSignTiffII[] = "II\x2a\x00";
|
54 | static const char fmtSignTiffMM[] = "MM\x00\x2a";
|
55 |
|
56 | #ifdef HAVE_TIFF
|
57 |
|
58 | #include "tiff.h"
|
59 | #include "tiffio.h"
|
60 |
|
61 | static int grfmt_tiff_err_handler_init = 0;
|
62 | static void GrFmtSilentTIFFErrorHandler( const char*, const char*, va_list ) {}
|
63 |
|
64 | TiffDecoder::TiffDecoder()
|
65 | {
|
66 | m_tif = 0;
|
67 | if( !grfmt_tiff_err_handler_init )
|
68 | {
|
69 | grfmt_tiff_err_handler_init = 1;
|
70 |
|
71 | TIFFSetErrorHandler( GrFmtSilentTIFFErrorHandler );
|
72 | TIFFSetWarningHandler( GrFmtSilentTIFFErrorHandler );
|
73 | }
|
74 | }
|
75 |
|
76 |
|
77 | void TiffDecoder::close()
|
78 | {
|
79 | if( m_tif )
|
80 | {
|
81 | TIFF* tif = (TIFF*)m_tif;
|
82 | TIFFClose( tif );
|
83 | m_tif = 0;
|
84 | }
|
85 | }
|
86 |
|
87 | TiffDecoder::~TiffDecoder()
|
88 | {
|
89 | close();
|
90 | }
|
91 |
|
92 | size_t TiffDecoder::signatureLength() const
|
93 | {
|
94 | return 4;
|
95 | }
|
96 |
|
97 | bool TiffDecoder::checkSignature( const string& signature ) const
|
98 | {
|
99 | return signature.size() >= 4 &&
|
100 | (memcmp(signature.c_str(), fmtSignTiffII, 4) == 0 ||
|
101 | memcmp(signature.c_str(), fmtSignTiffMM, 4) == 0);
|
102 | }
|
103 |
|
104 | ImageDecoder TiffDecoder::newDecoder() const
|
105 | {
|
106 | return new TiffDecoder;
|
107 | }
|
108 |
|
109 | bool TiffDecoder::readHeader()
|
110 | {
|
111 | char errmsg[1024];
|
112 | bool result = false;
|
113 |
|
114 | close();
|
115 | TIFF* tif = TIFFOpen( m_filename.c_str(), "rb" );
|
116 |
|
117 | if( tif )
|
118 | {
|
119 | int width = 0, height = 0, photometric = 0;
|
120 | m_tif = tif;
|
121 |
|
122 | if( TIFFRGBAImageOK( tif, errmsg ) &&
|
123 | TIFFGetField( tif, TIFFTAG_IMAGEWIDTH, &width ) &&
|
124 | TIFFGetField( tif, TIFFTAG_IMAGELENGTH, &height ) &&
|
125 | TIFFGetField( tif, TIFFTAG_PHOTOMETRIC, &photometric ))
|
126 | {
|
127 | int bpp=8, ncn = photometric > 1 ? 3 : 1;
|
128 | TIFFGetField( tif, TIFFTAG_BITSPERSAMPLE, &bpp );
|
129 | TIFFGetField( tif, TIFFTAG_SAMPLESPERPIXEL, &ncn );
|
130 |
|
131 | m_width = width;
|
132 | m_height = height;
|
133 | if( bpp > 8 &&
|
134 | ((photometric != 2 && photometric != 1) ||
|
135 | (ncn != 1 && ncn != 3 && ncn != 4)))
|
136 | bpp = 8;
|
137 | m_type = CV_MAKETYPE(bpp > 8 ? CV_16U : CV_8U, photometric > 1 ? 3 : 1);
|
138 | result = true;
|
139 | }
|
140 | }
|
141 |
|
142 | if( !result )
|
143 | close();
|
144 |
|
145 | return result;
|
146 | }
|
147 |
|
148 |
|
149 | bool TiffDecoder::readData( Mat& img )
|
150 | {
|
151 | bool result = false;
|
152 | bool color = img.channels() > 1;
|
153 | uchar* data = img.data;
|
154 | int step = (int)img.step;
|
155 |
|
156 | if( img.depth() != CV_8U && img.depth() != CV_16U )
|
157 | return false;
|
158 |
|
159 | if( m_tif && m_width && m_height )
|
160 | {
|
161 | TIFF* tif = (TIFF*)m_tif;
|
162 | int tile_width0 = m_width, tile_height0 = 0;
|
163 | int x, y, i;
|
164 | int is_tiled = TIFFIsTiled(tif);
|
165 | int photometric;
|
166 | TIFFGetField( tif, TIFFTAG_PHOTOMETRIC, &photometric );
|
167 | int bpp = 8, ncn = photometric > 1 ? 3 : 1;
|
168 | TIFFGetField( tif, TIFFTAG_BITSPERSAMPLE, &bpp );
|
169 | TIFFGetField( tif, TIFFTAG_SAMPLESPERPIXEL, &ncn );
|
170 | int dst_bpp = img.depth() == CV_8U ? 8 : 16;
|
171 |
|
172 | if( (!is_tiled &&
|
173 | TIFFGetField( tif, TIFFTAG_ROWSPERSTRIP, &tile_height0 )) ||
|
174 | (is_tiled &&
|
175 | TIFFGetField( tif, TIFFTAG_TILEWIDTH, &tile_width0 ) &&
|
176 | TIFFGetField( tif, TIFFTAG_TILELENGTH, &tile_height0 )))
|
177 | {
|
178 | if( tile_width0 <= 0 )
|
179 | tile_width0 = m_width;
|
180 |
|
181 | if( tile_height0 <= 0 )
|
182 | tile_height0 = m_height;
|
183 |
|
184 | AutoBuffer<uchar> _buffer(tile_height0*tile_width0*8);
|
185 | uchar* buffer = _buffer;
|
186 | ushort* buffer16 = (ushort*)buffer;
|
187 | int tileidx = 0;
|
188 |
|
189 | for( y = 0; y < m_height; y += tile_height0, data += step*tile_height0 )
|
190 | {
|
191 | int tile_height = tile_height0;
|
192 |
|
193 | if( y + tile_height > m_height )
|
194 | tile_height = m_height - y;
|
195 |
|
196 | for( x = 0; x < m_width; x += tile_width0, tileidx++ )
|
197 | {
|
198 | int tile_width = tile_width0, ok;
|
199 |
|
200 | if( x + tile_width > m_width )
|
201 | tile_width = m_width - x;
|
202 |
|
203 | if( dst_bpp == 8 )
|
204 | {
|
205 | if( !is_tiled )
|
206 | ok = TIFFReadRGBAStrip( tif, y, (uint32*)buffer );
|
207 | else
|
208 | ok = TIFFReadRGBATile( tif, x, y, (uint32*)buffer );
|
209 |
|
210 | if( !ok )
|
211 | {
|
212 | close();
|
213 | return false;
|
214 | }
|
215 |
|
216 | for( i = 0; i < tile_height; i++ )
|
217 | if( color )
|
218 | icvCvt_BGRA2BGR_8u_C4C3R( buffer + i*tile_width*4, 0,
|
219 | data + x*3 + step*(tile_height - i - 1), 0,
|
220 | cvSize(tile_width,1), 2 );
|
221 | else
|
222 | icvCvt_BGRA2Gray_8u_C4C1R( buffer + i*tile_width*4, 0,
|
223 | data + x + step*(tile_height - i - 1), 0,
|
224 | cvSize(tile_width,1), 2 );
|
225 | }
|
226 | else
|
227 | {
|
228 | if( !is_tiled )
|
229 | ok = (int)TIFFReadEncodedStrip( tif, tileidx, (uint32*)buffer, (tsize_t)-1 ) >= 0;
|
230 | else
|
231 | ok = (int)TIFFReadEncodedTile( tif, tileidx, (uint32*)buffer, (tsize_t)-1 ) >= 0;
|
232 |
|
233 | if( !ok )
|
234 | {
|
235 | close();
|
236 | return false;
|
237 | }
|
238 |
|
239 | for( i = 0; i < tile_height; i++ )
|
240 | {
|
241 | if( color )
|
242 | {
|
243 | if( ncn == 1 )
|
244 | {
|
245 | icvCvt_Gray2BGR_16u_C1C3R(buffer16 + i*tile_width*ncn, 0,
|
246 | (ushort*)(data + step*i) + x*3, 0,
|
247 | cvSize(tile_width,1) );
|
248 | }
|
249 | else if( ncn == 3 )
|
250 | {
|
251 | icvCvt_RGB2BGR_16u_C3R(buffer16 + i*tile_width*ncn, 0,
|
252 | (ushort*)(data + step*i) + x*3, 0,
|
253 | cvSize(tile_width,1) );
|
254 | }
|
255 | else
|
256 | {
|
257 | icvCvt_BGRA2BGR_16u_C4C3R(buffer16 + i*tile_width*ncn, 0,
|
258 | (ushort*)(data + step*i) + x*3, 0,
|
259 | cvSize(tile_width,1), 2 );
|
260 | }
|
261 | }
|
262 | else
|
263 | {
|
264 | if( ncn == 1 )
|
265 | {
|
266 | memcpy((ushort*)(data + step*i)+x,
|
267 | buffer16 + i*tile_width*ncn,
|
268 | tile_width*sizeof(buffer16[0]));
|
269 | }
|
270 | else
|
271 | {
|
272 | icvCvt_BGRA2Gray_16u_CnC1R(buffer16 + i*tile_width*ncn, 0,
|
273 | (ushort*)(data + step*i) + x, 0,
|
274 | cvSize(tile_width,1), ncn, 2 );
|
275 | }
|
276 | }
|
277 | }
|
278 | }
|
279 | }
|
280 | }
|
281 |
|
282 | result = true;
|
283 | }
|
284 | else if( (!is_tiled &&
|
285 | !(TIFFGetField( tif, TIFFTAG_ROWSPERSTRIP, &tile_height0 ))))
|
286 | {
|
287 | if( tile_width0 <= 0 )
|
288 | tile_width0 = m_width;
|
289 |
|
290 | if( tile_height0 <= 0 )
|
291 | tile_height0 = m_height;
|
292 |
|
293 | AutoBuffer<uchar> _buffer(tile_height0*tile_width0*8);
|
294 | uchar* buffer = _buffer;
|
295 | ushort* buffer16 = (ushort*)buffer;
|
296 | int tileidx = 0;
|
297 |
|
298 | for( y = 0; y < m_height; y += tile_height0, data += step*tile_height0 )
|
299 | {
|
300 | int tile_height = tile_height0;
|
301 |
|
302 | if( y + tile_height > m_height )
|
303 | tile_height = m_height - y;
|
304 |
|
305 | for( x = 0; x < m_width; x += tile_width0, tileidx++ )
|
306 | {
|
307 | int tile_width = tile_width0, ok;
|
308 |
|
309 | if( x + tile_width > m_width )
|
310 | tile_width = m_width - x;
|
311 |
|
312 | if( dst_bpp == 8 )
|
313 | {
|
314 | if( !is_tiled )
|
315 | ok = TIFFReadRGBAStrip( tif, y, (uint32*)buffer );
|
316 | else
|
317 | ok = TIFFReadRGBATile( tif, x, y, (uint32*)buffer );
|
318 |
|
319 | if( !ok )
|
320 | {
|
321 | close();
|
322 | return false;
|
323 | }
|
324 |
|
325 | for( i = 0; i < tile_height; i++ )
|
326 | if( color )
|
327 | icvCvt_BGRA2BGR_8u_C4C3R( buffer + i*tile_width*4, 0,
|
328 | data + x*3 + step*(tile_height - i - 1), 0,
|
329 | cvSize(tile_width,1), 2 );
|
330 | else
|
331 | icvCvt_BGRA2Gray_8u_C4C1R( buffer + i*tile_width*4, 0,
|
332 | data + x + step*(tile_height - i - 1), 0,
|
333 | cvSize(tile_width,1), 2 );
|
334 | }
|
335 | else
|
336 | {
|
337 | if( !is_tiled )
|
338 | ok = (int)TIFFReadEncodedStrip( tif, tileidx, (uint32*)buffer, (tsize_t)-1 ) >= 0;
|
339 | else
|
340 | ok = (int)TIFFReadEncodedTile( tif, tileidx, (uint32*)buffer, (tsize_t)-1 ) >= 0;
|
341 |
|
342 | if( !ok )
|
343 | {
|
344 | close();
|
345 | return false;
|
346 | }
|
347 |
|
348 | for( i = 0; i < tile_height; i++ )
|
349 | {
|
350 | if( color )
|
351 | {
|
352 | if( ncn == 1 )
|
353 | {
|
354 | icvCvt_Gray2BGR_16u_C1C3R(buffer16 + i*tile_width*ncn, 0,
|
355 | (ushort*)(data + step*i) + x*3, 0,
|
356 | cvSize(tile_width,1) );
|
357 | }
|
358 | else if( ncn == 3 )
|
359 | {
|
360 | icvCvt_RGB2BGR_16u_C3R(buffer16 + i*tile_width*ncn, 0,
|
361 | (ushort*)(data + step*i) + x*3, 0,
|
362 | cvSize(tile_width,1) );
|
363 | }
|
364 | else
|
365 | {
|
366 | icvCvt_BGRA2BGR_16u_C4C3R(buffer16 + i*tile_width*ncn, 0,
|
367 | (ushort*)(data + step*i) + x*3, 0,
|
368 | cvSize(tile_width,1), 2 );
|
369 | }
|
370 | }
|
371 | else
|
372 | {
|
373 | if( ncn == 1 )
|
374 | {
|
375 | memcpy((ushort*)(data + step*i)+x,
|
376 | buffer16 + i*tile_width*ncn,
|
377 | tile_width*sizeof(buffer16[0]));
|
378 | }
|
379 | else
|
380 | {
|
381 | icvCvt_BGRA2Gray_16u_CnC1R(buffer16 + i*tile_width*ncn, 0,
|
382 | (ushort*)(data + step*i) + x, 0,
|
383 | cvSize(tile_width,1), ncn, 2 );
|
384 | }
|
385 | }
|
386 | }
|
387 | }
|
388 | }
|
389 | }
|
390 |
|
391 | result = true;
|
392 | }
|
393 | }
|
394 |
|
395 | close();
|
396 | return result;
|
397 | }
|
398 |
|
399 | #endif
|
400 |
|
401 |
|
402 |
|
403 | TiffEncoder::TiffEncoder()
|
404 | {
|
405 | m_description = "TIFF Files (*.tiff;*.tif)";
|
406 | m_buf_supported = true;
|
407 | }
|
408 |
|
409 | TiffEncoder::~TiffEncoder()
|
410 | {
|
411 | }
|
412 |
|
413 | ImageEncoder TiffEncoder::newEncoder() const
|
414 | {
|
415 | return new TiffEncoder;
|
416 | }
|
417 |
|
418 | void TiffEncoder::writeTag( WLByteStream& strm, TiffTag tag,
|
419 | TiffFieldType fieldType,
|
420 | int count, int value )
|
421 | {
|
422 | strm.putWord( tag );
|
423 | strm.putWord( fieldType );
|
424 | strm.putDWord( count );
|
425 | strm.putDWord( value );
|
426 | }
|
427 |
|
428 |
|
429 | bool TiffEncoder::write( const Mat& img, const vector<int>& )
|
430 | {
|
431 | int channels = img.channels();
|
432 | int width = img.cols, height = img.rows;
|
433 | int fileStep = width*channels;
|
434 | WLByteStream strm;
|
435 |
|
436 | if( m_buf )
|
437 | {
|
438 | if( !strm.open(*m_buf) )
|
439 | return false;
|
440 | }
|
441 | else if( !strm.open(m_filename) )
|
442 | return false;
|
443 |
|
444 | int rowsPerStrip = (1 << 13)/fileStep;
|
445 |
|
446 | if( rowsPerStrip < 1 )
|
447 | rowsPerStrip = 1;
|
448 |
|
449 | if( rowsPerStrip > height )
|
450 | rowsPerStrip = height;
|
451 |
|
452 | int i, stripCount = (height + rowsPerStrip - 1) / rowsPerStrip;
|
453 |
|
454 | if( m_buf )
|
455 | m_buf->reserve( alignSize(stripCount*8 + fileStep*height + 256, 256) );
|
456 |
|
457 | |
458 | int uncompressedRowSize = rowsPerStrip * fileStep;
|
459 | #endif*/
|
460 | int directoryOffset = 0;
|
461 |
|
462 | AutoBuffer<int,1024> stripOffsets(stripCount);
|
463 | AutoBuffer<short,1024> stripCounts(stripCount);
|
464 | AutoBuffer<uchar,1024> _buffer(fileStep+32);
|
465 | uchar* buffer = _buffer;
|
466 | int stripOffsetsOffset = 0;
|
467 | int stripCountsOffset = 0;
|
468 | int bitsPerSample = 8;
|
469 | int y = 0;
|
470 |
|
471 | strm.putBytes( fmtSignTiffII, 4 );
|
472 | strm.putDWord( directoryOffset );
|
473 |
|
474 |
|
475 |
|
476 | for( i = 0; i < stripCount; i++ )
|
477 | {
|
478 | int limit = y + rowsPerStrip;
|
479 |
|
480 | if( limit > height )
|
481 | limit = height;
|
482 |
|
483 | stripOffsets[i] = strm.getPos();
|
484 |
|
485 | for( ; y < limit; y++ )
|
486 | {
|
487 | if( channels == 3 )
|
488 | icvCvt_BGR2RGB_8u_C3R( img.data + img.step*y, 0, buffer, 0, cvSize(width,1) );
|
489 | else if( channels == 4 )
|
490 | icvCvt_BGRA2RGBA_8u_C4R( img.data + img.step*y, 0, buffer, 0, cvSize(width,1) );
|
491 |
|
492 | strm.putBytes( channels > 1 ? buffer : img.data + img.step*y, fileStep );
|
493 | }
|
494 |
|
495 | stripCounts[i] = (short)(strm.getPos() - stripOffsets[i]);
|
496 | |
497 | stripCounts[i] < uncompressedRowSize &&
|
498 | i == stripCount - 1);*/
|
499 | }
|
500 |
|
501 | if( stripCount > 2 )
|
502 | {
|
503 | stripOffsetsOffset = strm.getPos();
|
504 | for( i = 0; i < stripCount; i++ )
|
505 | strm.putDWord( stripOffsets[i] );
|
506 |
|
507 | stripCountsOffset = strm.getPos();
|
508 | for( i = 0; i < stripCount; i++ )
|
509 | strm.putWord( stripCounts[i] );
|
510 | }
|
511 | else if(stripCount == 2)
|
512 | {
|
513 | stripOffsetsOffset = strm.getPos();
|
514 | for (i = 0; i < stripCount; i++)
|
515 | {
|
516 | strm.putDWord (stripOffsets [i]);
|
517 | }
|
518 | stripCountsOffset = stripCounts [0] + (stripCounts [1] << 16);
|
519 | }
|
520 | else
|
521 | {
|
522 | stripOffsetsOffset = stripOffsets[0];
|
523 | stripCountsOffset = stripCounts[0];
|
524 | }
|
525 |
|
526 | if( channels > 1 )
|
527 | {
|
528 | bitsPerSample = strm.getPos();
|
529 | strm.putWord(8);
|
530 | strm.putWord(8);
|
531 | strm.putWord(8);
|
532 | if( channels == 4 )
|
533 | strm.putWord(8);
|
534 | }
|
535 |
|
536 | directoryOffset = strm.getPos();
|
537 |
|
538 |
|
539 | strm.putWord( 9 );
|
540 |
|
541 | |
542 | ascending order. This is a non-fatal error, but this cause
|
543 | warning with some tools. So, keep this in ascending order */
|
544 |
|
545 | writeTag( strm, TIFF_TAG_WIDTH, TIFF_TYPE_LONG, 1, width );
|
546 | writeTag( strm, TIFF_TAG_HEIGHT, TIFF_TYPE_LONG, 1, height );
|
547 | writeTag( strm, TIFF_TAG_BITS_PER_SAMPLE,
|
548 | TIFF_TYPE_SHORT, channels, bitsPerSample );
|
549 | writeTag( strm, TIFF_TAG_COMPRESSION, TIFF_TYPE_LONG, 1, TIFF_UNCOMP );
|
550 | writeTag( strm, TIFF_TAG_PHOTOMETRIC, TIFF_TYPE_SHORT, 1, channels > 1 ? 2 : 1 );
|
551 |
|
552 | writeTag( strm, TIFF_TAG_STRIP_OFFSETS, TIFF_TYPE_LONG,
|
553 | stripCount, stripOffsetsOffset );
|
554 |
|
555 | writeTag( strm, TIFF_TAG_SAMPLES_PER_PIXEL, TIFF_TYPE_SHORT, 1, channels );
|
556 | writeTag( strm, TIFF_TAG_ROWS_PER_STRIP, TIFF_TYPE_LONG, 1, rowsPerStrip );
|
557 |
|
558 | writeTag( strm, TIFF_TAG_STRIP_COUNTS,
|
559 | stripCount > 1 ? TIFF_TYPE_SHORT : TIFF_TYPE_LONG,
|
560 | stripCount, stripCountsOffset );
|
561 |
|
562 | strm.putDWord(0);
|
563 | strm.close();
|
564 |
|
565 | if( m_buf )
|
566 | {
|
567 | (*m_buf)[4] = (uchar)directoryOffset;
|
568 | (*m_buf)[5] = (uchar)(directoryOffset >> 8);
|
569 | (*m_buf)[6] = (uchar)(directoryOffset >> 16);
|
570 | (*m_buf)[7] = (uchar)(directoryOffset >> 24);
|
571 | }
|
572 | else
|
573 | {
|
574 |
|
575 | FILE* f = fopen( m_filename.c_str(), "r+b" );
|
576 | buffer[0] = (uchar)directoryOffset;
|
577 | buffer[1] = (uchar)(directoryOffset >> 8);
|
578 | buffer[2] = (uchar)(directoryOffset >> 16);
|
579 | buffer[3] = (uchar)(directoryOffset >> 24);
|
580 |
|
581 | fseek( f, 4, SEEK_SET );
|
582 | fwrite( buffer, 1, 4, f );
|
583 | fclose(f);
|
584 | }
|
585 |
|
586 | return true;
|
587 | }
|
588 |
|
589 | }
|