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 // Intel License Agreement
11 // For Open Source Computer Vision Library
12 //
13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
14 // Third party copyrights are property of their respective owners.
15 //
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
18 //
19 // * Redistribution's of source code must retain the above copyright notice,
20 // this list of conditions and the following disclaimer.
21 //
22 // * Redistribution's in binary form must reproduce the above copyright notice,
23 // this list of conditions and the following disclaimer in the documentation
24 // and/or other materials provided with the distribution.
25 //
26 // * The name of Intel Corporation may not be used to endorse or promote products
27 // derived from this software without specific prior written permission.
28 //
29 // This software is provided by the copyright holders and contributors "as is" and
30 // any express or implied warranties, including, but not limited to, the implied
31 // warranties of merchantability and fitness for a particular purpose are disclaimed.
32 // In no event shall the Intel Corporation or contributors be liable for any direct,
33 // indirect, incidental, special, exemplary, or consequential damages
34 // (including, but not limited to, procurement of substitute goods or services;
35 // loss of use, data, or profits; or business interruption) however caused
36 // and on any theory of liability, whether in contract, strict liability,
37 // or tort (including negligence or otherwise) arising in any way out of
38 // the use of this software, even if advised of the possibility of such damage.
39 //
40 //M*/
41
42 /****************************************************************************************\
43 A part of the file implements TIFF reader on base of libtiff library
44 (see otherlibs/_graphics/readme.txt for copyright notice)
45 \****************************************************************************************/
46
47 #include "_highgui.h"
48 #include "grfmt_tiff.h"
49
50 static const char fmtSignTiffII[] = "II\x2a\x00";
51 static const char fmtSignTiffMM[] = "MM\x00\x2a";
52
GrFmtTiff()53 GrFmtTiff::GrFmtTiff()
54 {
55 m_sign_len = 4;
56 m_signature = "";
57 m_description = "TIFF Files (*.tiff;*.tif)";
58 }
59
~GrFmtTiff()60 GrFmtTiff::~GrFmtTiff()
61 {
62 }
63
CheckSignature(const char * signature)64 bool GrFmtTiff::CheckSignature( const char* signature )
65 {
66 return memcmp( signature, fmtSignTiffII, 4 ) == 0 ||
67 memcmp( signature, fmtSignTiffMM, 4 ) == 0;
68 }
69
70
NewReader(const char * filename)71 GrFmtReader* GrFmtTiff::NewReader( const char* filename )
72 {
73 return new GrFmtTiffReader( filename );
74 }
75
76
NewWriter(const char * filename)77 GrFmtWriter* GrFmtTiff::NewWriter( const char* filename )
78 {
79 return new GrFmtTiffWriter( filename );
80 }
81
82
83 #ifdef HAVE_TIFF
84
85 #include "tiff.h"
86 #include "tiffio.h"
87
88 static int grfmt_tiff_err_handler_init = 0;
89
GrFmtSilentTIFFErrorHandler(const char *,const char *,va_list)90 static void GrFmtSilentTIFFErrorHandler( const char*, const char*, va_list ) {}
91
GrFmtTiffReader(const char * filename)92 GrFmtTiffReader::GrFmtTiffReader( const char* filename ) : GrFmtReader( filename )
93 {
94 m_tif = 0;
95
96 if( !grfmt_tiff_err_handler_init )
97 {
98 grfmt_tiff_err_handler_init = 1;
99
100 TIFFSetErrorHandler( GrFmtSilentTIFFErrorHandler );
101 TIFFSetWarningHandler( GrFmtSilentTIFFErrorHandler );
102 }
103 }
104
105
~GrFmtTiffReader()106 GrFmtTiffReader::~GrFmtTiffReader()
107 {
108 }
109
110
Close()111 void GrFmtTiffReader::Close()
112 {
113 if( m_tif )
114 {
115 TIFF* tif = (TIFF*)m_tif;
116 TIFFClose( tif );
117 m_tif = 0;
118 }
119 }
120
121
CheckFormat(const char * signature)122 bool GrFmtTiffReader::CheckFormat( const char* signature )
123 {
124 return memcmp( signature, fmtSignTiffII, 4 ) == 0 ||
125 memcmp( signature, fmtSignTiffMM, 4 ) == 0;
126 }
127
128
ReadHeader()129 bool GrFmtTiffReader::ReadHeader()
130 {
131 char errmsg[1024];
132 bool result = false;
133
134 Close();
135 TIFF* tif = TIFFOpen( m_filename, "r" );
136
137 if( tif )
138 {
139 int width = 0, height = 0, photometric = 0, compression = 0;
140 m_tif = tif;
141
142 if( TIFFRGBAImageOK( tif, errmsg ) &&
143 TIFFGetField( tif, TIFFTAG_IMAGEWIDTH, &width ) &&
144 TIFFGetField( tif, TIFFTAG_IMAGELENGTH, &height ) &&
145 TIFFGetField( tif, TIFFTAG_PHOTOMETRIC, &photometric ) &&
146 (!TIFFGetField( tif, TIFFTAG_COMPRESSION, &compression ) ||
147 (compression != COMPRESSION_LZW &&
148 compression != COMPRESSION_OJPEG)))
149 {
150 m_width = width;
151 m_height = height;
152 m_iscolor = photometric > 1;
153
154 result = true;
155 }
156 }
157
158 if( !result )
159 Close();
160
161 return result;
162 }
163
164
ReadData(uchar * data,int step,int color)165 bool GrFmtTiffReader::ReadData( uchar* data, int step, int color )
166 {
167 bool result = false;
168 uchar* buffer = 0;
169
170 color = color > 0 || (color < 0 && m_iscolor);
171
172 if( m_tif && m_width && m_height )
173 {
174 TIFF* tif = (TIFF*)m_tif;
175 int tile_width0 = m_width, tile_height0 = 0;
176 int x, y, i;
177 int is_tiled = TIFFIsTiled(tif);
178
179 if( !is_tiled &&
180 TIFFGetField( tif, TIFFTAG_ROWSPERSTRIP, &tile_height0 ) ||
181 is_tiled &&
182 TIFFGetField( tif, TIFFTAG_TILEWIDTH, &tile_width0 ) &&
183 TIFFGetField( tif, TIFFTAG_TILELENGTH, &tile_height0 ))
184 {
185 if( tile_width0 <= 0 )
186 tile_width0 = m_width;
187
188 if( tile_height0 <= 0 )
189 tile_height0 = m_height;
190
191 buffer = new uchar[tile_height0*tile_width0*4];
192
193 for( y = 0; y < m_height; y += tile_height0, data += step*tile_height0 )
194 {
195 int tile_height = tile_height0;
196
197 if( y + tile_height > m_height )
198 tile_height = m_height - y;
199
200 for( x = 0; x < m_width; x += tile_width0 )
201 {
202 int tile_width = tile_width0, ok;
203
204 if( x + tile_width > m_width )
205 tile_width = m_width - x;
206
207 if( !is_tiled )
208 ok = TIFFReadRGBAStrip( tif, y, (uint32*)buffer );
209 else
210 ok = TIFFReadRGBATile( tif, x, y, (uint32*)buffer );
211
212 if( !ok )
213 goto exit_func;
214
215 for( i = 0; i < tile_height; i++ )
216 if( color )
217 icvCvt_BGRA2BGR_8u_C4C3R( buffer + i*tile_width*4, 0,
218 data + x*3 + step*(tile_height - i - 1), 0,
219 cvSize(tile_width,1), 2 );
220 else
221 icvCvt_BGRA2Gray_8u_C4C1R( buffer + i*tile_width*4, 0,
222 data + x + step*(tile_height - i - 1), 0,
223 cvSize(tile_width,1), 2 );
224 }
225 }
226
227 result = true;
228 }
229 }
230
231 exit_func:
232
233 Close();
234 delete[] buffer;
235
236 return result;
237 }
238
239 #else
240
241 static const int tiffMask[] = { 0xff, 0xff, 0xffffffff, 0xffff, 0xffffffff };
242
243 /************************ TIFF reader *****************************/
244
GrFmtTiffReader(const char * filename)245 GrFmtTiffReader::GrFmtTiffReader( const char* filename ) : GrFmtReader( filename )
246 {
247 m_offsets = 0;
248 m_maxoffsets = 0;
249 m_strips = -1;
250 m_max_pal_length = 0;
251 m_temp_palette = 0;
252 }
253
254
~GrFmtTiffReader()255 GrFmtTiffReader::~GrFmtTiffReader()
256 {
257 Close();
258
259 delete[] m_offsets;
260 delete[] m_temp_palette;
261 }
262
Close()263 void GrFmtTiffReader::Close()
264 {
265 m_strm.Close();
266 }
267
268
CheckFormat(const char * signature)269 bool GrFmtTiffReader::CheckFormat( const char* signature )
270 {
271 return memcmp( signature, fmtSignTiffII, 4 ) == 0 ||
272 memcmp( signature, fmtSignTiffMM, 4 ) == 0;
273 }
274
275
GetWordEx()276 int GrFmtTiffReader::GetWordEx()
277 {
278 int val = m_strm.GetWord();
279 if( m_byteorder == TIFF_ORDER_MM )
280 val = ((val)>>8)|(((val)&0xff)<<8);
281 return val;
282 }
283
284
GetDWordEx()285 int GrFmtTiffReader::GetDWordEx()
286 {
287 int val = m_strm.GetDWord();
288 if( m_byteorder == TIFF_ORDER_MM )
289 val = BSWAP( val );
290 return val;
291 }
292
293
ReadTable(int offset,int count,TiffFieldType fieldType,int * & array,int & arraysize)294 int GrFmtTiffReader::ReadTable( int offset, int count,
295 TiffFieldType fieldType,
296 int*& array, int& arraysize )
297 {
298 int i;
299
300 if( count < 0 )
301 return RBS_BAD_HEADER;
302
303 if( fieldType != TIFF_TYPE_SHORT &&
304 fieldType != TIFF_TYPE_LONG &&
305 fieldType != TIFF_TYPE_BYTE )
306 return RBS_BAD_HEADER;
307
308 if( count > arraysize )
309 {
310 delete[] array;
311 arraysize = arraysize*3/2;
312 if( arraysize < count )
313 arraysize = count;
314 array = new int[arraysize];
315 }
316
317 if( count > 1 )
318 {
319 int pos = m_strm.GetPos();
320 m_strm.SetPos( offset );
321
322 if( fieldType == TIFF_TYPE_LONG )
323 {
324 if( m_byteorder == TIFF_ORDER_MM )
325 for( i = 0; i < count; i++ )
326 array[i] = ((RMByteStream&)m_strm).GetDWord();
327 else
328 for( i = 0; i < count; i++ )
329 array[i] = ((RLByteStream&)m_strm).GetDWord();
330 }
331 else if( fieldType == TIFF_TYPE_SHORT )
332 {
333 if( m_byteorder == TIFF_ORDER_MM )
334 for( i = 0; i < count; i++ )
335 array[i] = ((RMByteStream&)m_strm).GetWord();
336 else
337 for( i = 0; i < count; i++ )
338 array[i] = ((RLByteStream&)m_strm).GetWord();
339 }
340 else // fieldType == TIFF_TYPE_BYTE
341 for( i = 0; i < count; i++ )
342 array[i] = m_strm.GetByte();
343
344 m_strm.SetPos(pos);
345 }
346 else
347 {
348 assert( (offset & ~tiffMask[fieldType]) == 0 );
349 array[0] = offset;
350 }
351
352 return 0;
353 }
354
355
ReadHeader()356 bool GrFmtTiffReader::ReadHeader()
357 {
358 bool result = false;
359 int photometric = -1;
360 int channels = 1;
361 int pal_length = -1;
362
363 const int MAX_CHANNELS = 4;
364 int bpp_arr[MAX_CHANNELS];
365
366 assert( strlen(m_filename) != 0 );
367 if( !m_strm.Open( m_filename )) return false;
368
369 m_width = -1;
370 m_height = -1;
371 m_strips = -1;
372 m_bpp = 1;
373 m_compression = TIFF_UNCOMP;
374 m_rows_per_strip = -1;
375 m_iscolor = false;
376
377 if( setjmp( m_strm.JmpBuf()) == 0 )
378 {
379 m_byteorder = (TiffByteOrder)m_strm.GetWord();
380 m_strm.Skip( 2 );
381 int header_offset = GetDWordEx();
382
383 m_strm.SetPos( header_offset );
384
385 // read the first tag directory
386 int i, j, count = GetWordEx();
387
388 for( i = 0; i < count; i++ )
389 {
390 // read tag
391 TiffTag tag = (TiffTag)GetWordEx();
392 TiffFieldType fieldType = (TiffFieldType)GetWordEx();
393 int count = GetDWordEx();
394 int value = GetDWordEx();
395 if( count == 1 )
396 {
397 if( m_byteorder == TIFF_ORDER_MM )
398 {
399 if( fieldType == TIFF_TYPE_SHORT )
400 value = (unsigned)value >> 16;
401 else if( fieldType == TIFF_TYPE_BYTE )
402 value = (unsigned)value >> 24;
403 }
404
405 value &= tiffMask[fieldType];
406 }
407
408 switch( tag )
409 {
410 case TIFF_TAG_WIDTH:
411 m_width = value;
412 break;
413
414 case TIFF_TAG_HEIGHT:
415 m_height = value;
416 break;
417
418 case TIFF_TAG_BITS_PER_SAMPLE:
419 {
420 int* bpp_arr_ref = bpp_arr;
421
422 if( count > MAX_CHANNELS )
423 BAD_HEADER_ERR();
424
425 if( ReadTable( value, count, fieldType, bpp_arr_ref, count ) < 0 )
426 BAD_HEADER_ERR();
427
428 for( j = 1; j < count; j++ )
429 {
430 if( bpp_arr[j] != bpp_arr[0] )
431 BAD_HEADER_ERR();
432 }
433
434 m_bpp = bpp_arr[0];
435 }
436
437 break;
438
439 case TIFF_TAG_COMPRESSION:
440 m_compression = (TiffCompression)value;
441 if( m_compression != TIFF_UNCOMP &&
442 m_compression != TIFF_HUFFMAN &&
443 m_compression != TIFF_PACKBITS )
444 BAD_HEADER_ERR();
445 break;
446
447 case TIFF_TAG_PHOTOMETRIC:
448 photometric = value;
449 if( (unsigned)photometric > 3 )
450 BAD_HEADER_ERR();
451 break;
452
453 case TIFF_TAG_STRIP_OFFSETS:
454 m_strips = count;
455 if( ReadTable( value, count, fieldType, m_offsets, m_maxoffsets ) < 0 )
456 BAD_HEADER_ERR();
457 break;
458
459 case TIFF_TAG_SAMPLES_PER_PIXEL:
460 channels = value;
461 if( channels != 1 && channels != 3 && channels != 4 )
462 BAD_HEADER_ERR();
463 break;
464
465 case TIFF_TAG_ROWS_PER_STRIP:
466 m_rows_per_strip = value;
467 break;
468
469 case TIFF_TAG_PLANAR_CONFIG:
470 {
471 int planar_config = value;
472 if( planar_config != 1 )
473 BAD_HEADER_ERR();
474 }
475 break;
476
477 case TIFF_TAG_COLOR_MAP:
478 if( fieldType != TIFF_TYPE_SHORT || count < 2 )
479 BAD_HEADER_ERR();
480 if( ReadTable( value, count, fieldType,
481 m_temp_palette, m_max_pal_length ) < 0 )
482 BAD_HEADER_ERR();
483 pal_length = count / 3;
484 if( pal_length > 256 )
485 BAD_HEADER_ERR();
486 for( i = 0; i < pal_length; i++ )
487 {
488 m_palette[i].r = (uchar)(m_temp_palette[i] >> 8);
489 m_palette[i].g = (uchar)(m_temp_palette[i + pal_length] >> 8);
490 m_palette[i].b = (uchar)(m_temp_palette[i + pal_length*2] >> 8);
491 }
492 break;
493 case TIFF_TAG_STRIP_COUNTS:
494 break;
495 }
496 }
497
498 if( m_strips == 1 && m_rows_per_strip == -1 )
499 m_rows_per_strip = m_height;
500
501 if( m_width > 0 && m_height > 0 && m_strips > 0 &&
502 (m_height + m_rows_per_strip - 1)/m_rows_per_strip == m_strips )
503 {
504 switch( m_bpp )
505 {
506 case 1:
507 if( photometric == 0 || photometric == 1 && channels == 1 )
508 {
509 FillGrayPalette( m_palette, m_bpp, photometric == 0 );
510 result = true;
511 m_iscolor = false;
512 }
513 break;
514 case 4:
515 case 8:
516 if( (photometric == 0 || photometric == 1 ||
517 photometric == 3 && pal_length == (1 << m_bpp)) &&
518 m_compression != TIFF_HUFFMAN && channels == 1 )
519 {
520 if( pal_length < 0 )
521 {
522 FillGrayPalette( m_palette, m_bpp, photometric == 0 );
523 m_iscolor = false;
524 }
525 else
526 {
527 m_iscolor = IsColorPalette( m_palette, m_bpp );
528 }
529 result = true;
530 }
531 else if( photometric == 2 && pal_length < 0 &&
532 (channels == 3 || channels == 4) &&
533 m_compression == TIFF_UNCOMP )
534 {
535 m_bpp = 8*channels;
536 m_iscolor = true;
537 result = true;
538 }
539 break;
540 default:
541 BAD_HEADER_ERR();
542 }
543 }
544 bad_header_exit:
545 ;
546 }
547
548 if( !result )
549 {
550 m_strips = -1;
551 m_width = m_height = -1;
552 m_strm.Close();
553 }
554
555 return result;
556 }
557
558
ReadData(uchar * data,int step,int color)559 bool GrFmtTiffReader::ReadData( uchar* data, int step, int color )
560 {
561 const int buffer_size = 1 << 12;
562 uchar buffer[buffer_size];
563 uchar gray_palette[256];
564 bool result = false;
565 uchar* src = buffer;
566 int src_pitch = (m_width*m_bpp + 7)/8;
567 int y = 0;
568
569 if( m_strips < 0 || !m_strm.IsOpened())
570 return false;
571
572 if( src_pitch+32 > buffer_size )
573 src = new uchar[src_pitch+32];
574
575 if( !color )
576 if( m_bpp <= 8 )
577 {
578 CvtPaletteToGray( m_palette, gray_palette, 1 << m_bpp );
579 }
580
581 if( setjmp( m_strm.JmpBuf()) == 0 )
582 {
583 for( int s = 0; s < m_strips; s++ )
584 {
585 int y_limit = m_rows_per_strip;
586
587 y_limit += y;
588 if( y_limit > m_height ) y_limit = m_height;
589
590 m_strm.SetPos( m_offsets[s] );
591
592 if( m_compression == TIFF_UNCOMP )
593 {
594 for( ; y < y_limit; y++, data += step )
595 {
596 m_strm.GetBytes( src, src_pitch );
597 if( color )
598 switch( m_bpp )
599 {
600 case 1:
601 FillColorRow1( data, src, m_width, m_palette );
602 break;
603 case 4:
604 FillColorRow4( data, src, m_width, m_palette );
605 break;
606 case 8:
607 FillColorRow8( data, src, m_width, m_palette );
608 break;
609 case 24:
610 icvCvt_RGB2BGR_8u_C3R( src, 0, data, 0, cvSize(m_width,1) );
611 break;
612 case 32:
613 icvCvt_BGRA2BGR_8u_C4C3R( src, 0, data, 0, cvSize(m_width,1), 2 );
614 break;
615 default:
616 assert(0);
617 goto bad_decoding_end;
618 }
619 else
620 switch( m_bpp )
621 {
622 case 1:
623 FillGrayRow1( data, src, m_width, gray_palette );
624 break;
625 case 4:
626 FillGrayRow4( data, src, m_width, gray_palette );
627 break;
628 case 8:
629 FillGrayRow8( data, src, m_width, gray_palette );
630 break;
631 case 24:
632 icvCvt_BGR2Gray_8u_C3C1R( src, 0, data, 0, cvSize(m_width,1), 2 );
633 break;
634 case 32:
635 icvCvt_BGRA2Gray_8u_C4C1R( src, 0, data, 0, cvSize(m_width,1), 2 );
636 break;
637 default:
638 assert(0);
639 goto bad_decoding_end;
640 }
641 }
642 }
643 else
644 {
645 }
646
647 result = true;
648
649 bad_decoding_end:
650
651 ;
652 }
653 }
654
655 if( src != buffer ) delete[] src;
656 return result;
657 }
658
659 #endif
660
661 //////////////////////////////////////////////////////////////////////////////////////////
662
GrFmtTiffWriter(const char * filename)663 GrFmtTiffWriter::GrFmtTiffWriter( const char* filename ) : GrFmtWriter( filename )
664 {
665 }
666
~GrFmtTiffWriter()667 GrFmtTiffWriter::~GrFmtTiffWriter()
668 {
669 }
670
WriteTag(TiffTag tag,TiffFieldType fieldType,int count,int value)671 void GrFmtTiffWriter::WriteTag( TiffTag tag, TiffFieldType fieldType,
672 int count, int value )
673 {
674 m_strm.PutWord( tag );
675 m_strm.PutWord( fieldType );
676 m_strm.PutDWord( count );
677 m_strm.PutDWord( value );
678 }
679
680
WriteImage(const uchar * data,int step,int width,int height,int,int channels)681 bool GrFmtTiffWriter::WriteImage( const uchar* data, int step,
682 int width, int height, int /*depth*/, int channels )
683 {
684 bool result = false;
685 int fileStep = width*channels;
686
687 assert( data && width > 0 && height > 0 && step >= fileStep);
688
689 if( m_strm.Open( m_filename ) )
690 {
691 int rowsPerStrip = (1 << 13)/fileStep;
692
693 if( rowsPerStrip < 1 )
694 rowsPerStrip = 1;
695
696 if( rowsPerStrip > height )
697 rowsPerStrip = height;
698
699 int i, stripCount = (height + rowsPerStrip - 1) / rowsPerStrip;
700 /*#if defined _DEBUG || !defined WIN32
701 int uncompressedRowSize = rowsPerStrip * fileStep;
702 #endif*/
703 int directoryOffset = 0;
704
705 int* stripOffsets = new int[stripCount];
706 short* stripCounts = new short[stripCount];
707 uchar* buffer = new uchar[fileStep + 32];
708 int stripOffsetsOffset = 0;
709 int stripCountsOffset = 0;
710 int bitsPerSample = 8; // TODO support 16 bit
711 int y = 0;
712
713 m_strm.PutBytes( fmtSignTiffII, 4 );
714 m_strm.PutDWord( directoryOffset );
715
716 // write an image data first (the most reasonable way
717 // for compressed images)
718 for( i = 0; i < stripCount; i++ )
719 {
720 int limit = y + rowsPerStrip;
721
722 if( limit > height )
723 limit = height;
724
725 stripOffsets[i] = m_strm.GetPos();
726
727 for( ; y < limit; y++, data += step )
728 {
729 if( channels == 3 )
730 icvCvt_BGR2RGB_8u_C3R( data, 0, buffer, 0, cvSize(width,1) );
731 else if( channels == 4 )
732 icvCvt_BGRA2RGBA_8u_C4R( data, 0, buffer, 0, cvSize(width,1) );
733
734 m_strm.PutBytes( channels > 1 ? buffer : data, fileStep );
735 }
736
737 stripCounts[i] = (short)(m_strm.GetPos() - stripOffsets[i]);
738 /*assert( stripCounts[i] == uncompressedRowSize ||
739 stripCounts[i] < uncompressedRowSize &&
740 i == stripCount - 1);*/
741 }
742
743 if( stripCount > 2 )
744 {
745 stripOffsetsOffset = m_strm.GetPos();
746 for( i = 0; i < stripCount; i++ )
747 m_strm.PutDWord( stripOffsets[i] );
748
749 stripCountsOffset = m_strm.GetPos();
750 for( i = 0; i < stripCount; i++ )
751 m_strm.PutWord( stripCounts[i] );
752 }
753 else if(stripCount == 2)
754 {
755 stripOffsetsOffset = m_strm.GetPos();
756 for (i = 0; i < stripCount; i++)
757 {
758 m_strm.PutDWord (stripOffsets [i]);
759 }
760 stripCountsOffset = stripCounts [0] + (stripCounts [1] << 16);
761 }
762 else
763 {
764 stripOffsetsOffset = stripOffsets[0];
765 stripCountsOffset = stripCounts[0];
766 }
767
768 if( channels > 1 )
769 {
770 bitsPerSample = m_strm.GetPos();
771 m_strm.PutWord(8);
772 m_strm.PutWord(8);
773 m_strm.PutWord(8);
774 if( channels == 4 )
775 m_strm.PutWord(8);
776 }
777
778 directoryOffset = m_strm.GetPos();
779
780 // write header
781 m_strm.PutWord( 9 );
782
783 /* warning: specification 5.0 of Tiff want to have tags in
784 ascending order. This is a non-fatal error, but this cause
785 warning with some tools. So, keep this in ascending order */
786
787 WriteTag( TIFF_TAG_WIDTH, TIFF_TYPE_LONG, 1, width );
788 WriteTag( TIFF_TAG_HEIGHT, TIFF_TYPE_LONG, 1, height );
789 WriteTag( TIFF_TAG_BITS_PER_SAMPLE,
790 TIFF_TYPE_SHORT, channels, bitsPerSample );
791 WriteTag( TIFF_TAG_COMPRESSION, TIFF_TYPE_LONG, 1, TIFF_UNCOMP );
792 WriteTag( TIFF_TAG_PHOTOMETRIC, TIFF_TYPE_SHORT, 1, channels > 1 ? 2 : 1 );
793
794 WriteTag( TIFF_TAG_STRIP_OFFSETS, TIFF_TYPE_LONG,
795 stripCount, stripOffsetsOffset );
796
797 WriteTag( TIFF_TAG_SAMPLES_PER_PIXEL, TIFF_TYPE_SHORT, 1, channels );
798 WriteTag( TIFF_TAG_ROWS_PER_STRIP, TIFF_TYPE_LONG, 1, rowsPerStrip );
799
800 WriteTag( TIFF_TAG_STRIP_COUNTS,
801 stripCount > 1 ? TIFF_TYPE_SHORT : TIFF_TYPE_LONG,
802 stripCount, stripCountsOffset );
803
804 m_strm.PutDWord(0);
805 m_strm.Close();
806
807 // write directory offset
808 FILE* f = fopen( m_filename, "r+b" );
809 buffer[0] = (uchar)directoryOffset;
810 buffer[1] = (uchar)(directoryOffset >> 8);
811 buffer[2] = (uchar)(directoryOffset >> 16);
812 buffer[3] = (uchar)(directoryOffset >> 24);
813
814 fseek( f, 4, SEEK_SET );
815 fwrite( buffer, 1, 4, f );
816 fclose(f);
817
818 delete[] stripOffsets;
819 delete[] stripCounts;
820 delete[] buffer;
821
822 result = true;
823 }
824 return result;
825 }
826
827