Example #1
0
        /// <summary>
        /// Flush the TIFF file header into the stream.
        /// </summary>
        /// <param name="cancellationToken">The <see cref="CancellationToken"/> that fires if the user has requested to abort this operation.</param>
        /// <returns></returns>
        public async Task FlushAsync(CancellationToken cancellationToken = default)
        {
            EnsureNotDisposed();
            cancellationToken.ThrowIfCancellationRequested();

            Debug.Assert(_writer != null);
            if (_requireBigTiff && !_useBigTiff)
            {
                throw new InvalidOperationException("Must use BigTIFF format. But it is disabled.");
            }

            byte[] buffer = ArrayPool <byte> .Shared.Rent(SmallBufferSize);

            try
            {
                Array.Clear(buffer, 0, 16);
                TiffFileHeader.Write(buffer, _imageFileDirectoryOffset, BitConverter.IsLittleEndian, _useBigTiff);
                await _writer !.WriteAsync(0, new ArraySegment <byte>(buffer, 0, _useBigTiff ? 16 : 8), cancellationToken).ConfigureAwait(false);
                await _writer.FlushAsync(cancellationToken).ConfigureAwait(false);
            }
            finally
            {
                ArrayPool <byte> .Shared.Return(buffer);
            }
        }
Example #2
0
        /// <summary>
        /// Try to parse TIFF file header from the specified buffer.
        /// </summary>
        /// <param name="data">The buffer to use.</param>
        /// <param name="header">The parsed TIFF file header.</param>
        /// <returns>True if the TIFF file header is successfully parsed. Otherwise, false.</returns>
        public static bool TryParse(ReadOnlySpan <byte> data, out TiffFileHeader header)
        {
            if (data.Length < 8)
            {
                header = default;
                return(false);
            }

            // Read byte order
            short byteOrderFlag = MemoryMarshal.Read <short>(data);
            bool  reverseEndianRequired;

            if (byteOrderFlag == LittleEndianByteOrderFlag)
            {
                reverseEndianRequired = !BitConverter.IsLittleEndian;
            }
            else if (byteOrderFlag == BigEndianByteOrderFlag)
            {
                reverseEndianRequired = BitConverter.IsLittleEndian;
            }
            else
            {
                header = default;
                return(false);
            }

            // Read TIFF version
            short version = MemoryMarshal.Read <short>(data.Slice(2));

            if (reverseEndianRequired)
            {
                version = BinaryPrimitives.ReverseEndianness(version);
            }

            if (version == StandardTiffVersion)
            {
                // Standard TIFF
                int imageFileDirectoryOffset32 = MemoryMarshal.Read <int>(data.Slice(4));
                if (reverseEndianRequired)
                {
                    imageFileDirectoryOffset32 = BinaryPrimitives.ReverseEndianness(imageFileDirectoryOffset32);
                }

                // An IFD can be at any location in the file after the header but must begin on a word boundary.
                if (imageFileDirectoryOffset32 < 8 || (imageFileDirectoryOffset32 & 0b1) == 1)
                {
                    header = default;
                    return(false);
                }

                header = new TiffFileHeader(byteOrderFlag, imageFileDirectoryOffset32);
                return(true);
            }
            else if (version == BigTiffVersion)
            {
                // BigTIFF
                data = data.Slice(4);
                if (data.Length < 12)
                {
                    header = default;
                    return(false);
                }

                short byteSizeOfOffsets          = MemoryMarshal.Read <short>(data);
                short bigTiffConstant            = MemoryMarshal.Read <short>(data.Slice(2));
                long  imageFileDirectoryOffset64 = MemoryMarshal.Read <long>(data.Slice(4));
                if (reverseEndianRequired)
                {
                    byteSizeOfOffsets = BinaryPrimitives.ReverseEndianness(byteSizeOfOffsets);
                    // Uncomment this when we support BigTIFF constant other than zero.
                    // bigTiffConstant = BinaryPrimitives.ReverseEndianness(bigTiffConstant);
                    imageFileDirectoryOffset64 = BinaryPrimitives.ReverseEndianness(imageFileDirectoryOffset64);
                }

                if (byteSizeOfOffsets != 8)
                {
                    // Unsupported byte size of offsets
                    header = default;
                    return(false);
                }

                if (bigTiffConstant != 0)
                {
                    header = default;
                    return(false);
                }

                // An IFD can be at any location in the file after the header but must begin on a word boundary.
                if (imageFileDirectoryOffset64 < 16 || (imageFileDirectoryOffset64 & 0b1) == 1)
                {
                    header = default;
                    return(false);
                }

                header = new TiffFileHeader(byteOrderFlag, BigTiffVersion, byteSizeOfOffsets, imageFileDirectoryOffset64);
                return(true);
            }
            else
            {
                header = default;
                return(false);
            }
        }