grfmt_tiff.cpp

The original file as present in highgui source - Aashish Kumar, 2012-10-03 09:57 am

Download (16.1 kB)

 
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
#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
/*#if defined _DEBUG || !defined WIN32
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; // TODO support 16 bit
360
    int  y = 0;
361
362
    strm.putBytes( fmtSignTiffII, 4 );
363
    strm.putDWord( directoryOffset );
364
365
    // write an image data first (the most reasonable way
366
    // for compressed images)
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
        /*assert( stripCounts[i] == uncompressedRowSize ||
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
    // write header
430
    strm.putWord( 9 );
431
432
    /* warning: specification 5.0 of Tiff want to have tags in
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
        // write directory offset
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
}