| /*M/////////////////////////////////////////////////////////////////////////////////////// |
| // |
| // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. |
| // |
| // By downloading, copying, installing or using the software you agree to this license. |
| // If you do not agree to this license, do not download, install, |
| // copy or use the software. |
| // |
| // |
| // Intel License Agreement |
| // For Open Source Computer Vision Library |
| // |
| // Copyright (C) 2000, Intel Corporation, all rights reserved. |
| // Third party copyrights are property of their respective owners. |
| // |
| // Redistribution and use in source and binary forms, with or without modification, |
| // are permitted provided that the following conditions are met: |
| // |
| // * Redistribution's of source code must retain the above copyright notice, |
| // this list of conditions and the following disclaimer. |
| // |
| // * Redistribution's in binary form must reproduce the above copyright notice, |
| // this list of conditions and the following disclaimer in the documentation |
| // and/or other materials provided with the distribution. |
| // |
| // * The name of Intel Corporation may not be used to endorse or promote products |
| // derived from this software without specific prior written permission. |
| // |
| // This software is provided by the copyright holders and contributors "as is" and |
| // any express or implied warranties, including, but not limited to, the implied |
| // warranties of merchantability and fitness for a particular purpose are disclaimed. |
| // In no event shall the Intel Corporation or contributors be liable for any direct, |
| // indirect, incidental, special, exemplary, or consequential damages |
| // (including, but not limited to, procurement of substitute goods or services; |
| // loss of use, data, or profits; or business interruption) however caused |
| // and on any theory of liability, whether in contract, strict liability, |
| // or tort (including negligence or otherwise) arising in any way out of |
| // the use of this software, even if advised of the possibility of such damage. |
| // |
| //M*/ |
| |
| /****************************************************************************************\ |
| A part of the file implements TIFF reader on base of libtiff library |
| (see otherlibs/_graphics/readme.txt for copyright notice) |
| \****************************************************************************************/ |
| |
| #include "_highgui.h" |
| #include "grfmt_tiff.h" |
| |
| static const char fmtSignTiffII[] = "II\x2a\x00"; |
| static const char fmtSignTiffMM[] = "MM\x00\x2a"; |
| |
| GrFmtTiff::GrFmtTiff() |
| { |
| m_sign_len = 4; |
| m_signature = ""; |
| m_description = "TIFF Files (*.tiff;*.tif)"; |
| } |
| |
| GrFmtTiff::~GrFmtTiff() |
| { |
| } |
| |
| bool GrFmtTiff::CheckSignature( const char* signature ) |
| { |
| return memcmp( signature, fmtSignTiffII, 4 ) == 0 || |
| memcmp( signature, fmtSignTiffMM, 4 ) == 0; |
| } |
| |
| |
| GrFmtReader* GrFmtTiff::NewReader( const char* filename ) |
| { |
| return new GrFmtTiffReader( filename ); |
| } |
| |
| |
| GrFmtWriter* GrFmtTiff::NewWriter( const char* filename ) |
| { |
| return new GrFmtTiffWriter( filename ); |
| } |
| |
| |
| #ifdef HAVE_TIFF |
| |
| #include "tiff.h" |
| #include "tiffio.h" |
| |
| static int grfmt_tiff_err_handler_init = 0; |
| |
| static void GrFmtSilentTIFFErrorHandler( const char*, const char*, va_list ) {} |
| |
| GrFmtTiffReader::GrFmtTiffReader( const char* filename ) : GrFmtReader( filename ) |
| { |
| m_tif = 0; |
| |
| if( !grfmt_tiff_err_handler_init ) |
| { |
| grfmt_tiff_err_handler_init = 1; |
| |
| TIFFSetErrorHandler( GrFmtSilentTIFFErrorHandler ); |
| TIFFSetWarningHandler( GrFmtSilentTIFFErrorHandler ); |
| } |
| } |
| |
| |
| GrFmtTiffReader::~GrFmtTiffReader() |
| { |
| } |
| |
| |
| void GrFmtTiffReader::Close() |
| { |
| if( m_tif ) |
| { |
| TIFF* tif = (TIFF*)m_tif; |
| TIFFClose( tif ); |
| m_tif = 0; |
| } |
| } |
| |
| |
| bool GrFmtTiffReader::CheckFormat( const char* signature ) |
| { |
| return memcmp( signature, fmtSignTiffII, 4 ) == 0 || |
| memcmp( signature, fmtSignTiffMM, 4 ) == 0; |
| } |
| |
| |
| bool GrFmtTiffReader::ReadHeader() |
| { |
| char errmsg[1024]; |
| bool result = false; |
| |
| Close(); |
| TIFF* tif = TIFFOpen( m_filename, "r" ); |
| |
| if( tif ) |
| { |
| int width = 0, height = 0, photometric = 0, compression = 0; |
| m_tif = tif; |
| |
| if( TIFFRGBAImageOK( tif, errmsg ) && |
| TIFFGetField( tif, TIFFTAG_IMAGEWIDTH, &width ) && |
| TIFFGetField( tif, TIFFTAG_IMAGELENGTH, &height ) && |
| TIFFGetField( tif, TIFFTAG_PHOTOMETRIC, &photometric ) && |
| (!TIFFGetField( tif, TIFFTAG_COMPRESSION, &compression ) || |
| (compression != COMPRESSION_LZW && |
| compression != COMPRESSION_OJPEG))) |
| { |
| m_width = width; |
| m_height = height; |
| m_iscolor = photometric > 1; |
| |
| result = true; |
| } |
| } |
| |
| if( !result ) |
| Close(); |
| |
| return result; |
| } |
| |
| |
| bool GrFmtTiffReader::ReadData( uchar* data, int step, int color ) |
| { |
| bool result = false; |
| uchar* buffer = 0; |
| |
| color = color > 0 || (color < 0 && m_iscolor); |
| |
| if( m_tif && m_width && m_height ) |
| { |
| TIFF* tif = (TIFF*)m_tif; |
| int tile_width0 = m_width, tile_height0 = 0; |
| int x, y, i; |
| int is_tiled = TIFFIsTiled(tif); |
| |
| if( !is_tiled && |
| TIFFGetField( tif, TIFFTAG_ROWSPERSTRIP, &tile_height0 ) || |
| is_tiled && |
| TIFFGetField( tif, TIFFTAG_TILEWIDTH, &tile_width0 ) && |
| TIFFGetField( tif, TIFFTAG_TILELENGTH, &tile_height0 )) |
| { |
| if( tile_width0 <= 0 ) |
| tile_width0 = m_width; |
| |
| if( tile_height0 <= 0 ) |
| tile_height0 = m_height; |
| |
| buffer = new uchar[tile_height0*tile_width0*4]; |
| |
| for( y = 0; y < m_height; y += tile_height0, data += step*tile_height0 ) |
| { |
| int tile_height = tile_height0; |
| |
| if( y + tile_height > m_height ) |
| tile_height = m_height - y; |
| |
| for( x = 0; x < m_width; x += tile_width0 ) |
| { |
| int tile_width = tile_width0, ok; |
| |
| if( x + tile_width > m_width ) |
| tile_width = m_width - x; |
| |
| if( !is_tiled ) |
| ok = TIFFReadRGBAStrip( tif, y, (uint32*)buffer ); |
| else |
| ok = TIFFReadRGBATile( tif, x, y, (uint32*)buffer ); |
| |
| if( !ok ) |
| goto exit_func; |
| |
| for( i = 0; i < tile_height; i++ ) |
| if( color ) |
| icvCvt_BGRA2BGR_8u_C4C3R( buffer + i*tile_width*4, 0, |
| data + x*3 + step*(tile_height - i - 1), 0, |
| cvSize(tile_width,1), 2 ); |
| else |
| icvCvt_BGRA2Gray_8u_C4C1R( buffer + i*tile_width*4, 0, |
| data + x + step*(tile_height - i - 1), 0, |
| cvSize(tile_width,1), 2 ); |
| } |
| } |
| |
| result = true; |
| } |
| } |
| |
| exit_func: |
| |
| Close(); |
| delete[] buffer; |
| |
| return result; |
| } |
| |
| #else |
| |
| static const int tiffMask[] = { 0xff, 0xff, 0xffffffff, 0xffff, 0xffffffff }; |
| |
| /************************ TIFF reader *****************************/ |
| |
| GrFmtTiffReader::GrFmtTiffReader( const char* filename ) : GrFmtReader( filename ) |
| { |
| m_offsets = 0; |
| m_maxoffsets = 0; |
| m_strips = -1; |
| m_max_pal_length = 0; |
| m_temp_palette = 0; |
| } |
| |
| |
| GrFmtTiffReader::~GrFmtTiffReader() |
| { |
| Close(); |
| |
| delete[] m_offsets; |
| delete[] m_temp_palette; |
| } |
| |
| void GrFmtTiffReader::Close() |
| { |
| m_strm.Close(); |
| } |
| |
| |
| bool GrFmtTiffReader::CheckFormat( const char* signature ) |
| { |
| return memcmp( signature, fmtSignTiffII, 4 ) == 0 || |
| memcmp( signature, fmtSignTiffMM, 4 ) == 0; |
| } |
| |
| |
| int GrFmtTiffReader::GetWordEx() |
| { |
| int val = m_strm.GetWord(); |
| if( m_byteorder == TIFF_ORDER_MM ) |
| val = ((val)>>8)|(((val)&0xff)<<8); |
| return val; |
| } |
| |
| |
| int GrFmtTiffReader::GetDWordEx() |
| { |
| int val = m_strm.GetDWord(); |
| if( m_byteorder == TIFF_ORDER_MM ) |
| val = BSWAP( val ); |
| return val; |
| } |
| |
| |
| int GrFmtTiffReader::ReadTable( int offset, int count, |
| TiffFieldType fieldType, |
| int*& array, int& arraysize ) |
| { |
| int i; |
| |
| if( count < 0 ) |
| return RBS_BAD_HEADER; |
| |
| if( fieldType != TIFF_TYPE_SHORT && |
| fieldType != TIFF_TYPE_LONG && |
| fieldType != TIFF_TYPE_BYTE ) |
| return RBS_BAD_HEADER; |
| |
| if( count > arraysize ) |
| { |
| delete[] array; |
| arraysize = arraysize*3/2; |
| if( arraysize < count ) |
| arraysize = count; |
| array = new int[arraysize]; |
| } |
| |
| if( count > 1 ) |
| { |
| int pos = m_strm.GetPos(); |
| m_strm.SetPos( offset ); |
| |
| if( fieldType == TIFF_TYPE_LONG ) |
| { |
| if( m_byteorder == TIFF_ORDER_MM ) |
| for( i = 0; i < count; i++ ) |
| array[i] = ((RMByteStream&)m_strm).GetDWord(); |
| else |
| for( i = 0; i < count; i++ ) |
| array[i] = ((RLByteStream&)m_strm).GetDWord(); |
| } |
| else if( fieldType == TIFF_TYPE_SHORT ) |
| { |
| if( m_byteorder == TIFF_ORDER_MM ) |
| for( i = 0; i < count; i++ ) |
| array[i] = ((RMByteStream&)m_strm).GetWord(); |
| else |
| for( i = 0; i < count; i++ ) |
| array[i] = ((RLByteStream&)m_strm).GetWord(); |
| } |
| else // fieldType == TIFF_TYPE_BYTE |
| for( i = 0; i < count; i++ ) |
| array[i] = m_strm.GetByte(); |
| |
| m_strm.SetPos(pos); |
| } |
| else |
| { |
| assert( (offset & ~tiffMask[fieldType]) == 0 ); |
| array[0] = offset; |
| } |
| |
| return 0; |
| } |
| |
| |
| bool GrFmtTiffReader::ReadHeader() |
| { |
| bool result = false; |
| int photometric = -1; |
| int channels = 1; |
| int pal_length = -1; |
| |
| const int MAX_CHANNELS = 4; |
| int bpp_arr[MAX_CHANNELS]; |
| |
| assert( strlen(m_filename) != 0 ); |
| if( !m_strm.Open( m_filename )) return false; |
| |
| m_width = -1; |
| m_height = -1; |
| m_strips = -1; |
| m_bpp = 1; |
| m_compression = TIFF_UNCOMP; |
| m_rows_per_strip = -1; |
| m_iscolor = false; |
| |
| if( setjmp( m_strm.JmpBuf()) == 0 ) |
| { |
| m_byteorder = (TiffByteOrder)m_strm.GetWord(); |
| m_strm.Skip( 2 ); |
| int header_offset = GetDWordEx(); |
| |
| m_strm.SetPos( header_offset ); |
| |
| // read the first tag directory |
| int i, j, count = GetWordEx(); |
| |
| for( i = 0; i < count; i++ ) |
| { |
| // read tag |
| TiffTag tag = (TiffTag)GetWordEx(); |
| TiffFieldType fieldType = (TiffFieldType)GetWordEx(); |
| int count = GetDWordEx(); |
| int value = GetDWordEx(); |
| if( count == 1 ) |
| { |
| if( m_byteorder == TIFF_ORDER_MM ) |
| { |
| if( fieldType == TIFF_TYPE_SHORT ) |
| value = (unsigned)value >> 16; |
| else if( fieldType == TIFF_TYPE_BYTE ) |
| value = (unsigned)value >> 24; |
| } |
| |
| value &= tiffMask[fieldType]; |
| } |
| |
| switch( tag ) |
| { |
| case TIFF_TAG_WIDTH: |
| m_width = value; |
| break; |
| |
| case TIFF_TAG_HEIGHT: |
| m_height = value; |
| break; |
| |
| case TIFF_TAG_BITS_PER_SAMPLE: |
| { |
| int* bpp_arr_ref = bpp_arr; |
| |
| if( count > MAX_CHANNELS ) |
| BAD_HEADER_ERR(); |
| |
| if( ReadTable( value, count, fieldType, bpp_arr_ref, count ) < 0 ) |
| BAD_HEADER_ERR(); |
| |
| for( j = 1; j < count; j++ ) |
| { |
| if( bpp_arr[j] != bpp_arr[0] ) |
| BAD_HEADER_ERR(); |
| } |
| |
| m_bpp = bpp_arr[0]; |
| } |
| |
| break; |
| |
| case TIFF_TAG_COMPRESSION: |
| m_compression = (TiffCompression)value; |
| if( m_compression != TIFF_UNCOMP && |
| m_compression != TIFF_HUFFMAN && |
| m_compression != TIFF_PACKBITS ) |
| BAD_HEADER_ERR(); |
| break; |
| |
| case TIFF_TAG_PHOTOMETRIC: |
| photometric = value; |
| if( (unsigned)photometric > 3 ) |
| BAD_HEADER_ERR(); |
| break; |
| |
| case TIFF_TAG_STRIP_OFFSETS: |
| m_strips = count; |
| if( ReadTable( value, count, fieldType, m_offsets, m_maxoffsets ) < 0 ) |
| BAD_HEADER_ERR(); |
| break; |
| |
| case TIFF_TAG_SAMPLES_PER_PIXEL: |
| channels = value; |
| if( channels != 1 && channels != 3 && channels != 4 ) |
| BAD_HEADER_ERR(); |
| break; |
| |
| case TIFF_TAG_ROWS_PER_STRIP: |
| m_rows_per_strip = value; |
| break; |
| |
| case TIFF_TAG_PLANAR_CONFIG: |
| { |
| int planar_config = value; |
| if( planar_config != 1 ) |
| BAD_HEADER_ERR(); |
| } |
| break; |
| |
| case TIFF_TAG_COLOR_MAP: |
| if( fieldType != TIFF_TYPE_SHORT || count < 2 ) |
| BAD_HEADER_ERR(); |
| if( ReadTable( value, count, fieldType, |
| m_temp_palette, m_max_pal_length ) < 0 ) |
| BAD_HEADER_ERR(); |
| pal_length = count / 3; |
| if( pal_length > 256 ) |
| BAD_HEADER_ERR(); |
| for( i = 0; i < pal_length; i++ ) |
| { |
| m_palette[i].r = (uchar)(m_temp_palette[i] >> 8); |
| m_palette[i].g = (uchar)(m_temp_palette[i + pal_length] >> 8); |
| m_palette[i].b = (uchar)(m_temp_palette[i + pal_length*2] >> 8); |
| } |
| break; |
| case TIFF_TAG_STRIP_COUNTS: |
| break; |
| } |
| } |
| |
| if( m_strips == 1 && m_rows_per_strip == -1 ) |
| m_rows_per_strip = m_height; |
| |
| if( m_width > 0 && m_height > 0 && m_strips > 0 && |
| (m_height + m_rows_per_strip - 1)/m_rows_per_strip == m_strips ) |
| { |
| switch( m_bpp ) |
| { |
| case 1: |
| if( photometric == 0 || photometric == 1 && channels == 1 ) |
| { |
| FillGrayPalette( m_palette, m_bpp, photometric == 0 ); |
| result = true; |
| m_iscolor = false; |
| } |
| break; |
| case 4: |
| case 8: |
| if( (photometric == 0 || photometric == 1 || |
| photometric == 3 && pal_length == (1 << m_bpp)) && |
| m_compression != TIFF_HUFFMAN && channels == 1 ) |
| { |
| if( pal_length < 0 ) |
| { |
| FillGrayPalette( m_palette, m_bpp, photometric == 0 ); |
| m_iscolor = false; |
| } |
| else |
| { |
| m_iscolor = IsColorPalette( m_palette, m_bpp ); |
| } |
| result = true; |
| } |
| else if( photometric == 2 && pal_length < 0 && |
| (channels == 3 || channels == 4) && |
| m_compression == TIFF_UNCOMP ) |
| { |
| m_bpp = 8*channels; |
| m_iscolor = true; |
| result = true; |
| } |
| break; |
| default: |
| BAD_HEADER_ERR(); |
| } |
| } |
| bad_header_exit: |
| ; |
| } |
| |
| if( !result ) |
| { |
| m_strips = -1; |
| m_width = m_height = -1; |
| m_strm.Close(); |
| } |
| |
| return result; |
| } |
| |
| |
| bool GrFmtTiffReader::ReadData( uchar* data, int step, int color ) |
| { |
| const int buffer_size = 1 << 12; |
| uchar buffer[buffer_size]; |
| uchar gray_palette[256]; |
| bool result = false; |
| uchar* src = buffer; |
| int src_pitch = (m_width*m_bpp + 7)/8; |
| int y = 0; |
| |
| if( m_strips < 0 || !m_strm.IsOpened()) |
| return false; |
| |
| if( src_pitch+32 > buffer_size ) |
| src = new uchar[src_pitch+32]; |
| |
| if( !color ) |
| if( m_bpp <= 8 ) |
| { |
| CvtPaletteToGray( m_palette, gray_palette, 1 << m_bpp ); |
| } |
| |
| if( setjmp( m_strm.JmpBuf()) == 0 ) |
| { |
| for( int s = 0; s < m_strips; s++ ) |
| { |
| int y_limit = m_rows_per_strip; |
| |
| y_limit += y; |
| if( y_limit > m_height ) y_limit = m_height; |
| |
| m_strm.SetPos( m_offsets[s] ); |
| |
| if( m_compression == TIFF_UNCOMP ) |
| { |
| for( ; y < y_limit; y++, data += step ) |
| { |
| m_strm.GetBytes( src, src_pitch ); |
| if( color ) |
| switch( m_bpp ) |
| { |
| case 1: |
| FillColorRow1( data, src, m_width, m_palette ); |
| break; |
| case 4: |
| FillColorRow4( data, src, m_width, m_palette ); |
| break; |
| case 8: |
| FillColorRow8( data, src, m_width, m_palette ); |
| break; |
| case 24: |
| icvCvt_RGB2BGR_8u_C3R( src, 0, data, 0, cvSize(m_width,1) ); |
| break; |
| case 32: |
| icvCvt_BGRA2BGR_8u_C4C3R( src, 0, data, 0, cvSize(m_width,1), 2 ); |
| break; |
| default: |
| assert(0); |
| goto bad_decoding_end; |
| } |
| else |
| switch( m_bpp ) |
| { |
| case 1: |
| FillGrayRow1( data, src, m_width, gray_palette ); |
| break; |
| case 4: |
| FillGrayRow4( data, src, m_width, gray_palette ); |
| break; |
| case 8: |
| FillGrayRow8( data, src, m_width, gray_palette ); |
| break; |
| case 24: |
| icvCvt_BGR2Gray_8u_C3C1R( src, 0, data, 0, cvSize(m_width,1), 2 ); |
| break; |
| case 32: |
| icvCvt_BGRA2Gray_8u_C4C1R( src, 0, data, 0, cvSize(m_width,1), 2 ); |
| break; |
| default: |
| assert(0); |
| goto bad_decoding_end; |
| } |
| } |
| } |
| else |
| { |
| } |
| |
| result = true; |
| |
| bad_decoding_end: |
| |
| ; |
| } |
| } |
| |
| if( src != buffer ) delete[] src; |
| return result; |
| } |
| |
| #endif |
| |
| ////////////////////////////////////////////////////////////////////////////////////////// |
| |
| GrFmtTiffWriter::GrFmtTiffWriter( const char* filename ) : GrFmtWriter( filename ) |
| { |
| } |
| |
| GrFmtTiffWriter::~GrFmtTiffWriter() |
| { |
| } |
| |
| void GrFmtTiffWriter::WriteTag( TiffTag tag, TiffFieldType fieldType, |
| int count, int value ) |
| { |
| m_strm.PutWord( tag ); |
| m_strm.PutWord( fieldType ); |
| m_strm.PutDWord( count ); |
| m_strm.PutDWord( value ); |
| } |
| |
| |
| bool GrFmtTiffWriter::WriteImage( const uchar* data, int step, |
| int width, int height, int /*depth*/, int channels ) |
| { |
| bool result = false; |
| int fileStep = width*channels; |
| |
| assert( data && width > 0 && height > 0 && step >= fileStep); |
| |
| if( m_strm.Open( m_filename ) ) |
| { |
| int rowsPerStrip = (1 << 13)/fileStep; |
| |
| if( rowsPerStrip < 1 ) |
| rowsPerStrip = 1; |
| |
| if( rowsPerStrip > height ) |
| rowsPerStrip = height; |
| |
| int i, stripCount = (height + rowsPerStrip - 1) / rowsPerStrip; |
| /*#if defined _DEBUG || !defined WIN32 |
| int uncompressedRowSize = rowsPerStrip * fileStep; |
| #endif*/ |
| int directoryOffset = 0; |
| |
| int* stripOffsets = new int[stripCount]; |
| short* stripCounts = new short[stripCount]; |
| uchar* buffer = new uchar[fileStep + 32]; |
| int stripOffsetsOffset = 0; |
| int stripCountsOffset = 0; |
| int bitsPerSample = 8; // TODO support 16 bit |
| int y = 0; |
| |
| m_strm.PutBytes( fmtSignTiffII, 4 ); |
| m_strm.PutDWord( directoryOffset ); |
| |
| // write an image data first (the most reasonable way |
| // for compressed images) |
| for( i = 0; i < stripCount; i++ ) |
| { |
| int limit = y + rowsPerStrip; |
| |
| if( limit > height ) |
| limit = height; |
| |
| stripOffsets[i] = m_strm.GetPos(); |
| |
| for( ; y < limit; y++, data += step ) |
| { |
| if( channels == 3 ) |
| icvCvt_BGR2RGB_8u_C3R( data, 0, buffer, 0, cvSize(width,1) ); |
| else if( channels == 4 ) |
| icvCvt_BGRA2RGBA_8u_C4R( data, 0, buffer, 0, cvSize(width,1) ); |
| |
| m_strm.PutBytes( channels > 1 ? buffer : data, fileStep ); |
| } |
| |
| stripCounts[i] = (short)(m_strm.GetPos() - stripOffsets[i]); |
| /*assert( stripCounts[i] == uncompressedRowSize || |
| stripCounts[i] < uncompressedRowSize && |
| i == stripCount - 1);*/ |
| } |
| |
| if( stripCount > 2 ) |
| { |
| stripOffsetsOffset = m_strm.GetPos(); |
| for( i = 0; i < stripCount; i++ ) |
| m_strm.PutDWord( stripOffsets[i] ); |
| |
| stripCountsOffset = m_strm.GetPos(); |
| for( i = 0; i < stripCount; i++ ) |
| m_strm.PutWord( stripCounts[i] ); |
| } |
| else if(stripCount == 2) |
| { |
| stripOffsetsOffset = m_strm.GetPos(); |
| for (i = 0; i < stripCount; i++) |
| { |
| m_strm.PutDWord (stripOffsets [i]); |
| } |
| stripCountsOffset = stripCounts [0] + (stripCounts [1] << 16); |
| } |
| else |
| { |
| stripOffsetsOffset = stripOffsets[0]; |
| stripCountsOffset = stripCounts[0]; |
| } |
| |
| if( channels > 1 ) |
| { |
| bitsPerSample = m_strm.GetPos(); |
| m_strm.PutWord(8); |
| m_strm.PutWord(8); |
| m_strm.PutWord(8); |
| if( channels == 4 ) |
| m_strm.PutWord(8); |
| } |
| |
| directoryOffset = m_strm.GetPos(); |
| |
| // write header |
| m_strm.PutWord( 9 ); |
| |
| /* warning: specification 5.0 of Tiff want to have tags in |
| ascending order. This is a non-fatal error, but this cause |
| warning with some tools. So, keep this in ascending order */ |
| |
| WriteTag( TIFF_TAG_WIDTH, TIFF_TYPE_LONG, 1, width ); |
| WriteTag( TIFF_TAG_HEIGHT, TIFF_TYPE_LONG, 1, height ); |
| WriteTag( TIFF_TAG_BITS_PER_SAMPLE, |
| TIFF_TYPE_SHORT, channels, bitsPerSample ); |
| WriteTag( TIFF_TAG_COMPRESSION, TIFF_TYPE_LONG, 1, TIFF_UNCOMP ); |
| WriteTag( TIFF_TAG_PHOTOMETRIC, TIFF_TYPE_SHORT, 1, channels > 1 ? 2 : 1 ); |
| |
| WriteTag( TIFF_TAG_STRIP_OFFSETS, TIFF_TYPE_LONG, |
| stripCount, stripOffsetsOffset ); |
| |
| WriteTag( TIFF_TAG_SAMPLES_PER_PIXEL, TIFF_TYPE_SHORT, 1, channels ); |
| WriteTag( TIFF_TAG_ROWS_PER_STRIP, TIFF_TYPE_LONG, 1, rowsPerStrip ); |
| |
| WriteTag( TIFF_TAG_STRIP_COUNTS, |
| stripCount > 1 ? TIFF_TYPE_SHORT : TIFF_TYPE_LONG, |
| stripCount, stripCountsOffset ); |
| |
| m_strm.PutDWord(0); |
| m_strm.Close(); |
| |
| // write directory offset |
| FILE* f = fopen( m_filename, "r+b" ); |
| buffer[0] = (uchar)directoryOffset; |
| buffer[1] = (uchar)(directoryOffset >> 8); |
| buffer[2] = (uchar)(directoryOffset >> 16); |
| buffer[3] = (uchar)(directoryOffset >> 24); |
| |
| fseek( f, 4, SEEK_SET ); |
| fwrite( buffer, 1, 4, f ); |
| fclose(f); |
| |
| delete[] stripOffsets; |
| delete[] stripCounts; |
| delete[] buffer; |
| |
| result = true; |
| } |
| return result; |
| } |
| |