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 | }
|
285 |
|
286 | close();
|
287 | return result;
|
288 | }
|
289 |
|
290 | #endif
|
291 |
|
292 |
|
293 |
|
294 | TiffEncoder::TiffEncoder()
|
295 | {
|
296 | m_description = "TIFF Files (*.tiff;*.tif)";
|
297 | m_buf_supported = true;
|
298 | }
|
299 |
|
300 | TiffEncoder::~TiffEncoder()
|
301 | {
|
302 | }
|
303 |
|
304 | ImageEncoder TiffEncoder::newEncoder() const
|
305 | {
|
306 | return new TiffEncoder;
|
307 | }
|
308 |
|
309 | void TiffEncoder::writeTag( WLByteStream& strm, TiffTag tag,
|
310 | TiffFieldType fieldType,
|
311 | int count, int value )
|
312 | {
|
313 | strm.putWord( tag );
|
314 | strm.putWord( fieldType );
|
315 | strm.putDWord( count );
|
316 | strm.putDWord( value );
|
317 | }
|
318 |
|
319 |
|
320 | bool TiffEncoder::write( const Mat& img, const vector<int>& )
|
321 | {
|
322 | int channels = img.channels();
|
323 | int width = img.cols, height = img.rows;
|
324 | int fileStep = width*channels;
|
325 | WLByteStream strm;
|
326 |
|
327 | if( m_buf )
|
328 | {
|
329 | if( !strm.open(*m_buf) )
|
330 | return false;
|
331 | }
|
332 | else if( !strm.open(m_filename) )
|
333 | return false;
|
334 |
|
335 | int rowsPerStrip = (1 << 13)/fileStep;
|
336 |
|
337 | if( rowsPerStrip < 1 )
|
338 | rowsPerStrip = 1;
|
339 |
|
340 | if( rowsPerStrip > height )
|
341 | rowsPerStrip = height;
|
342 |
|
343 | int i, stripCount = (height + rowsPerStrip - 1) / rowsPerStrip;
|
344 |
|
345 | if( m_buf )
|
346 | m_buf->reserve( alignSize(stripCount*8 + fileStep*height + 256, 256) );
|
347 |
|
348 | |
349 | int uncompressedRowSize = rowsPerStrip * fileStep;
|
350 | #endif*/
|
351 | int directoryOffset = 0;
|
352 |
|
353 | AutoBuffer<int,1024> stripOffsets(stripCount);
|
354 | AutoBuffer<short,1024> stripCounts(stripCount);
|
355 | AutoBuffer<uchar,1024> _buffer(fileStep+32);
|
356 | uchar* buffer = _buffer;
|
357 | int stripOffsetsOffset = 0;
|
358 | int stripCountsOffset = 0;
|
359 | int bitsPerSample = 8;
|
360 | int y = 0;
|
361 |
|
362 | strm.putBytes( fmtSignTiffII, 4 );
|
363 | strm.putDWord( directoryOffset );
|
364 |
|
365 |
|
366 |
|
367 | for( i = 0; i < stripCount; i++ )
|
368 | {
|
369 | int limit = y + rowsPerStrip;
|
370 |
|
371 | if( limit > height )
|
372 | limit = height;
|
373 |
|
374 | stripOffsets[i] = strm.getPos();
|
375 |
|
376 | for( ; y < limit; y++ )
|
377 | {
|
378 | if( channels == 3 )
|
379 | icvCvt_BGR2RGB_8u_C3R( img.data + img.step*y, 0, buffer, 0, cvSize(width,1) );
|
380 | else if( channels == 4 )
|
381 | icvCvt_BGRA2RGBA_8u_C4R( img.data + img.step*y, 0, buffer, 0, cvSize(width,1) );
|
382 |
|
383 | strm.putBytes( channels > 1 ? buffer : img.data + img.step*y, fileStep );
|
384 | }
|
385 |
|
386 | stripCounts[i] = (short)(strm.getPos() - stripOffsets[i]);
|
387 | |
388 | stripCounts[i] < uncompressedRowSize &&
|
389 | i == stripCount - 1);*/
|
390 | }
|
391 |
|
392 | if( stripCount > 2 )
|
393 | {
|
394 | stripOffsetsOffset = strm.getPos();
|
395 | for( i = 0; i < stripCount; i++ )
|
396 | strm.putDWord( stripOffsets[i] );
|
397 |
|
398 | stripCountsOffset = strm.getPos();
|
399 | for( i = 0; i < stripCount; i++ )
|
400 | strm.putWord( stripCounts[i] );
|
401 | }
|
402 | else if(stripCount == 2)
|
403 | {
|
404 | stripOffsetsOffset = strm.getPos();
|
405 | for (i = 0; i < stripCount; i++)
|
406 | {
|
407 | strm.putDWord (stripOffsets [i]);
|
408 | }
|
409 | stripCountsOffset = stripCounts [0] + (stripCounts [1] << 16);
|
410 | }
|
411 | else
|
412 | {
|
413 | stripOffsetsOffset = stripOffsets[0];
|
414 | stripCountsOffset = stripCounts[0];
|
415 | }
|
416 |
|
417 | if( channels > 1 )
|
418 | {
|
419 | bitsPerSample = strm.getPos();
|
420 | strm.putWord(8);
|
421 | strm.putWord(8);
|
422 | strm.putWord(8);
|
423 | if( channels == 4 )
|
424 | strm.putWord(8);
|
425 | }
|
426 |
|
427 | directoryOffset = strm.getPos();
|
428 |
|
429 |
|
430 | strm.putWord( 9 );
|
431 |
|
432 | |
433 | ascending order. This is a non-fatal error, but this cause
|
434 | warning with some tools. So, keep this in ascending order */
|
435 |
|
436 | writeTag( strm, TIFF_TAG_WIDTH, TIFF_TYPE_LONG, 1, width );
|
437 | writeTag( strm, TIFF_TAG_HEIGHT, TIFF_TYPE_LONG, 1, height );
|
438 | writeTag( strm, TIFF_TAG_BITS_PER_SAMPLE,
|
439 | TIFF_TYPE_SHORT, channels, bitsPerSample );
|
440 | writeTag( strm, TIFF_TAG_COMPRESSION, TIFF_TYPE_LONG, 1, TIFF_UNCOMP );
|
441 | writeTag( strm, TIFF_TAG_PHOTOMETRIC, TIFF_TYPE_SHORT, 1, channels > 1 ? 2 : 1 );
|
442 |
|
443 | writeTag( strm, TIFF_TAG_STRIP_OFFSETS, TIFF_TYPE_LONG,
|
444 | stripCount, stripOffsetsOffset );
|
445 |
|
446 | writeTag( strm, TIFF_TAG_SAMPLES_PER_PIXEL, TIFF_TYPE_SHORT, 1, channels );
|
447 | writeTag( strm, TIFF_TAG_ROWS_PER_STRIP, TIFF_TYPE_LONG, 1, rowsPerStrip );
|
448 |
|
449 | writeTag( strm, TIFF_TAG_STRIP_COUNTS,
|
450 | stripCount > 1 ? TIFF_TYPE_SHORT : TIFF_TYPE_LONG,
|
451 | stripCount, stripCountsOffset );
|
452 |
|
453 | strm.putDWord(0);
|
454 | strm.close();
|
455 |
|
456 | if( m_buf )
|
457 | {
|
458 | (*m_buf)[4] = (uchar)directoryOffset;
|
459 | (*m_buf)[5] = (uchar)(directoryOffset >> 8);
|
460 | (*m_buf)[6] = (uchar)(directoryOffset >> 16);
|
461 | (*m_buf)[7] = (uchar)(directoryOffset >> 24);
|
462 | }
|
463 | else
|
464 | {
|
465 |
|
466 | FILE* f = fopen( m_filename.c_str(), "r+b" );
|
467 | buffer[0] = (uchar)directoryOffset;
|
468 | buffer[1] = (uchar)(directoryOffset >> 8);
|
469 | buffer[2] = (uchar)(directoryOffset >> 16);
|
470 | buffer[3] = (uchar)(directoryOffset >> 24);
|
471 |
|
472 | fseek( f, 4, SEEK_SET );
|
473 | fwrite( buffer, 1, 4, f );
|
474 | fclose(f);
|
475 | }
|
476 |
|
477 | return true;
|
478 | }
|
479 |
|
480 | }
|