// // Copyright (c) James Jackson-South and contributors. // Licensed under the Apache License, Version 2.0. // namespace ImageSharp.Formats { using System; using System.IO; using System.Runtime.CompilerServices; using System.Threading.Tasks; /// /// Performs the tiff decoding operation. /// internal class TiffDecoderCore : IDisposable { /// /// The decoder options. /// private readonly IDecoderOptions options; /// /// A flag indicating if the file is encoded in little-endian or big-endian format. /// private bool isLittleEndian; /// /// Initializes a new instance of the class. /// /// The decoder options. public TiffDecoderCore(IDecoderOptions options) { this.options = options ?? new DecoderOptions(); } /// /// Gets the input stream. /// public Stream InputStream { get; private set; } /// /// Decodes the image from the specified and sets /// the data to image. /// /// The pixel format. /// The image, where the data should be set to. /// The stream, where the image should be. /// Whether to decode metadata only. public void Decode(Image image, Stream stream, bool metadataOnly) where TColor : struct, IPixel { this.InputStream = stream; uint firstIfdOffset = ReadHeader(); } /// /// Dispose /// public void Dispose() { } private uint ReadHeader() { byte[] headerBytes = new byte[8]; ReadBytes(headerBytes, 8); if (headerBytes[0] == TiffConstants.ByteOrderLittleEndian && headerBytes[1] == TiffConstants.ByteOrderLittleEndian) isLittleEndian = true; else if (headerBytes[0] != TiffConstants.ByteOrderBigEndian && headerBytes[1] != TiffConstants.ByteOrderBigEndian) throw new ImageFormatException("Invalid TIFF file header."); if (ToUInt16(headerBytes, 2) != TiffConstants.HeaderMagicNumber) throw new ImageFormatException("Invalid TIFF file header."); uint firstIfdOffset = ToUInt32(headerBytes, 4); if (firstIfdOffset == 0) throw new ImageFormatException("Invalid TIFF file header."); return firstIfdOffset; } private byte[] ReadBytes(byte[] buffer, int count) { int offset = 0; while (count > 0) { int bytesRead = InputStream.Read(buffer, offset, count); if (bytesRead == 0) break; offset += bytesRead; count -= bytesRead; } return buffer; } private Int16 ToInt16(byte[] bytes, int offset) { if (isLittleEndian) return (short)(bytes[offset + 0] | (bytes[offset + 1] << 8)); else return (short)((bytes[offset + 0] << 8) | bytes[offset + 1]); } private Int32 ToInt32(byte[] bytes, int offset) { if (isLittleEndian) return bytes[offset + 0] | (bytes[offset + 1] << 8) | (bytes[offset + 2] << 16) | (bytes[offset + 3] << 24); else return (bytes[offset + 0] << 24) | (bytes[offset + 1] << 16) | (bytes[offset + 2] << 8) | bytes[offset + 3]; } private UInt32 ToUInt32(byte[] bytes, int offset) { return (uint)ToInt32(bytes, offset); } private UInt16 ToUInt16(byte[] bytes, int offset) { return (ushort)ToInt16(bytes, offset); } } }