1 /*M///////////////////////////////////////////////////////////////////////////////////////
\r
3 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
\r
5 // By downloading, copying, installing or using the software you agree to this license.
\r
6 // If you do not agree to this license, do not download, install,
\r
7 // copy or use the software.
\r
10 // License Agreement
\r
11 // For Open Source Computer Vision Library
\r
13 // Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
\r
14 // Copyright (C) 2009, Willow Garage Inc., all rights reserved.
\r
15 // Third party copyrights are property of their respective owners.
\r
17 // Redistribution and use in source and binary forms, with or without modification,
\r
18 // are permitted provided that the following conditions are met:
\r
20 // * Redistribution's of source code must retain the above copyright notice,
\r
21 // this list of conditions and the following disclaimer.
\r
23 // * Redistribution's in binary form must reproduce the above copyright notice,
\r
24 // this list of conditions and the following disclaimer in the documentation
\r
25 // and/or other materials provided with the distribution.
\r
27 // * The name of the copyright holders may not be used to endorse or promote products
\r
28 // derived from this software without specific prior written permission.
\r
30 // This software is provided by the copyright holders and contributors "as is" and
\r
31 // any express or implied warranties, including, but not limited to, the implied
\r
32 // warranties of merchantability and fitness for a particular purpose are disclaimed.
\r
33 // In no event shall the Intel Corporation or contributors be liable for any direct,
\r
34 // indirect, incidental, special, exemplary, or consequential damages
\r
35 // (including, but not limited to, procurement of substitute goods or services;
\r
36 // loss of use, data, or profits; or business interruption) however caused
\r
37 // and on any theory of liability, whether in contract, strict liability,
\r
38 // or tort (including negligence or otherwise) arising in any way out of
\r
39 // the use of this software, even if advised of the possibility of such damage.
\r
43 /****************************************************************************************\
\r
44 A part of the file implements TIFF reader on base of libtiff library
\r
45 (see otherlibs/_graphics/readme.txt for copyright notice)
\r
46 \****************************************************************************************/
\r
48 #include "_highgui.h"
\r
49 #include "grfmt_tiff.h"
\r
53 static const char fmtSignTiffII[] = "II\x2a\x00";
\r
54 static const char fmtSignTiffMM[] = "MM\x00\x2a";
\r
61 static int grfmt_tiff_err_handler_init = 0;
\r
62 static void GrFmtSilentTIFFErrorHandler( const char*, const char*, va_list ) {}
\r
64 TiffDecoder::TiffDecoder()
\r
67 if( !grfmt_tiff_err_handler_init )
\r
69 grfmt_tiff_err_handler_init = 1;
\r
71 TIFFSetErrorHandler( GrFmtSilentTIFFErrorHandler );
\r
72 TIFFSetWarningHandler( GrFmtSilentTIFFErrorHandler );
\r
77 void TiffDecoder::close()
\r
81 TIFF* tif = (TIFF*)m_tif;
\r
87 TiffDecoder::~TiffDecoder()
\r
92 size_t TiffDecoder::signatureLength() const
\r
97 bool TiffDecoder::checkSignature( const string& signature ) const
\r
99 return signature.size() >= 4 &&
\r
100 (memcmp(signature.c_str(), fmtSignTiffII, 4) == 0 ||
\r
101 memcmp(signature.c_str(), fmtSignTiffMM, 4) == 0);
\r
104 ImageDecoder TiffDecoder::newDecoder() const
\r
106 return new TiffDecoder;
\r
109 bool TiffDecoder::readHeader()
\r
112 bool result = false;
\r
115 TIFF* tif = TIFFOpen( m_filename.c_str(), "rb" );
\r
119 int width = 0, height = 0, photometric = 0, compression = 0;
\r
122 if( TIFFRGBAImageOK( tif, errmsg ) &&
\r
123 TIFFGetField( tif, TIFFTAG_IMAGEWIDTH, &width ) &&
\r
124 TIFFGetField( tif, TIFFTAG_IMAGELENGTH, &height ) &&
\r
125 TIFFGetField( tif, TIFFTAG_PHOTOMETRIC, &photometric ) &&
\r
126 (!TIFFGetField( tif, TIFFTAG_COMPRESSION, &compression ) ||
\r
127 (compression != COMPRESSION_LZW &&
\r
128 compression != COMPRESSION_OJPEG)))
\r
132 m_type = photometric > 1 ? CV_8UC3 : CV_8UC1;
\r
145 bool TiffDecoder::readData( Mat& img )
\r
147 bool result = false;
\r
148 bool color = img.channels() > 1;
\r
149 uchar* data = img.data;
\r
150 int step = img.step;
\r
152 if( m_tif && m_width && m_height )
\r
154 TIFF* tif = (TIFF*)m_tif;
\r
155 int tile_width0 = m_width, tile_height0 = 0;
\r
157 int is_tiled = TIFFIsTiled(tif);
\r
160 TIFFGetField( tif, TIFFTAG_ROWSPERSTRIP, &tile_height0 )) ||
\r
162 TIFFGetField( tif, TIFFTAG_TILEWIDTH, &tile_width0 ) &&
\r
163 TIFFGetField( tif, TIFFTAG_TILELENGTH, &tile_height0 )))
\r
165 if( tile_width0 <= 0 )
\r
166 tile_width0 = m_width;
\r
168 if( tile_height0 <= 0 )
\r
169 tile_height0 = m_height;
\r
171 AutoBuffer<uchar> _buffer(tile_height0*tile_width0*4);
\r
172 uchar* buffer = _buffer;
\r
174 for( y = 0; y < m_height; y += tile_height0, data += step*tile_height0 )
\r
176 int tile_height = tile_height0;
\r
178 if( y + tile_height > m_height )
\r
179 tile_height = m_height - y;
\r
181 for( x = 0; x < m_width; x += tile_width0 )
\r
183 int tile_width = tile_width0, ok;
\r
185 if( x + tile_width > m_width )
\r
186 tile_width = m_width - x;
\r
189 ok = TIFFReadRGBAStrip( tif, y, (uint32*)buffer );
\r
191 ok = TIFFReadRGBATile( tif, x, y, (uint32*)buffer );
\r
199 for( i = 0; i < tile_height; i++ )
\r
201 icvCvt_BGRA2BGR_8u_C4C3R( buffer + i*tile_width*4, 0,
\r
202 data + x*3 + step*(tile_height - i - 1), 0,
\r
203 cvSize(tile_width,1), 2 );
\r
205 icvCvt_BGRA2Gray_8u_C4C1R( buffer + i*tile_width*4, 0,
\r
206 data + x + step*(tile_height - i - 1), 0,
\r
207 cvSize(tile_width,1), 2 );
\r
221 //////////////////////////////////////////////////////////////////////////////////////////
\r
223 TiffEncoder::TiffEncoder()
\r
225 m_description = "TIFF Files (*.tiff;*.tif)";
\r
226 m_buf_supported = true;
\r
229 TiffEncoder::~TiffEncoder()
\r
233 ImageEncoder TiffEncoder::newEncoder() const
\r
235 return new TiffEncoder;
\r
238 void TiffEncoder::writeTag( WLByteStream& strm, TiffTag tag,
\r
239 TiffFieldType fieldType,
\r
240 int count, int value )
\r
242 strm.putWord( tag );
\r
243 strm.putWord( fieldType );
\r
244 strm.putDWord( count );
\r
245 strm.putDWord( value );
\r
249 bool TiffEncoder::write( const Mat& img, const vector<int>& )
\r
251 int channels = img.channels();
\r
252 int width = img.cols, height = img.rows;
\r
253 int fileStep = width*channels;
\r
258 if( !strm.open(*m_buf) )
\r
261 else if( !strm.open(m_filename) )
\r
264 int rowsPerStrip = (1 << 13)/fileStep;
\r
266 if( rowsPerStrip < 1 )
\r
269 if( rowsPerStrip > height )
\r
270 rowsPerStrip = height;
\r
272 int i, stripCount = (height + rowsPerStrip - 1) / rowsPerStrip;
\r
275 m_buf->reserve( alignSize(stripCount*8 + fileStep*height + 256, 256) );
\r
277 /*#if defined _DEBUG || !defined WIN32
\r
278 int uncompressedRowSize = rowsPerStrip * fileStep;
\r
280 int directoryOffset = 0;
\r
282 AutoBuffer<int,1024> stripOffsets(stripCount);
\r
283 AutoBuffer<short,1024> stripCounts(stripCount);
\r
284 AutoBuffer<uchar,1024> _buffer(fileStep+32);
\r
285 uchar* buffer = _buffer;
\r
286 int stripOffsetsOffset = 0;
\r
287 int stripCountsOffset = 0;
\r
288 int bitsPerSample = 8; // TODO support 16 bit
\r
291 strm.putBytes( fmtSignTiffII, 4 );
\r
292 strm.putDWord( directoryOffset );
\r
294 // write an image data first (the most reasonable way
\r
295 // for compressed images)
\r
296 for( i = 0; i < stripCount; i++ )
\r
298 int limit = y + rowsPerStrip;
\r
300 if( limit > height )
\r
303 stripOffsets[i] = strm.getPos();
\r
305 for( ; y < limit; y++ )
\r
307 if( channels == 3 )
\r
308 icvCvt_BGR2RGB_8u_C3R( img.data + img.step*y, 0, buffer, 0, cvSize(width,1) );
\r
309 else if( channels == 4 )
\r
310 icvCvt_BGRA2RGBA_8u_C4R( img.data + img.step*y, 0, buffer, 0, cvSize(width,1) );
\r
312 strm.putBytes( channels > 1 ? buffer : img.data + img.step*y, fileStep );
\r
315 stripCounts[i] = (short)(strm.getPos() - stripOffsets[i]);
\r
316 /*assert( stripCounts[i] == uncompressedRowSize ||
\r
317 stripCounts[i] < uncompressedRowSize &&
\r
318 i == stripCount - 1);*/
\r
321 if( stripCount > 2 )
\r
323 stripOffsetsOffset = strm.getPos();
\r
324 for( i = 0; i < stripCount; i++ )
\r
325 strm.putDWord( stripOffsets[i] );
\r
327 stripCountsOffset = strm.getPos();
\r
328 for( i = 0; i < stripCount; i++ )
\r
329 strm.putWord( stripCounts[i] );
\r
331 else if(stripCount == 2)
\r
333 stripOffsetsOffset = strm.getPos();
\r
334 for (i = 0; i < stripCount; i++)
\r
336 strm.putDWord (stripOffsets [i]);
\r
338 stripCountsOffset = stripCounts [0] + (stripCounts [1] << 16);
\r
342 stripOffsetsOffset = stripOffsets[0];
\r
343 stripCountsOffset = stripCounts[0];
\r
348 bitsPerSample = strm.getPos();
\r
352 if( channels == 4 )
\r
356 directoryOffset = strm.getPos();
\r
361 /* warning: specification 5.0 of Tiff want to have tags in
\r
362 ascending order. This is a non-fatal error, but this cause
\r
363 warning with some tools. So, keep this in ascending order */
\r
365 writeTag( strm, TIFF_TAG_WIDTH, TIFF_TYPE_LONG, 1, width );
\r
366 writeTag( strm, TIFF_TAG_HEIGHT, TIFF_TYPE_LONG, 1, height );
\r
367 writeTag( strm, TIFF_TAG_BITS_PER_SAMPLE,
\r
368 TIFF_TYPE_SHORT, channels, bitsPerSample );
\r
369 writeTag( strm, TIFF_TAG_COMPRESSION, TIFF_TYPE_LONG, 1, TIFF_UNCOMP );
\r
370 writeTag( strm, TIFF_TAG_PHOTOMETRIC, TIFF_TYPE_SHORT, 1, channels > 1 ? 2 : 1 );
\r
372 writeTag( strm, TIFF_TAG_STRIP_OFFSETS, TIFF_TYPE_LONG,
\r
373 stripCount, stripOffsetsOffset );
\r
375 writeTag( strm, TIFF_TAG_SAMPLES_PER_PIXEL, TIFF_TYPE_SHORT, 1, channels );
\r
376 writeTag( strm, TIFF_TAG_ROWS_PER_STRIP, TIFF_TYPE_LONG, 1, rowsPerStrip );
\r
378 writeTag( strm, TIFF_TAG_STRIP_COUNTS,
\r
379 stripCount > 1 ? TIFF_TYPE_SHORT : TIFF_TYPE_LONG,
\r
380 stripCount, stripCountsOffset );
\r
387 (*m_buf)[4] = (uchar)directoryOffset;
\r
388 (*m_buf)[5] = (uchar)(directoryOffset >> 8);
\r
389 (*m_buf)[6] = (uchar)(directoryOffset >> 16);
\r
390 (*m_buf)[7] = (uchar)(directoryOffset >> 24);
\r
394 // write directory offset
\r
395 FILE* f = fopen( m_filename.c_str(), "r+b" );
\r
396 buffer[0] = (uchar)directoryOffset;
\r
397 buffer[1] = (uchar)(directoryOffset >> 8);
\r
398 buffer[2] = (uchar)(directoryOffset >> 16);
\r
399 buffer[3] = (uchar)(directoryOffset >> 24);
\r
401 fseek( f, 4, SEEK_SET );
\r
402 fwrite( buffer, 1, 4, f );
\r