Skip to content

Commit

Permalink
Merge pull request #1400 from IldarKhayrutdinov/tiff-format
Browse files Browse the repository at this point in the history
#12 Small improves
  • Loading branch information
JimBobSquarePants committed Oct 22, 2020
2 parents 8ccad40 + b3a3049 commit 6bc2941
Show file tree
Hide file tree
Showing 12 changed files with 133 additions and 126 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public override void Decompress(Stream stream, int byteCount, Span<byte> buffer)

if ((cmf & 0x0f) != 8)
{
throw new Exception($"Bad compression method for ZLIB header: cmf={cmf}");
TiffThrowHelper.ThrowBadZlibHeader(cmf);
}

// If the 'fdict' flag is set then we should skip the next four bytes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public static TiffBaseCompression Create(TiffCompressionType compressionType, Me
case TiffCompressionType.Lzw:
return new LzwTiffCompression(allocator);
default:
throw new InvalidOperationException();
throw TiffThrowHelper.NotSupportedCompression(nameof(compressionType));
}
}
}
Expand Down
8 changes: 3 additions & 5 deletions src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.

using System;
using System.Collections.Generic;
using System.IO;
using SixLabors.ImageSharp.Metadata.Profiles.Exif;

namespace SixLabors.ImageSharp.Formats.Tiff
Expand Down Expand Up @@ -40,13 +38,13 @@ private bool ReadHeader()
ushort magic = this.stream.ReadUInt16();
if (magic != TiffConstants.HeaderMagicNumber)
{
throw new ImageFormatException("Invalid TIFF header magic number: " + magic);
TiffThrowHelper.ThrowInvalidHeader();
}

uint firstIfdOffset = this.stream.ReadUInt32();
if (firstIfdOffset == 0)
{
throw new ImageFormatException("Invalid TIFF file header.");
TiffThrowHelper.ThrowInvalidHeader();
}

this.nextIfdOffset = firstIfdOffset;
Expand Down Expand Up @@ -95,7 +93,7 @@ private IExifValue[] ReadIfd()
}
else if (leftBytes < 0)
{
throw new InvalidDataException("Out of range of IFD structure.");
TiffThrowHelper.ThrowOutOfRange("IFD");
}

return entries.ToArray();
Expand Down
4 changes: 2 additions & 2 deletions src/ImageSharp/Formats/Tiff/Ifd/EntryReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ private bool ReadValueOrOffset(ExifValue entry, ExifDataType rawDataType, uint c
}
else if (leftBytes < 0)
{
throw new InvalidDataException("Out of range of IFD entry structure.");
TiffThrowHelper.ThrowOutOfRange("IFD entry");
}
}

Expand Down Expand Up @@ -244,7 +244,7 @@ private object ReadData(ExifDataType entryDataType, ExifDataType rawDataType, ui

if (buf[buf.Length - 1] != 0)
{
throw new ImageFormatException("The retrieved string is not null terminated.");
TiffThrowHelper.ThrowBadStringEntry();
}

return Encoding.UTF8.GetString(buf, 0, buf.Length - 1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ public static TiffBaseColorDecoder<TPixel> Create(TiffColorType colorType, ushor
return new PaletteTiffColor<TPixel>(bitsPerSample, colorMap);

default:
throw new InvalidOperationException();
throw TiffThrowHelper.InvalidColorType(colorType.ToString());
}
}

Expand All @@ -88,7 +88,7 @@ public static RgbPlanarTiffColor<TPixel> CreatePlanar(TiffColorType colorType, u
return new RgbPlanarTiffColor<TPixel>(bitsPerSample);

default:
throw new InvalidOperationException();
throw TiffThrowHelper.InvalidColorType(colorType.ToString());
}
}
}
Expand Down
53 changes: 0 additions & 53 deletions src/ImageSharp/Formats/Tiff/Streams/TiffStreamFactory.cs

This file was deleted.

8 changes: 4 additions & 4 deletions src/ImageSharp/Formats/Tiff/TiffDecoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public Image<TPixel> Decode<TPixel>(Configuration configuration, Stream stream)
{
Guard.NotNull(stream, "stream");

using var decoder = new TiffDecoderCore(stream, configuration, this);
var decoder = new TiffDecoderCore(configuration, this);
return decoder.Decode<TPixel>(configuration, stream);
}

Expand All @@ -38,7 +38,7 @@ public Task<Image<TPixel>> DecodeAsync<TPixel>(Configuration configuration, Stre
{
Guard.NotNull(stream, nameof(stream));

var decoder = new TiffDecoderCore(stream, configuration, this);
var decoder = new TiffDecoderCore(configuration, this);
return decoder.DecodeAsync<TPixel>(configuration, stream, cancellationToken);
}

Expand All @@ -52,7 +52,7 @@ public IImageInfo Identify(Configuration configuration, Stream stream)
{
Guard.NotNull(stream, nameof(stream));

var decoder = new TiffDecoderCore(stream, configuration, this);
var decoder = new TiffDecoderCore(configuration, this);
return decoder.Identify(configuration, stream);
}

Expand All @@ -61,7 +61,7 @@ public Task<IImageInfo> IdentifyAsync(Configuration configuration, Stream stream
{
Guard.NotNull(stream, nameof(stream));

var decoder = new TiffDecoderCore(stream, configuration, this);
var decoder = new TiffDecoderCore(configuration, this);
return decoder.IdentifyAsync(configuration, stream, cancellationToken);
}
}
Expand Down
85 changes: 46 additions & 39 deletions src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff
/// <summary>
/// Performs the tiff decoding operation.
/// </summary>
internal class TiffDecoderCore : IImageDecoderInternals, IDisposable
internal class TiffDecoderCore : IImageDecoderInternals
{
/// <summary>
/// The global configuration
Expand All @@ -35,42 +35,22 @@ internal class TiffDecoderCore : IImageDecoderInternals, IDisposable
/// </summary>
private readonly bool ignoreMetadata;

private BufferedReadStream inputStream;

/// <summary>
/// Initializes a new instance of the <see cref="TiffDecoderCore" /> class.
/// </summary>
/// <param name="configuration">The configuration.</param>
/// <param name="options">The decoder options.</param>
private TiffDecoderCore(Configuration configuration, ITiffDecoderOptions options)
public TiffDecoderCore(Configuration configuration, ITiffDecoderOptions options)
{
options = options ?? new TiffDecoder();
options ??= new TiffDecoder();

this.configuration = configuration ?? Configuration.Default;
this.ignoreMetadata = options.IgnoreMetadata;
this.memoryAllocator = this.configuration.MemoryAllocator;
}

/// <summary>
/// Initializes a new instance of the <see cref="TiffDecoderCore" /> class.
/// </summary>
/// <param name="stream">The stream.</param>
/// <param name="configuration">The configuration.</param>
/// <param name="options">The decoder options.</param>
public TiffDecoderCore(Stream stream, Configuration configuration, ITiffDecoderOptions options)
: this(configuration, options)
{
this.ByteOrder = TiffStreamFactory.ReadByteOrder(stream);
}

/// <summary>
/// Gets the byte order.
/// </summary>
public TiffByteOrder ByteOrder { get; }

/// <summary>
/// Gets the input stream.
/// </summary>
public TiffStream Stream { get; private set; }

/// <summary>
/// Gets or sets the number of bits for each sample of the pixel format used to encode the image.
/// </summary>
Expand Down Expand Up @@ -111,8 +91,9 @@ public TiffDecoderCore(Stream stream, Configuration configuration, ITiffDecoderO
public Image<TPixel> Decode<TPixel>(BufferedReadStream stream, CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel<TPixel>
{
this.Stream = TiffStreamFactory.Create(this.ByteOrder, stream);
var reader = new DirectoryReader(this.Stream);
this.inputStream = stream;
TiffStream tiffStream = CreateStream(stream);
var reader = new DirectoryReader(tiffStream);

IEnumerable<IExifValue[]> directories = reader.Read();

Expand All @@ -125,7 +106,7 @@ public Image<TPixel> Decode<TPixel>(BufferedReadStream stream, CancellationToken
framesMetadata.Add(frameMetadata);
}

ImageMetadata metadata = framesMetadata.CreateMetadata(this.ignoreMetadata, this.Stream.ByteOrder);
ImageMetadata metadata = framesMetadata.CreateMetadata(this.ignoreMetadata, tiffStream.ByteOrder);

// todo: tiff frames can have different sizes
{
Expand All @@ -135,7 +116,7 @@ public Image<TPixel> Decode<TPixel>(BufferedReadStream stream, CancellationToken
{
if (frame.Size() != root.Size())
{
throw new NotSupportedException("Images with different sizes are not supported");
TiffThrowHelper.ThrowNotSupported("Images with different sizes are not supported");
}
}
}
Expand All @@ -148,8 +129,9 @@ public Image<TPixel> Decode<TPixel>(BufferedReadStream stream, CancellationToken
/// <inheritdoc/>
public IImageInfo Identify(BufferedReadStream stream, CancellationToken cancellationToken)
{
this.Stream = TiffStreamFactory.Create(this.ByteOrder, stream);
var reader = new DirectoryReader(this.Stream);
this.inputStream = stream;
TiffStream tiffStream = CreateStream(stream);
var reader = new DirectoryReader(tiffStream);

IEnumerable<IExifValue[]> directories = reader.Read();

Expand All @@ -159,7 +141,7 @@ public IImageInfo Identify(BufferedReadStream stream, CancellationToken cancella
framesMetadata.Add(new TiffFrameMetadata() { Tags = ifd });
}

ImageMetadata metadata = framesMetadata.CreateMetadata(this.ignoreMetadata, this.Stream.ByteOrder);
ImageMetadata metadata = framesMetadata.CreateMetadata(this.ignoreMetadata, tiffStream.ByteOrder);

TiffFrameMetadata root = framesMetadata.First();
int bitsPerPixel = 0;
Expand All @@ -171,10 +153,35 @@ public IImageInfo Identify(BufferedReadStream stream, CancellationToken cancella
return new ImageInfo(new PixelTypeInfo(bitsPerPixel), (int)root.Width, (int)root.Height, metadata);
}

/// <inheritdoc/>
public void Dispose()
private static TiffStream CreateStream(Stream stream)
{
TiffByteOrder byteOrder = ReadByteOrder(stream);
if (byteOrder == TiffByteOrder.BigEndian)
{
return new TiffBigEndianStream(stream);
}
else if (byteOrder == TiffByteOrder.LittleEndian)
{
return new TiffLittleEndianStream(stream);
}

throw TiffThrowHelper.InvalidHeader();
}

private static TiffByteOrder ReadByteOrder(Stream stream)
{
// nothing
byte[] headerBytes = new byte[2];
stream.Read(headerBytes, 0, 2);
if (headerBytes[0] == TiffConstants.ByteOrderLittleEndian && headerBytes[1] == TiffConstants.ByteOrderLittleEndian)
{
return TiffByteOrder.LittleEndian;
}
else if (headerBytes[0] == TiffConstants.ByteOrderBigEndian && headerBytes[1] == TiffConstants.ByteOrderBigEndian)
{
return TiffByteOrder.BigEndian;
}

throw TiffThrowHelper.InvalidHeader();
}

/// <summary>
Expand Down Expand Up @@ -283,8 +290,8 @@ private void DecodeStripsPlanar<TPixel>(ImageFrame<TPixel> frame, int rowsPerStr
{
int stripIndex = (i * stripsPerPixel) + planeIndex;

this.Stream.Seek(stripOffsets[stripIndex]);
decompressor.Decompress(this.Stream.InputStream, (int)stripByteCounts[stripIndex], stripBuffers[planeIndex].GetSpan());
this.inputStream.Seek(stripOffsets[stripIndex], SeekOrigin.Begin);
decompressor.Decompress(this.inputStream, (int)stripByteCounts[stripIndex], stripBuffers[planeIndex].GetSpan());
}

colorDecoder.Decode(stripBuffers, pixels, 0, rowsPerStrip * i, frame.Width, stripHeight);
Expand Down Expand Up @@ -316,8 +323,8 @@ private void DecodeStripsChunky<TPixel>(ImageFrame<TPixel> frame, int rowsPerStr
{
int stripHeight = stripIndex < stripOffsets.Length - 1 || frame.Height % rowsPerStrip == 0 ? rowsPerStrip : frame.Height % rowsPerStrip;

this.Stream.Seek(stripOffsets[stripIndex]);
decompressor.Decompress(this.Stream.InputStream, (int)stripByteCounts[stripIndex], stripBuffer.GetSpan());
this.inputStream.Seek(stripOffsets[stripIndex], SeekOrigin.Begin);
decompressor.Decompress(this.inputStream, (int)stripByteCounts[stripIndex], stripBuffer.GetSpan());

colorDecoder.Decode(stripBuffer.GetSpan(), pixels, 0, rowsPerStrip * stripIndex, frame.Width, stripHeight);
}
Expand Down
Loading

0 comments on commit 6bc2941

Please sign in to comment.