Browse Source

Review changes

pull/1553/head
Brian Popow 5 years ago
parent
commit
5fcb5fcf0f
  1. 2
      src/ImageSharp/Formats/Tiff/Compression/Compressors/DeflateCompressor.cs
  2. 2
      src/ImageSharp/Formats/Tiff/Compression/Compressors/LzwCompressor.cs
  3. 2
      src/ImageSharp/Formats/Tiff/Compression/Compressors/NoCompressor.cs
  4. 2
      src/ImageSharp/Formats/Tiff/Compression/Compressors/PackBitsCompressor.cs
  5. 4
      src/ImageSharp/Formats/Tiff/Compression/Compressors/PackBitsWriter.cs
  6. 8
      src/ImageSharp/Formats/Tiff/Compression/Compressors/T4BitCompressor.cs
  7. 4
      src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs
  8. 5
      src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs
  9. 12
      src/ImageSharp/Formats/Tiff/Constants/TiffNewSubfileType.cs
  10. 2
      src/ImageSharp/Formats/Tiff/Constants/TiffPredictor.cs
  11. 4
      src/ImageSharp/Formats/Tiff/ITiffDecoderOptions.cs
  12. 5
      src/ImageSharp/Formats/Tiff/ITiffEncoderOptions.cs
  13. 6
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero1TiffColor.cs
  14. 6
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero4TiffColor.cs
  15. 6
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero8TiffColor.cs
  16. 2
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZeroTiffColor.cs
  17. 2
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/PaletteTiffColor.cs
  18. 6
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb888TiffColor.cs
  19. 2
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbPlanarTiffColor.cs
  20. 2
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbTiffColor.cs
  21. 16
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffBaseColorDecoder.cs
  22. 2
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory.cs
  23. 2
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorType.cs
  24. 6
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero1TiffColor.cs
  25. 6
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero4TiffColor.cs
  26. 6
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero8TiffColor.cs
  27. 2
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZeroTiffColor.cs
  28. 5
      src/ImageSharp/Formats/Tiff/README.md
  29. 1
      src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs
  30. 1
      src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs
  31. 3
      src/ImageSharp/Formats/Tiff/TiffEncoder.cs
  32. 68
      src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs
  33. 6
      src/ImageSharp/Formats/Tiff/Writers/TiffBaseColorWriter.cs
  34. 2
      src/ImageSharp/Formats/Tiff/Writers/TiffStreamWriter.cs
  35. 36
      src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs
  36. 2
      tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/BlackIsZeroTiffColorTests.cs
  37. 21
      tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/PaletteTiffColorTests.cs
  38. 2
      tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/RgbPlanarTiffColorTests.cs
  39. 2
      tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/RgbTiffColorTests.cs
  40. 2
      tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/WhiteIsZeroTiffColorTests.cs
  41. 38
      tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs
  42. 1
      tests/ImageSharp.Tests/ImageSharp.Tests.csproj

2
src/ImageSharp/Formats/Tiff/Compression/Compressors/DeflateCompressor.cs

@ -9,7 +9,7 @@ using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Compressors
{
internal class DeflateCompressor : TiffBaseCompressor
internal sealed class DeflateCompressor : TiffBaseCompressor
{
private readonly DeflateCompressionLevel compressionLevel;

2
src/ImageSharp/Formats/Tiff/Compression/Compressors/LzwCompressor.cs

@ -8,7 +8,7 @@ using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Compressors
{
internal class LzwCompressor : TiffBaseCompressor
internal sealed class LzwCompressor : TiffBaseCompressor
{
private TiffLzwEncoder lzwEncoder;

2
src/ImageSharp/Formats/Tiff/Compression/Compressors/NoCompressor.cs

@ -8,7 +8,7 @@ using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Compressors
{
internal class NoCompressor : TiffBaseCompressor
internal sealed class NoCompressor : TiffBaseCompressor
{
public NoCompressor(Stream output, MemoryAllocator memoryAllocator, int width, int bitsPerPixel)
: base(output, memoryAllocator, width, bitsPerPixel)

2
src/ImageSharp/Formats/Tiff/Compression/Compressors/PackBitsCompressor.cs

@ -8,7 +8,7 @@ using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Compressors
{
internal class PackBitsCompressor : TiffBaseCompressor
internal sealed class PackBitsCompressor : TiffBaseCompressor
{
private IManagedByteBuffer pixelData;

4
src/ImageSharp/Formats/Tiff/Compression/Compressors/PackBitsWriter.cs

@ -19,7 +19,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Compressors
while (posInRowSpan < rowSpan.Length)
{
var useReplicateRun = IsReplicateRun(rowSpan, posInRowSpan);
bool useReplicateRun = IsReplicateRun(rowSpan, posInRowSpan);
if (useReplicateRun)
{
if (literalRunLength > 0)
@ -29,7 +29,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Compressors
}
// Write a run with the same bytes.
var runLength = FindRunLength(rowSpan, posInRowSpan, maxRunLength);
int runLength = FindRunLength(rowSpan, posInRowSpan, maxRunLength);
WriteRun(rowSpan, posInRowSpan, runLength, compressedRowSpan, bytesWritten);
bytesWritten += 2;

8
src/ImageSharp/Formats/Tiff/Compression/Compressors/T4BitCompressor.cs

@ -13,13 +13,13 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Compressors
/// <summary>
/// Bitwriter for writing compressed CCITT T4 1D data.
/// </summary>
internal class T4BitCompressor : TiffBaseCompressor
internal sealed class T4BitCompressor : TiffBaseCompressor
{
private const uint WhiteZeroRunTermCode = 0x35;
private const uint BlackZeroRunTermCode = 0x37;
private static readonly List<uint> MakeupRunLength = new List<uint>()
private static readonly uint[] MakeupRunLength =
{
64, 128, 192, 256, 320, 384, 448, 512, 576, 640, 704, 768, 832, 896, 960, 1024, 1088, 1152, 1216, 1280, 1344, 1408, 1472, 1536, 1600, 1664, 1728, 1792, 1856, 1920, 1984, 2048, 2112, 2176, 2240, 2304, 2368, 2432, 2496, 2560
};
@ -368,7 +368,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Compressors
private uint GetBestFittingMakeupRunLength(uint runLength)
{
for (int i = 0; i < MakeupRunLength.Count - 1; i++)
for (int i = 0; i < MakeupRunLength.Length - 1; i++)
{
if (MakeupRunLength[i] <= runLength && MakeupRunLength[i + 1] > runLength)
{
@ -376,7 +376,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Compressors
}
}
return MakeupRunLength[MakeupRunLength.Count - 1];
return MakeupRunLength[MakeupRunLength.Length - 1];
}
private uint GetTermCode(uint runLength, out uint codeLength, bool isWhiteRun)

4
src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs

@ -95,7 +95,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression
private static void Undo8Bit(Span<byte> pixelBytes, int width)
{
var rowBytesCount = width;
int rowBytesCount = width;
int height = pixelBytes.Length / rowBytesCount;
for (int y = 0; y < height; y++)
{
@ -112,7 +112,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression
private static void Undo24Bit(Span<byte> pixelBytes, int width)
{
var rowBytesCount = width * 3;
int rowBytesCount = width * 3;
int height = pixelBytes.Length / rowBytesCount;
for (int y = 0; y < height; y++)
{

5
src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs

@ -75,6 +75,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Constants
/// </summary>
public const int SizeOfDouble = 8;
/// <summary>
/// The default strip size is 8k.
/// </summary>
public const int DefaultStripSize = 8 * 1024;
/// <summary>
/// The bits per sample for 1 bit bicolor images.
/// </summary>

12
src/ImageSharp/Formats/Tiff/Constants/TiffNewSubfileType.cs

@ -14,31 +14,31 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Constants
/// <summary>
/// A full-resolution image.
/// </summary>
FullImage = 0x0000,
FullImage = 0,
/// <summary>
/// Reduced-resolution version of another image in this TIFF file.
/// </summary>
Preview = 0x0001,
Preview = 1,
/// <summary>
/// A single page of a multi-page image.
/// </summary>
SinglePage = 0x0002,
SinglePage = 2,
/// <summary>
/// A transparency mask for another image in this TIFF file.
/// </summary>
TransparencyMask = 0x0004,
TransparencyMask = 4,
/// <summary>
/// Alternative reduced-resolution version of another image in this TIFF file (see DNG specification).
/// </summary>
AlternativePreview = 0x10000,
AlternativePreview = 65536,
/// <summary>
/// Mixed raster content (see RFC2301).
/// </summary>
MixedRasterContent = 0x0008
MixedRasterContent = 8
}
}

2
src/ImageSharp/Formats/Tiff/Constants/TiffPredictor.cs

@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Constants
public enum TiffPredictor : ushort
{
/// <summary>
/// No prediction scheme used before coding
/// No prediction.
/// </summary>
None = 1,

4
src/ImageSharp/Formats/Tiff/ITiffDecoderOptions.cs

@ -1,4 +1,4 @@
// Copyright (c) Six Labors.
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.Formats.Tiff
@ -6,7 +6,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff
/// <summary>
/// Encapsulates the options for the <see cref="TiffDecoder"/>.
/// </summary>
public interface ITiffDecoderOptions
internal interface ITiffDecoderOptions
{
/// <summary>
/// Gets a value indicating whether the metadata should be ignored when the image is being decoded.

5
src/ImageSharp/Formats/Tiff/ITiffEncoderOptions.cs

@ -43,10 +43,5 @@ namespace SixLabors.ImageSharp.Formats.Tiff
/// Gets the quantizer for creating a color palette image.
/// </summary>
IQuantizer Quantizer { get; }
/// <summary>
/// Gets the maximum size of strip (bytes).
/// </summary>
int MaxStripBytes { get; }
}
}

6
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero1TiffColor.cs

@ -6,7 +6,7 @@ using System;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Formats.Tiff
namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
{
/// <summary>
/// Implements the 'BlackIsZero' photometric interpretation (optimized for bilevel images).
@ -15,10 +15,6 @@ namespace SixLabors.ImageSharp.Formats.Tiff
internal class BlackIsZero1TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
public BlackIsZero1TiffColor()
{
}
/// <inheritdoc/>
public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
{

6
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero4TiffColor.cs

@ -6,7 +6,7 @@ using System;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Formats.Tiff
namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
{
/// <summary>
/// Implements the 'BlackIsZero' photometric interpretation (optimized for 4-bit grayscale images).
@ -14,10 +14,6 @@ namespace SixLabors.ImageSharp.Formats.Tiff
internal class BlackIsZero4TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
public BlackIsZero4TiffColor()
{
}
/// <inheritdoc/>
public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
{

6
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero8TiffColor.cs

@ -6,7 +6,7 @@ using System;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Formats.Tiff
namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
{
/// <summary>
/// Implements the 'BlackIsZero' photometric interpretation (optimized for 8-bit grayscale images).
@ -14,10 +14,6 @@ namespace SixLabors.ImageSharp.Formats.Tiff
internal class BlackIsZero8TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
public BlackIsZero8TiffColor()
{
}
/// <inheritdoc/>
public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
{

2
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZeroTiffColor.cs

@ -7,7 +7,7 @@ using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Formats.Tiff
namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
{
/// <summary>
/// Implements the 'BlackIsZero' photometric interpretation (for all bit depths).

2
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/PaletteTiffColor.cs

@ -7,7 +7,7 @@ using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Formats.Tiff
namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
{
/// <summary>
/// Implements the 'PaletteTiffColor' photometric interpretation (for all bit depths).

6
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb888TiffColor.cs

@ -6,7 +6,7 @@ using System;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Formats.Tiff
namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
{
/// <summary>
/// Implements the 'RGB' photometric interpretation (optimized for 8-bit full color images).
@ -14,10 +14,6 @@ namespace SixLabors.ImageSharp.Formats.Tiff
internal class Rgb888TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
public Rgb888TiffColor()
{
}
/// <inheritdoc/>
public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
{

2
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbPlanarTiffColor.cs

@ -6,7 +6,7 @@ using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Formats.Tiff
namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
{
/// <summary>
/// Implements the 'RGB' photometric interpretation with 'Planar' layout (for all bit depths).

2
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbTiffColor.cs

@ -7,7 +7,7 @@ using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Formats.Tiff
namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
{
/// <summary>
/// Implements the 'RGB' photometric interpretation (for all bit depths).

16
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffBaseColorDecoder.cs

@ -5,7 +5,7 @@ using System;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Formats.Tiff
namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
{
/// <summary>
/// The base class for photometric interpretation decoders.
@ -14,20 +14,6 @@ namespace SixLabors.ImageSharp.Formats.Tiff
internal abstract class TiffBaseColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
protected TiffBaseColorDecoder()
{
}
/*
/// <summary>
/// Gets the photometric interpretation value.
/// </summary>
/// <value>
/// The photometric interpretation value.
/// </value>
public TiffColorType ColorType { get; }
*/
/// <summary>
/// Decodes source raw pixel data using the current photometric interpretation.
/// </summary>

2
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory.cs

@ -3,7 +3,7 @@
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Formats.Tiff
namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
{
internal static class TiffColorDecoderFactory<TPixel>
where TPixel : unmanaged, IPixel<TPixel>

2
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorType.cs

@ -1,7 +1,7 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.Formats.Tiff
namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
{
/// <summary>
/// Provides enumeration of the various TIFF photometric interpretation implementation types.

6
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero1TiffColor.cs

@ -6,7 +6,7 @@ using System;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Formats.Tiff
namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
{
/// <summary>
/// Implements the 'WhiteIsZero' photometric interpretation (optimized for bilevel images).
@ -14,10 +14,6 @@ namespace SixLabors.ImageSharp.Formats.Tiff
internal class WhiteIsZero1TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
public WhiteIsZero1TiffColor()
{
}
/// <inheritdoc/>
public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
{

6
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero4TiffColor.cs

@ -6,7 +6,7 @@ using System;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Formats.Tiff
namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
{
/// <summary>
/// Implements the 'WhiteIsZero' photometric interpretation (optimized for 4-bit grayscale images).
@ -14,10 +14,6 @@ namespace SixLabors.ImageSharp.Formats.Tiff
internal class WhiteIsZero4TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
public WhiteIsZero4TiffColor()
{
}
/// <inheritdoc/>
public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
{

6
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero8TiffColor.cs

@ -6,7 +6,7 @@ using System;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Formats.Tiff
namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
{
/// <summary>
/// Implements the 'WhiteIsZero' photometric interpretation (optimized for 8-bit grayscale images).
@ -14,10 +14,6 @@ namespace SixLabors.ImageSharp.Formats.Tiff
internal class WhiteIsZero8TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
public WhiteIsZero8TiffColor()
{
}
/// <inheritdoc/>
public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
{

2
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZeroTiffColor.cs

@ -7,7 +7,7 @@ using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Formats.Tiff
namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
{
/// <summary>
/// Implements the 'WhiteIsZero' photometric interpretation (for all bit depths).

5
src/ImageSharp/Formats/Tiff/README.md

@ -25,6 +25,9 @@
## Implementation Status
- The Decoder and Encoder currently only supports a single frame per image.
- Some compression formats are not yet supported. See the list below.
### Deviations from the TIFF spec (to be fixed)
- Decoder
@ -46,7 +49,7 @@
|Lzw | Y | Y | Based on ImageSharp GIF LZW implementation - this code could be modified to be (i) shared, or (ii) optimised for each case |
|Old Jpeg | | | We should not even try to support this |
|Jpeg (Technote 2) | | | |
|Deflate (Technote 2) | Y | Y | Based on PNG Deflate. |
|Deflate (Technote 2) | Y | Y | Based on PNG Deflate. |
|Old Deflate (Technote 2) | | Y | |
### Photometric Interpretation Formats

1
src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs

@ -5,6 +5,7 @@ using System.Collections.Generic;
using System.Threading;
using SixLabors.ImageSharp.Formats.Tiff.Compression;
using SixLabors.ImageSharp.Formats.Tiff.Constants;
using SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation;
using SixLabors.ImageSharp.IO;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata;

1
src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs

@ -3,6 +3,7 @@
using SixLabors.ImageSharp.Formats.Tiff.Compression;
using SixLabors.ImageSharp.Formats.Tiff.Constants;
using SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation;
using SixLabors.ImageSharp.Metadata.Profiles.Exif;
namespace SixLabors.ImageSharp.Formats.Tiff

3
src/ImageSharp/Formats/Tiff/TiffEncoder.cs

@ -36,9 +36,6 @@ namespace SixLabors.ImageSharp.Formats.Tiff
/// <inheritdoc/>
public IQuantizer Quantizer { get; set; }
/// <inheritdoc/>
public int MaxStripBytes { get; set; } = TiffEncoderCore.DefaultStripSize;
/// <inheritdoc/>
public void Encode<TPixel>(Image<TPixel> image, Stream stream)
where TPixel : unmanaged, IPixel<TPixel>

68
src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs

@ -25,8 +25,6 @@ namespace SixLabors.ImageSharp.Formats.Tiff
/// </summary>
internal sealed class TiffEncoderCore : IImageEncoderInternals
{
public const int DefaultStripSize = 8 * 1024;
private static readonly ushort ByteOrderMarker = BitConverter.IsLittleEndian
? TiffConstants.ByteOrderLittleEndianShort
: TiffConstants.ByteOrderBigEndianShort;
@ -56,11 +54,6 @@ namespace SixLabors.ImageSharp.Formats.Tiff
/// </summary>
private readonly DeflateCompressionLevel compressionLevel;
/// <summary>
/// The maximum number of bytes for a strip.
/// </summary>
private readonly int maxStripBytes;
/// <summary>
/// Initializes a new instance of the <see cref="TiffEncoderCore"/> class.
/// </summary>
@ -75,7 +68,6 @@ namespace SixLabors.ImageSharp.Formats.Tiff
this.HorizontalPredictor = options.HorizontalPredictor;
this.CompressionType = options.Compression;
this.compressionLevel = options.CompressionLevel;
this.maxStripBytes = options.MaxStripBytes;
}
/// <summary>
@ -120,10 +112,9 @@ namespace SixLabors.ImageSharp.Formats.Tiff
this.configuration = image.GetConfiguration();
ImageMetadata metadata = image.Metadata;
TiffMetadata tiffMetadata = metadata.GetTiffMetadata();
this.BitsPerPixel ??= tiffMetadata.BitsPerPixel;
this.SetMode(tiffMetadata);
this.SetBitsPerPixel();
this.SetBitsPerPixel(tiffMetadata);
this.SetPhotometricInterpretation();
using (var writer = new TiffStreamWriter(stream))
@ -176,7 +167,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff
image.Width,
(int)tiffBitsPerPixel,
this.compressionLevel,
this.HorizontalPredictor != TiffPredictor.FloatingPoint ? this.HorizontalPredictor : TiffPredictor.None);
this.HorizontalPredictor == TiffPredictor.Horizontal ? this.HorizontalPredictor : TiffPredictor.None);
using TiffBaseColorWriter<TPixel> colorWriter = TiffColorWriterFactory.Create(
this.Mode,
@ -210,8 +201,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff
DebugGuard.MustBeGreaterThan(height, 0, nameof(height));
DebugGuard.MustBeGreaterThan(bytesPerRow, 0, nameof(bytesPerRow));
int stripBytes = this.maxStripBytes > 0 ? this.maxStripBytes : DefaultStripSize;
int rowsPerStrip = stripBytes / bytesPerRow;
int rowsPerStrip = TiffConstants.DefaultStripSize / bytesPerRow;
return rowsPerStrip > 0 ? (rowsPerStrip < height ? rowsPerStrip : height) : 1;
}
@ -293,30 +283,46 @@ namespace SixLabors.ImageSharp.Formats.Tiff
}
}
if (this.Mode == TiffEncodingMode.Default && this.BitsPerPixel != null)
if (this.Mode == TiffEncodingMode.Default && tiffMetadata.BitsPerPixel != null)
{
// Preserve input bits per pixel, if no encoding mode was specified.
switch (this.BitsPerPixel)
{
case TiffBitsPerPixel.Bit1:
this.Mode = TiffEncodingMode.BiColor;
break;
case TiffBitsPerPixel.Bit4:
this.Mode = TiffEncodingMode.ColorPalette;
break;
case TiffBitsPerPixel.Bit8:
this.Mode = tiffMetadata.PhotometricInterpretation == TiffPhotometricInterpretation.PaletteColor ? TiffEncodingMode.ColorPalette : TiffEncodingMode.Gray;
break;
default:
this.Mode = TiffEncodingMode.Rgb;
break;
}
this.SetModeWithBitsPerPixel(tiffMetadata.BitsPerPixel, tiffMetadata.PhotometricInterpretation);
return;
}
if (this.BitsPerPixel != null)
{
// The user has specified a bits per pixel, so use that to determine the encoding mode.
this.SetModeWithBitsPerPixel(this.BitsPerPixel, tiffMetadata.PhotometricInterpretation);
}
}
private void SetBitsPerPixel()
private void SetModeWithBitsPerPixel(TiffBitsPerPixel? bitsPerPixel, TiffPhotometricInterpretation photometricInterpretation)
{
switch (bitsPerPixel)
{
case TiffBitsPerPixel.Bit1:
this.Mode = TiffEncodingMode.BiColor;
break;
case TiffBitsPerPixel.Bit4:
this.Mode = TiffEncodingMode.ColorPalette;
break;
case TiffBitsPerPixel.Bit8:
this.Mode = photometricInterpretation == TiffPhotometricInterpretation.PaletteColor
? TiffEncodingMode.ColorPalette
: TiffEncodingMode.Gray;
break;
default:
this.Mode = TiffEncodingMode.Rgb;
break;
}
}
private void SetBitsPerPixel(TiffMetadata tiffMetadata)
{
this.BitsPerPixel ??= tiffMetadata.BitsPerPixel;
switch (this.Mode)
{
case TiffEncodingMode.BiColor:

6
src/ImageSharp/Formats/Tiff/Writers/TiffBaseColorWriter.cs

@ -22,8 +22,14 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Writers
this.EntriesCollector = entriesCollector;
}
/// <summary>
/// Gets the bits per pixel.
/// </summary>
public abstract int BitsPerPixel { get; }
/// <summary>
/// Gets the bytes per row.
/// </summary>
public int BytesPerRow => ((this.Image.Width * this.BitsPerPixel) + 7) / 8;
protected ImageFrame<TPixel> Image { get; }

2
src/ImageSharp/Formats/Tiff/Writers/TiffStreamWriter.cs

@ -10,7 +10,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Writers
/// <summary>
/// Utility class for writing TIFF data to a <see cref="Stream"/>.
/// </summary>
internal class TiffStreamWriter : IDisposable
internal sealed class TiffStreamWriter : IDisposable
{
private static readonly byte[] PaddingBytes = new byte[4];

36
src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs

@ -91,9 +91,6 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
private readonly byte[] buf2 = new byte[2];
private readonly Stream data;
private bool isBigEndian;
private List<ExifTag> invalidTags;
private uint exifOffset;
@ -120,11 +117,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
/// </summary>
public uint ThumbnailOffset { get; protected set; }
public bool IsBigEndian
{
get => this.isBigEndian;
protected set => this.isBigEndian = value;
}
public bool IsBigEndian { get; protected set; }
protected abstract void RegisterExtLoader(uint offset, Action loader);
@ -330,7 +323,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
{
uint newOffset = this.ConvertToUInt32(this.offsetBuffer);
// Ensure that the new index does not overrun the data
// Ensure that the new index does not overrun the data.
if (newOffset > int.MaxValue || (newOffset + size) > this.data.Length)
{
this.AddInvalidTag(new UnkownExifTag(tag));
@ -339,7 +332,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
this.RegisterExtLoader(newOffset, () =>
{
var dataBuffer = new byte[size];
byte[] dataBuffer = new byte[size];
this.Seek(newOffset);
if (this.TryReadSpan(dataBuffer))
{
@ -365,8 +358,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
foreach (IExifValue val in values)
{
// sometimes duplicates appear,
// can compare val.Tag == exif.Tag
// Sometimes duplicates appear, can compare val.Tag == exif.Tag
if (val == exif)
{
Debug.WriteLine($"Duplicate Exif tag: tag={exif.Tag}, dataType={exif.DataType}");
@ -403,11 +395,11 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
return false;
}
int readed = this.data.Read(span);
return readed == length;
int read = this.data.Read(span);
return read == length;
}
// Known as Long in Exif Specification
// Known as Long in Exif Specification.
protected uint ReadUInt32() =>
this.TryReadSpan(this.buf4)
? this.ConvertToUInt32(this.buf4)
@ -424,7 +416,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
return default;
}
long intValue = this.isBigEndian
long intValue = this.IsBigEndian
? BinaryPrimitives.ReadInt64BigEndian(buffer)
: BinaryPrimitives.ReadInt64LittleEndian(buffer);
@ -433,13 +425,13 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
private uint ConvertToUInt32(ReadOnlySpan<byte> buffer)
{
// Known as Long in Exif Specification
// Known as Long in Exif Specification.
if (buffer.Length < 4)
{
return default;
}
return this.isBigEndian
return this.IsBigEndian
? BinaryPrimitives.ReadUInt32BigEndian(buffer)
: BinaryPrimitives.ReadUInt32LittleEndian(buffer);
}
@ -451,7 +443,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
return default;
}
return this.isBigEndian
return this.IsBigEndian
? BinaryPrimitives.ReadUInt16BigEndian(buffer)
: BinaryPrimitives.ReadUInt16LittleEndian(buffer);
}
@ -463,7 +455,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
return default;
}
int intValue = this.isBigEndian
int intValue = this.IsBigEndian
? BinaryPrimitives.ReadInt32BigEndian(buffer)
: BinaryPrimitives.ReadInt32LittleEndian(buffer);
@ -492,7 +484,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
return default;
}
return this.isBigEndian
return this.IsBigEndian
? BinaryPrimitives.ReadInt32BigEndian(buffer)
: BinaryPrimitives.ReadInt32LittleEndian(buffer);
}
@ -517,7 +509,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
return default;
}
return this.isBigEndian
return this.IsBigEndian
? BinaryPrimitives.ReadInt16BigEndian(buffer)
: BinaryPrimitives.ReadInt16LittleEndian(buffer);
}

2
tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/BlackIsZeroTiffColorTests.cs

@ -3,7 +3,7 @@
using System.Collections.Generic;
using SixLabors.ImageSharp.Formats.Tiff;
using SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation;
using SixLabors.ImageSharp.PixelFormats;
using Xunit;

21
tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/PaletteTiffColorTests.cs

@ -3,7 +3,7 @@
using System.Collections.Generic;
using SixLabors.ImageSharp.Formats.Tiff;
using SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation;
using SixLabors.ImageSharp.PixelFormats;
using Xunit;
@ -13,9 +13,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff.PhotometricInterpretation
[Trait("Format", "Tiff")]
public class PaletteTiffColorTests : PhotometricInterpretationTestBase
{
public static uint[][] Palette4ColorPalette { get => GeneratePalette(16); }
public static uint[][] Palette4ColorPalette => GeneratePalette(16);
public static ushort[] Palette4ColorMap { get => GenerateColorMap(Palette4ColorPalette); }
public static ushort[] Palette4ColorMap => GenerateColorMap(Palette4ColorPalette);
private static readonly byte[] Palette4Bytes4X4 =
{
@ -54,9 +54,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff.PhotometricInterpretation
}
}
public static uint[][] Palette8ColorPalette { get => GeneratePalette(256); }
public static uint[][] Palette8ColorPalette => GeneratePalette(256);
public static ushort[] Palette8ColorMap { get => GenerateColorMap(Palette8ColorPalette); }
public static ushort[] Palette8ColorMap => GenerateColorMap(Palette8ColorPalette);
private static readonly byte[] Palette8Bytes4X4 =
{
@ -83,13 +83,10 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff.PhotometricInterpretation
[Theory]
[MemberData(nameof(Palette4Data))]
[MemberData(nameof(Palette8Data))]
public void Decode_WritesPixelData(byte[] inputData, ushort bitsPerSample, ushort[] colorMap, int left, int top, int width, int height, Rgba32[][] expectedResult)
{
AssertDecode(expectedResult, pixels =>
{
new PaletteTiffColor<Rgba32>(new[] { bitsPerSample }, colorMap).Decode(inputData, pixels, left, top, width, height);
});
}
public void Decode_WritesPixelData(byte[] inputData, ushort bitsPerSample, ushort[] colorMap, int left, int top, int width, int height, Rgba32[][] expectedResult) => AssertDecode(expectedResult, pixels =>
{
new PaletteTiffColor<Rgba32>(new[] { bitsPerSample }, colorMap).Decode(inputData, pixels, left, top, width, height);
});
private static uint[][] GeneratePalette(int count)
{

2
tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/RgbPlanarTiffColorTests.cs

@ -4,7 +4,7 @@
using System;
using System.Collections.Generic;
using SixLabors.ImageSharp.Formats.Tiff;
using SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;

2
tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/RgbTiffColorTests.cs

@ -3,7 +3,7 @@
using System.Collections.Generic;
using SixLabors.ImageSharp.Formats.Tiff;
using SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation;
using SixLabors.ImageSharp.PixelFormats;
using Xunit;

2
tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/WhiteIsZeroTiffColorTests.cs

@ -3,7 +3,7 @@
using System.Collections.Generic;
using SixLabors.ImageSharp.Formats.Tiff;
using SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation;
using SixLabors.ImageSharp.PixelFormats;
using Xunit;

38
tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs

@ -309,28 +309,28 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
where TPixel : unmanaged, IPixel<TPixel> => TestTiffEncoderCore(provider, TiffBitsPerPixel.Bit1, TiffEncodingMode.BiColor, TiffCompression.Ccitt1D);
[Theory]
[WithFile(GrayscaleUncompressed, PixelTypes.L8, TiffEncodingMode.Gray, TiffCompression.PackBits, 16 * 1024)]
[WithFile(PaletteDeflateMultistrip, PixelTypes.L8, TiffEncodingMode.ColorPalette, TiffCompression.Lzw, 32 * 1024)]
[WithFile(RgbUncompressed, PixelTypes.Rgba32, TiffEncodingMode.Rgb, TiffCompression.Deflate, 64 * 1024)]
[WithFile(RgbUncompressed, PixelTypes.Rgb24, TiffEncodingMode.Rgb, TiffCompression.None, 10 * 1024)]
[WithFile(RgbUncompressed, PixelTypes.Rgba32, TiffEncodingMode.Rgb, TiffCompression.None, 30 * 1024)]
[WithFile(RgbUncompressed, PixelTypes.Rgb48, TiffEncodingMode.Rgb, TiffCompression.None, 70 * 1024)]
public void TiffEncoder_StripLength<TPixel>(TestImageProvider<TPixel> provider, TiffEncodingMode mode, TiffCompression compression, int maxSize)
[WithFile(GrayscaleUncompressed, PixelTypes.L8, TiffEncodingMode.Gray, TiffCompression.PackBits)]
[WithFile(PaletteDeflateMultistrip, PixelTypes.L8, TiffEncodingMode.ColorPalette, TiffCompression.Lzw)]
[WithFile(RgbUncompressed, PixelTypes.Rgba32, TiffEncodingMode.Rgb, TiffCompression.Deflate)]
[WithFile(RgbUncompressed, PixelTypes.Rgb24, TiffEncodingMode.Rgb, TiffCompression.None)]
[WithFile(RgbUncompressed, PixelTypes.Rgba32, TiffEncodingMode.Rgb, TiffCompression.None)]
[WithFile(RgbUncompressed, PixelTypes.Rgb48, TiffEncodingMode.Rgb, TiffCompression.None)]
public void TiffEncoder_StripLength<TPixel>(TestImageProvider<TPixel> provider, TiffEncodingMode mode, TiffCompression compression)
where TPixel : unmanaged, IPixel<TPixel> =>
TestStripLength(provider, mode, compression, maxSize);
TestStripLength(provider, mode, compression);
[Theory]
[WithFile(Calliphora_BiColorUncompressed, PixelTypes.L8, TiffEncodingMode.BiColor, TiffCompression.CcittGroup3Fax, 9 * 1024)]
public void TiffEncoder_StripLength_OutOfBounds<TPixel>(TestImageProvider<TPixel> provider, TiffEncodingMode mode, TiffCompression compression, int maxSize)
[WithFile(Calliphora_BiColorUncompressed, PixelTypes.L8, TiffEncodingMode.BiColor, TiffCompression.CcittGroup3Fax)]
public void TiffEncoder_StripLength_OutOfBounds<TPixel>(TestImageProvider<TPixel> provider, TiffEncodingMode mode, TiffCompression compression)
where TPixel : unmanaged, IPixel<TPixel> =>
//// CcittGroup3Fax compressed data length can be larger than the original length
Assert.Throws<Xunit.Sdk.TrueException>(() => TestStripLength(provider, mode, compression, maxSize));
Assert.Throws<Xunit.Sdk.TrueException>(() => TestStripLength(provider, mode, compression));
private static void TestStripLength<TPixel>(TestImageProvider<TPixel> provider, TiffEncodingMode mode, TiffCompression compression, int maxSize)
private static void TestStripLength<TPixel>(TestImageProvider<TPixel> provider, TiffEncodingMode mode, TiffCompression compression)
where TPixel : unmanaged, IPixel<TPixel>
{
// arrange
var tiffEncoder = new TiffEncoder() { Mode = mode, Compression = compression, MaxStripBytes = maxSize };
var tiffEncoder = new TiffEncoder() { Mode = mode, Compression = compression };
Image<TPixel> input = provider.GetImage();
using var memStream = new MemoryStream();
TiffFrameMetadata inputMeta = input.Frames.RootFrame.Metadata.GetTiffMetadata();
@ -349,7 +349,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
foreach (Number sz in meta.StripByteCounts)
{
Assert.True((uint)sz <= maxSize);
Assert.True((uint)sz <= TiffConstants.DefaultStripSize);
}
// For uncompressed more accurate test.
@ -359,9 +359,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
{
// The difference must be less than one row.
int stripBytes = (int)meta.StripByteCounts[i];
var widthBytes = (meta.BitsPerPixel + 7) / 8 * (int)meta.Width;
int widthBytes = (meta.BitsPerPixel + 7) / 8 * (int)meta.Width;
Assert.True((maxSize - stripBytes) < widthBytes);
Assert.True((TiffConstants.DefaultStripSize - stripBytes) < widthBytes);
}
}
@ -370,8 +370,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
provider,
(TiffBitsPerPixel)inputMeta.BitsPerPixel,
mode,
inputMeta.Compression,
maxStripSize: maxSize);
inputMeta.Compression);
}
private static void TestTiffEncoderCore<TPixel>(
@ -391,8 +390,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
Mode = mode,
BitsPerPixel = bitsPerPixel,
Compression = compression,
HorizontalPredictor = predictor,
MaxStripBytes = maxStripSize
HorizontalPredictor = predictor
};
// Does DebugSave & load reference CompareToReferenceInput():

1
tests/ImageSharp.Tests/ImageSharp.Tests.csproj

@ -23,7 +23,6 @@
</Choose>
<ItemGroup>
<DotNetCliToolReference Include="dotnet-xunit" />
<InternalsVisibleTo Include="ImageSharp.Tests.ProfilingSandbox" Key="$(SixLaborsPublicKey)" />
</ItemGroup>

Loading…
Cancel
Save