/// <summary> /// Computes the size of the image file directory. /// </summary> /// <param name="imageFileDirectory">The image file directory.</param> /// <returns>The size of the image file directory (in bytes).</returns> private Int64 ComputeImageFileDirectorySize(TiffImageFileDirectory imageFileDirectory) { Int64 size = (_structure == TiffStructure.BigTiff ? 8 : 2) // number of entries + _imageFileDirectoryEntrySize * imageFileDirectory.Count // entries + _imageFileDirectoryFieldSize; // position of next directory TiffTagType entryType; UInt16 dataSize; Int32 dataCount; foreach (UInt16 entryTag in imageFileDirectory.Keys) { entryType = TiffTag.GetType(imageFileDirectory[entryTag][0]); dataSize = TiffTag.GetSize(entryType); if (entryType == TiffTagType.ASCII) { dataCount = 0; for (Int32 i = 0; i < imageFileDirectory[entryTag].Length; i++) { dataCount += (imageFileDirectory[entryTag][i] as String).Length; } } else { dataCount = imageFileDirectory[entryTag].Length; } if (dataCount * dataSize > _imageFileDirectoryFieldSize) { size += dataCount * dataSize + (dataCount * dataSize) % 2; } } return(size); }
/// <summary> /// Writes an image file directory to the stream. /// </summary> /// <param name="imageFileDirectory">The image file directory.</param> private void WriteImageFileDirectory(TiffImageFileDirectory imageFileDirectory) { _currentImageFileDirectoryStartPosition = _baseStream.Position; // write starting position _baseStream.Seek(_currentImageFileDirectoryEndPosition, SeekOrigin.Begin); _baseStream.Write(EndianBitConverter.GetBytes((UInt32)_currentImageFileDirectoryStartPosition), 0, _imageFileDirectoryFieldSize); // compute size of directory (without additional fields) Int64 imageFileDirectorySize = 2 + _imageFileDirectoryEntrySize * imageFileDirectory.Count; _currentImageFileDirectoryEndPosition = _currentImageFileDirectoryStartPosition + imageFileDirectorySize; // position after the IFD to write exceeding values _baseStream.Seek(_currentImageFileDirectoryEndPosition + _imageFileDirectoryFieldSize, SeekOrigin.Begin); // the IFD should be written in one operation Byte[] bytes; if (_imageCount == _maxImageCount - 1) { bytes = new Byte[imageFileDirectorySize + _imageFileDirectoryFieldSize]; } else { bytes = new Byte[imageFileDirectorySize]; } EndianBitConverter.CopyBytes((UInt16)imageFileDirectory.Count, bytes, 0); // number of entries Int32 byteIndex = 2; TiffTagType entryType; UInt16 dataSize; Int64 dataCount; foreach (UInt16 entryTag in imageFileDirectory.Keys) { entryType = TiffTag.GetType(imageFileDirectory[entryTag][0]); dataSize = TiffTag.GetSize(entryType); if (entryType == TiffTagType.ASCII) { dataCount = 0; for (Int32 i = 0; i < imageFileDirectory[entryTag].Length; i++) { dataCount += (imageFileDirectory[entryTag][i] as String).Length; } } else { dataCount = imageFileDirectory[entryTag].Length; } EndianBitConverter.CopyBytes(entryTag, bytes, byteIndex); EndianBitConverter.CopyBytes((UInt16)entryType, bytes, byteIndex + 2); EndianBitConverter.CopyBytes((UInt32)dataCount, bytes, byteIndex + 4); // values exceeding he field size (4) must be written to another position Byte[] dataBytes; Int32 dataStartIndex; if (dataCount * dataSize <= 4) { dataBytes = bytes; dataStartIndex = byteIndex + 8; } else { dataBytes = new Byte[dataCount * dataSize + (dataCount * dataSize) % 2]; dataStartIndex = 0; } for (Int32 valueIndex = 0; valueIndex < imageFileDirectory[entryTag].Length; valueIndex++) { dataStartIndex = TiffTag.SetValue(entryType, imageFileDirectory[entryTag][valueIndex], dataBytes, dataStartIndex); } if (dataCount * dataSize > 4) { Int64 valuePosition = _baseStream.Position; _baseStream.Write(dataBytes, 0, dataBytes.Length); EndianBitConverter.CopyBytes((UInt32)valuePosition, bytes, byteIndex + 8); } byteIndex += _imageFileDirectoryEntrySize; } _currentImageStartPosition = _baseStream.Position; // write the IFD _baseStream.Seek(_currentImageFileDirectoryStartPosition, SeekOrigin.Begin); _baseStream.Write(bytes, 0, bytes.Length); }