grfmt_tiff.cpp

Jeff Reeder, 2012-12-05 08:53 pm

Download (23 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
    bool result = false;
112
113
    close();
114
    TIFF* tif = TIFFOpen( m_filename.c_str(), "rb" );
115
116
    if( tif )
117
    {
118
        uint32 wdth = 0, hght = 0;
119
        uint16 photometric = 0;
120
        m_tif = tif;
121
122
        if( TIFFGetField( tif, TIFFTAG_IMAGEWIDTH, &wdth ) &&
123
            TIFFGetField( tif, TIFFTAG_IMAGELENGTH, &hght ) &&
124
            TIFFGetField( tif, TIFFTAG_PHOTOMETRIC, &photometric ))
125
        {
126
            uint16 bpp=8, ncn = photometric > 1 ? 3 : 1;
127
            TIFFGetField( tif, TIFFTAG_BITSPERSAMPLE, &bpp );
128
            TIFFGetField( tif, TIFFTAG_SAMPLESPERPIXEL, &ncn );
129
130
            m_width = wdth;
131
            m_height = hght;
132
            if( bpp > 8 &&
133
               ((photometric != 2 && photometric != 1) ||
134
                (ncn != 1 && ncn != 3 && ncn != 4)))
135
                bpp = 8;
136
137
            switch(bpp)
138
            {
139
                case 8:
140
                    m_type = CV_MAKETYPE(CV_8U, photometric > 1 ? 3 : 1);
141
                    break;
142
                case 16:
143
                    m_type = CV_MAKETYPE(CV_16U, photometric > 1 ? 3 : 1);
144
                    break;
145
146
                case 32:
147
                    m_type = CV_MAKETYPE(CV_32F, photometric > 1 ? 3 : 1);
148
                    break;
149
                case 64:
150
                    m_type = CV_MAKETYPE(CV_64F, photometric > 1 ? 3 : 1);
151
                    break;
152
153
                default:
154
                    result = false;
155
            }
156
            result = true;
157
        }
158
    }
159
160
    if( !result )
161
        close();
162
163
    return result;
164
}
165
166
167
bool  TiffDecoder::readData( Mat& img )
168
{
169
    bool result = false;
170
    bool color = img.channels() > 1;
171
    uchar* data = img.data;
172
    int step = (int)img.step;
173
174
    if( img.depth() != CV_8U && img.depth() != CV_16U && img.depth() != CV_32F && img.depth() != CV_64F )
175
        return false;
176
177
    if( m_tif && m_width && m_height )
178
    {
179
        TIFF* tif = (TIFF*)m_tif;
180
        uint32 tile_width0 = m_width, tile_height0 = 0;
181
        int x, y, i;
182
        int is_tiled = TIFFIsTiled(tif);
183
        uint16 photometric;
184
        TIFFGetField( tif, TIFFTAG_PHOTOMETRIC, &photometric );
185
        uint16 bpp = 8, ncn = photometric > 1 ? 3 : 1;
186
        TIFFGetField( tif, TIFFTAG_BITSPERSAMPLE, &bpp );
187
        TIFFGetField( tif, TIFFTAG_SAMPLESPERPIXEL, &ncn );
188
        const int bitsPerByte = 8;
189
        int dst_bpp = (int)(img.elemSize1() * bitsPerByte);
190
191
        if(dst_bpp == 8)
192
        {
193
            char errmsg[1024];
194
            if(!TIFFRGBAImageOK( tif, errmsg ))
195
            {
196
                close();
197
                return false;
198
            }
199
        }
200
201
        if( (!is_tiled) ||
202
            (is_tiled &&
203
            TIFFGetField( tif, TIFFTAG_TILEWIDTH, &tile_width0 ) &&
204
            TIFFGetField( tif, TIFFTAG_TILELENGTH, &tile_height0 )))
205
        {
206
            if(!is_tiled)
207
                TIFFGetField( tif, TIFFTAG_ROWSPERSTRIP, &tile_height0 );
208
209
            if( tile_width0 <= 0 )
210
                tile_width0 = m_width;
211
212
            if( tile_height0 <= 0 )
213
                tile_height0 = m_height;
214
215
            AutoBuffer<uchar> _buffer(tile_height0*tile_width0*8);
216
            uchar* buffer = _buffer;
217
            ushort* buffer16 = (ushort*)buffer;
218
            float* buffer32 = (float*)buffer;
219
            double* buffer64 = (double*)buffer;
220
            int tileidx = 0;
221
222
            for( y = 0; y < m_height; y += tile_height0, data += step*tile_height0 )
223
            {
224
                int tile_height = tile_height0;
225
226
                if( y + tile_height > m_height )
227
                    tile_height = m_height - y;
228
229
                for( x = 0; x < m_width; x += tile_width0, tileidx++ )
230
                {
231
                    int tile_width = tile_width0, ok;
232
233
                    if( x + tile_width > m_width )
234
                        tile_width = m_width - x;
235
236
                    switch(dst_bpp)
237
                    {
238
                        case 8:
239
                        {
240
                            if( !is_tiled )
241
                                ok = TIFFReadRGBAStrip( tif, y, (uint32*)buffer );
242
                            else
243
                                ok = TIFFReadRGBATile( tif, x, y, (uint32*)buffer );
244
245
                            if( !ok )
246
                            {
247
                                close();
248
                                return false;
249
                            }
250
251
                            for( i = 0; i < tile_height; i++ )
252
                                if( color )
253
                                    icvCvt_BGRA2BGR_8u_C4C3R( buffer + i*tile_width*4, 0,
254
                                                             data + x*3 + step*(tile_height - i - 1), 0,
255
                                                             cvSize(tile_width,1), 2 );
256
                                else
257
                                    icvCvt_BGRA2Gray_8u_C4C1R( buffer + i*tile_width*4, 0,
258
                                                              data + x + step*(tile_height - i - 1), 0,
259
                                                              cvSize(tile_width,1), 2 );
260
                            break;
261
                        }
262
263
                        case 16:
264
                        {
265
                            if( !is_tiled )
266
                                ok = (int)TIFFReadEncodedStrip( tif, tileidx, (uint32*)buffer, (tsize_t)-1 ) >= 0;
267
                            else
268
                                ok = (int)TIFFReadEncodedTile( tif, tileidx, (uint32*)buffer, (tsize_t)-1 ) >= 0;
269
270
                            if( !ok )
271
                            {
272
                                close();
273
                                return false;
274
                            }
275
276
                            for( i = 0; i < tile_height; i++ )
277
                            {
278
                                if( color )
279
                                {
280
                                    if( ncn == 1 )
281
                                    {
282
                                        icvCvt_Gray2BGR_16u_C1C3R(buffer16 + i*tile_width*ncn, 0,
283
                                                                  (ushort*)(data + step*i) + x*3, 0,
284
                                                                  cvSize(tile_width,1) );
285
                                    }
286
                                    else if( ncn == 3 )
287
                                    {
288
                                        icvCvt_RGB2BGR_16u_C3R(buffer16 + i*tile_width*ncn, 0,
289
                                                               (ushort*)(data + step*i) + x*3, 0,
290
                                                               cvSize(tile_width,1) );
291
                                    }
292
                                    else
293
                                    {
294
                                        icvCvt_BGRA2BGR_16u_C4C3R(buffer16 + i*tile_width*ncn, 0,
295
                                                               (ushort*)(data + step*i) + x*3, 0,
296
                                                               cvSize(tile_width,1), 2 );
297
                                    }
298
                                }
299
                                else
300
                                {
301
                                    if( ncn == 1 )
302
                                    {
303
                                        memcpy((ushort*)(data + step*i)+x,
304
                                               buffer16 + i*tile_width*ncn,
305
                                               tile_width*sizeof(buffer16[0]));
306
                                    }
307
                                    else
308
                                    {
309
                                        icvCvt_BGRA2Gray_16u_CnC1R(buffer16 + i*tile_width*ncn, 0,
310
                                                               (ushort*)(data + step*i) + x, 0,
311
                                                               cvSize(tile_width,1), ncn, 2 );
312
                                    }
313
                                }
314
                            }
315
                            break;
316
                        }
317
318
                        case 32:
319
                        case 64:
320
                        {
321
                            if( !is_tiled )
322
                                ok = (int)TIFFReadEncodedStrip( tif, tileidx, buffer, (tsize_t)-1 ) >= 0;
323
                            else
324
                                ok = (int)TIFFReadEncodedTile( tif, tileidx, buffer, (tsize_t)-1 ) >= 0;
325
326
                            if( !ok || ncn != 1 )
327
                            {
328
                                close();
329
                                return false;
330
                            }
331
332
                            for( i = 0; i < tile_height; i++ )
333
                            {
334
                                if(dst_bpp == 32)
335
                                {
336
                                    memcpy((float*)(data + step*i)+x,
337
                                           buffer32 + i*tile_width*ncn,
338
                                           tile_width*sizeof(buffer32[0]));
339
                                }
340
                                else
341
                                {
342
                                    memcpy((double*)(data + step*i)+x,
343
                                         buffer64 + i*tile_width*ncn,
344
                                         tile_width*sizeof(buffer64[0]));
345
                                }
346
                            }
347
348
                            break;
349
                        }
350
                        default:
351
                        {
352
                            close();
353
                            return false;
354
                        }
355
                    }
356
                }
357
            }
358
359
            result = true;
360
        }
361
    }
362
363
    close();
364
    return result;
365
}
366
367
#endif
368
369
//////////////////////////////////////////////////////////////////////////////////////////
370
371
TiffEncoder::TiffEncoder()
372
{
373
    m_description = "TIFF Files (*.tiff;*.tif)";
374
#ifdef HAVE_TIFF
375
    m_buf_supported = false;
376
#else
377
    m_buf_supported = true;
378
#endif
379
}
380
381
TiffEncoder::~TiffEncoder()
382
{
383
}
384
385
ImageEncoder TiffEncoder::newEncoder() const
386
{
387
    return new TiffEncoder;
388
}
389
390
bool TiffEncoder::isFormatSupported( int depth ) const
391
{
392
    return depth == CV_8U || depth == CV_16U;
393
}
394
395
void  TiffEncoder::writeTag( WLByteStream& strm, TiffTag tag,
396
                             TiffFieldType fieldType,
397
                             int count, int value )
398
{
399
    strm.putWord( tag );
400
    strm.putWord( fieldType );
401
    strm.putDWord( count );
402
    strm.putDWord( value );
403
}
404
405
#ifdef HAVE_TIFF
406
bool  TiffEncoder::writeLibTiff( const Mat& img, const vector<int>& /*params*/)
407
{
408
    int channels = img.channels();
409
    int width = img.cols, height = img.rows;
410
    int depth = img.depth();
411
412
    int bitsPerChannel = -1;
413
    switch (depth)
414
    {
415
        case CV_8U:
416
        {
417
            bitsPerChannel = 8;
418
            break;
419
        }
420
        case CV_16U:
421
        {
422
            bitsPerChannel = 16;
423
            break;
424
        }
425
        default:
426
        {
427
            return false;
428
        }
429
    }
430
431
    const int bitsPerByte = 8;
432
    size_t fileStep = (width * channels * bitsPerChannel) / bitsPerByte;
433
    int rowsPerStrip = (int)((1 << 13)/fileStep);
434
435
    if( rowsPerStrip < 1 )
436
        rowsPerStrip = 1;
437
438
    if( rowsPerStrip > height )
439
        rowsPerStrip = height;
440
441
442
    // do NOT put "wb" as the mode, because the b means "big endian" mode, not "binary" mode.
443
    // http://www.remotesensing.org/libtiff/man/TIFFOpen.3tiff.html
444
    TIFF* pTiffHandle = TIFFOpen(m_filename.c_str(), "w");
445
    if (!pTiffHandle)
446
    {
447
        return false;
448
    }
449
450
    // defaults for now, maybe base them on params in the future
451
    int   compression  = COMPRESSION_LZW;
452
    int   predictor    = PREDICTOR_HORIZONTAL;
453
454
    int   colorspace = channels > 1 ? PHOTOMETRIC_RGB : PHOTOMETRIC_MINISBLACK;
455
456
    if ( !TIFFSetField(pTiffHandle, TIFFTAG_IMAGEWIDTH, width)
457
      || !TIFFSetField(pTiffHandle, TIFFTAG_IMAGELENGTH, height)
458
      || !TIFFSetField(pTiffHandle, TIFFTAG_BITSPERSAMPLE, bitsPerChannel)
459
      || !TIFFSetField(pTiffHandle, TIFFTAG_COMPRESSION, compression)
460
      || !TIFFSetField(pTiffHandle, TIFFTAG_PHOTOMETRIC, colorspace)
461
      || !TIFFSetField(pTiffHandle, TIFFTAG_SAMPLESPERPIXEL, channels)
462
      || !TIFFSetField(pTiffHandle, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG)
463
      || !TIFFSetField(pTiffHandle, TIFFTAG_ROWSPERSTRIP, rowsPerStrip)
464
      || !TIFFSetField(pTiffHandle, TIFFTAG_PREDICTOR, predictor)
465
       )
466
    {
467
        TIFFClose(pTiffHandle);
468
        return false;
469
    }
470
471
    // row buffer, because TIFFWriteScanline modifies the original data!
472
    size_t scanlineSize = TIFFScanlineSize(pTiffHandle);
473
    AutoBuffer<uchar,1024> _buffer(scanlineSize+32);
474
    uchar* buffer = _buffer;
475
    if (!buffer)
476
    {
477
        TIFFClose(pTiffHandle);
478
        return false;
479
    }
480
481
    for (int y = 0; y < height; ++y)
482
    {
483
        switch(channels)
484
        {
485
            case 1:
486
            {
487
                memcpy(buffer, img.data + img.step * y, scanlineSize);
488
                break;
489
            }
490
491
            case 3:
492
            {
493
                if (depth == CV_8U)
494
                    icvCvt_BGR2RGB_8u_C3R( img.data + img.step*y, 0, buffer, 0, cvSize(width,1) );
495
                else
496
                    icvCvt_BGR2RGB_16u_C3R( (const ushort*)(img.data + img.step*y), 0, (ushort*)buffer, 0, cvSize(width,1) );
497
                break;
498
            }
499
500
            case 4:
501
            {
502
                if (depth == CV_8U)
503
                    icvCvt_BGRA2RGBA_8u_C4R( img.data + img.step*y, 0, buffer, 0, cvSize(width,1) );
504
                else
505
                    icvCvt_BGRA2RGBA_16u_C4R( (const ushort*)(img.data + img.step*y), 0, (ushort*)buffer, 0, cvSize(width,1) );
506
                break;
507
            }
508
509
            default:
510
            {
511
                TIFFClose(pTiffHandle);
512
                return false;
513
            }
514
        }
515
516
        int writeResult = TIFFWriteScanline(pTiffHandle, buffer, y, 0);
517
        if (writeResult != 1)
518
        {
519
            TIFFClose(pTiffHandle);
520
            return false;
521
        }
522
    }
523
524
    TIFFClose(pTiffHandle);
525
    return true;
526
}
527
528
#endif
529
530
#ifdef HAVE_TIFF
531
bool  TiffEncoder::write( const Mat& img, const vector<int>& params)
532
#else
533
bool  TiffEncoder::write( const Mat& img, const vector<int>& /*params*/)
534
#endif
535
{
536
    int channels = img.channels();
537
    int width = img.cols, height = img.rows;
538
    int depth = img.depth();
539
540
    if (depth != CV_8U && depth != CV_16U)
541
        return false;
542
543
    int bytesPerChannel = depth == CV_8U ? 1 : 2;
544
    int fileStep = width * channels * bytesPerChannel;
545
546
    WLByteStream strm;
547
548
    if( m_buf )
549
    {
550
        if( !strm.open(*m_buf) )
551
            return false;
552
    }
553
    else
554
    {
555
#ifdef HAVE_TIFF
556
      return writeLibTiff(img, params);
557
#else
558
      if( !strm.open(m_filename) )
559
          return false;
560
#endif
561
    }
562
563
    int rowsPerStrip = (1 << 13)/fileStep;
564
565
    if( rowsPerStrip < 1 )
566
        rowsPerStrip = 1;
567
568
    if( rowsPerStrip > height )
569
        rowsPerStrip = height;
570
571
    int i, stripCount = (height + rowsPerStrip - 1) / rowsPerStrip;
572
573
    if( m_buf )
574
        m_buf->reserve( alignSize(stripCount*8 + fileStep*height + 256, 256) );
575
576
/*#if defined _DEBUG || !defined WIN32
577
    int uncompressedRowSize = rowsPerStrip * fileStep;
578
#endif*/
579
    int directoryOffset = 0;
580
581
    AutoBuffer<int,1024> stripOffsets(stripCount);
582
    AutoBuffer<short,1024> stripCounts(stripCount);
583
    AutoBuffer<uchar,1024> _buffer(fileStep+32);
584
    uchar* buffer = _buffer;
585
    int  stripOffsetsOffset = 0;
586
    int  stripCountsOffset = 0;
587
    int  bitsPerSample = 8 * bytesPerChannel;
588
    int  y = 0;
589
590
    strm.putBytes( fmtSignTiffII, 4 );
591
    strm.putDWord( directoryOffset );
592
593
    // write an image data first (the most reasonable way
594
    // for compressed images)
595
    for( i = 0; i < stripCount; i++ )
596
    {
597
        int limit = y + rowsPerStrip;
598
599
        if( limit > height )
600
            limit = height;
601
602
        stripOffsets[i] = strm.getPos();
603
604
        for( ; y < limit; y++ )
605
        {
606
            if( channels == 3 )
607
            {
608
                if (depth == CV_8U)
609
                    icvCvt_BGR2RGB_8u_C3R( img.data + img.step*y, 0, buffer, 0, cvSize(width,1) );
610
                else
611
                    icvCvt_BGR2RGB_16u_C3R( (const ushort*)(img.data + img.step*y), 0, (ushort*)buffer, 0, cvSize(width,1) );
612
            }
613
            else
614
            {
615
              if( channels == 4 )
616
              {
617
                if (depth == CV_8U)
618
                    icvCvt_BGRA2RGBA_8u_C4R( img.data + img.step*y, 0, buffer, 0, cvSize(width,1) );
619
                else
620
                    icvCvt_BGRA2RGBA_16u_C4R( (const ushort*)(img.data + img.step*y), 0, (ushort*)buffer, 0, cvSize(width,1) );
621
              }
622
            }
623
624
            strm.putBytes( channels > 1 ? buffer : img.data + img.step*y, fileStep );
625
        }
626
627
        stripCounts[i] = (short)(strm.getPos() - stripOffsets[i]);
628
        /*assert( stripCounts[i] == uncompressedRowSize ||
629
                stripCounts[i] < uncompressedRowSize &&
630
                i == stripCount - 1);*/
631
    }
632
633
    if( stripCount > 2 )
634
    {
635
        stripOffsetsOffset = strm.getPos();
636
        for( i = 0; i < stripCount; i++ )
637
            strm.putDWord( stripOffsets[i] );
638
639
        stripCountsOffset = strm.getPos();
640
        for( i = 0; i < stripCount; i++ )
641
            strm.putWord( stripCounts[i] );
642
    }
643
    else if(stripCount == 2)
644
    {
645
        stripOffsetsOffset = strm.getPos();
646
        for (i = 0; i < stripCount; i++)
647
        {
648
            strm.putDWord (stripOffsets [i]);
649
        }
650
        stripCountsOffset = stripCounts [0] + (stripCounts [1] << 16);
651
    }
652
    else
653
    {
654
        stripOffsetsOffset = stripOffsets[0];
655
        stripCountsOffset = stripCounts[0];
656
    }
657
658
    if( channels > 1 )
659
    {
660
        int bitsPerSamplePos = strm.getPos();
661
        strm.putWord(bitsPerSample);
662
        strm.putWord(bitsPerSample);
663
        strm.putWord(bitsPerSample);
664
        if( channels == 4 )
665
            strm.putWord(bitsPerSample);
666
        bitsPerSample = bitsPerSamplePos;
667
    }
668
669
    directoryOffset = strm.getPos();
670
671
    // write header
672
    strm.putWord( 9 );
673
674
    /* warning: specification 5.0 of Tiff want to have tags in
675
       ascending order. This is a non-fatal error, but this cause
676
       warning with some tools. So, keep this in ascending order */
677
678
    writeTag( strm, TIFF_TAG_WIDTH, TIFF_TYPE_LONG, 1, width );
679
    writeTag( strm, TIFF_TAG_HEIGHT, TIFF_TYPE_LONG, 1, height );
680
    writeTag( strm, TIFF_TAG_BITS_PER_SAMPLE,
681
              TIFF_TYPE_SHORT, channels, bitsPerSample );
682
    writeTag( strm, TIFF_TAG_COMPRESSION, TIFF_TYPE_LONG, 1, TIFF_UNCOMP );
683
    writeTag( strm, TIFF_TAG_PHOTOMETRIC, TIFF_TYPE_SHORT, 1, channels > 1 ? 2 : 1 );
684
685
    writeTag( strm, TIFF_TAG_STRIP_OFFSETS, TIFF_TYPE_LONG,
686
              stripCount, stripOffsetsOffset );
687
688
    writeTag( strm, TIFF_TAG_SAMPLES_PER_PIXEL, TIFF_TYPE_SHORT, 1, channels );
689
    writeTag( strm, TIFF_TAG_ROWS_PER_STRIP, TIFF_TYPE_LONG, 1, rowsPerStrip );
690
691
    writeTag( strm, TIFF_TAG_STRIP_COUNTS,
692
              stripCount > 1 ? TIFF_TYPE_SHORT : TIFF_TYPE_LONG,
693
              stripCount, stripCountsOffset );
694
695
    strm.putDWord(0);
696
    strm.close();
697
698
    if( m_buf )
699
    {
700
        (*m_buf)[4] = (uchar)directoryOffset;
701
        (*m_buf)[5] = (uchar)(directoryOffset >> 8);
702
        (*m_buf)[6] = (uchar)(directoryOffset >> 16);
703
        (*m_buf)[7] = (uchar)(directoryOffset >> 24);
704
    }
705
    else
706
    {
707
        // write directory offset
708
        FILE* f = fopen( m_filename.c_str(), "r+b" );
709
        buffer[0] = (uchar)directoryOffset;
710
        buffer[1] = (uchar)(directoryOffset >> 8);
711
        buffer[2] = (uchar)(directoryOffset >> 16);
712
        buffer[3] = (uchar)(directoryOffset >> 24);
713
714
        fseek( f, 4, SEEK_SET );
715
        fwrite( buffer, 1, 4, f );
716
        fclose(f);
717
    }
718
719
    return true;
720
}
721
722
}