Browse Source

Introduce TiffBitsPerSample enum

pull/1570/head
Brian Popow 5 years ago
parent
commit
8077172088
  1. 36
      src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs
  2. 99
      src/ImageSharp/Formats/Tiff/TiffBitsPerSampleExtensions.cs
  3. 15
      src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs
  4. 4
      src/ImageSharp/Formats/Tiff/TiffDecoderMetadataCreator.cs
  5. 157
      src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs
  6. 30
      src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs
  7. 3
      tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs

36
src/ImageSharp/Formats/Tiff/TiffBitsPerSample.cs

@ -0,0 +1,36 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.Formats.Tiff
{
/// <summary>
/// The number of bits per component.
/// </summary>
public enum TiffBitsPerSample
{
/// <summary>
/// The Bits per samples is not known.
/// </summary>
Unknown,
/// <summary>
/// One bit per sample for bicolor images.
/// </summary>
One,
/// <summary>
/// Four bits per sample for grayscale images with 16 different levels of gray or paletted images with a palette of 16 colors.
/// </summary>
Four,
/// <summary>
/// Eight bits per sample for grayscale images with 256 different levels of gray or paletted images with a palette of 256 colors.
/// </summary>
Eight,
/// <summary>
/// Each channel has 8 Bits.
/// </summary>
Rgb888,
}
}

99
src/ImageSharp/Formats/Tiff/TiffBitsPerSampleExtensions.cs

@ -0,0 +1,99 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.ImageSharp.Formats.Experimental.Tiff;
namespace SixLabors.ImageSharp.Formats.Tiff
{
internal static class TiffBitsPerSampleExtensions
{
private static readonly ushort[] One = { 1 };
private static readonly ushort[] Four = { 4 };
private static readonly ushort[] Eight = { 8 };
private static readonly ushort[] Rgb888 = { 8, 8, 8 };
/// <summary>
/// Gets the bits per channel array for a given BitsPerSample value, e,g, for RGB888: [8, 8, 8]
/// </summary>
/// <param name="tiffBitsPerSample">The tiff bits per sample.</param>
/// <returns>Bits per sample array.</returns>
public static ushort[] Bits(this TiffBitsPerSample tiffBitsPerSample)
{
switch (tiffBitsPerSample)
{
case TiffBitsPerSample.One:
return One;
case TiffBitsPerSample.Four:
return Four;
case TiffBitsPerSample.Eight:
return Eight;
case TiffBitsPerSample.Rgb888:
return Rgb888;
default:
TiffThrowHelper.ThrowNotSupported("The bits per pixels are not supported");
return Array.Empty<ushort>();
}
}
/// <summary>
/// Maps an array of bits per sample to a concrete enum value.
/// </summary>
/// <param name="bitsPerSample">The bits per sample array.</param>
/// <returns>TiffBitsPerSample enum value.</returns>
public static TiffBitsPerSample GetBitsPerSample(this ushort[] bitsPerSample)
{
switch (bitsPerSample.Length)
{
case 3:
if (bitsPerSample[0] == Rgb888[0] && bitsPerSample[1] == Rgb888[1] && bitsPerSample[2] == Rgb888[2])
{
return TiffBitsPerSample.Rgb888;
}
break;
case 1:
if (bitsPerSample[0] == One[0])
{
return TiffBitsPerSample.One;
}
if (bitsPerSample[0] == Four[0])
{
return TiffBitsPerSample.Four;
}
if (bitsPerSample[0] == Eight[0])
{
return TiffBitsPerSample.Eight;
}
break;
}
return TiffBitsPerSample.Unknown;
}
/// <summary>
/// Gets the bits per pixel for the given bits per sample.
/// </summary>
/// <param name="tiffBitsPerSample">The tiff bits per sample.</param>
/// <returns>Bits per pixel.</returns>
public static int BitsPerPixel(this TiffBitsPerSample tiffBitsPerSample)
{
var bitsPerSample = tiffBitsPerSample.Bits();
int bitsPerPixel = 0;
foreach (var bits in bitsPerSample)
{
bitsPerPixel += bits;
}
return bitsPerPixel;
}
}
}

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

@ -5,6 +5,7 @@ using System.Collections.Generic;
using System.Threading;
using SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression;
using SixLabors.ImageSharp.Formats.Experimental.Tiff.Constants;
using SixLabors.ImageSharp.Formats.Tiff;
using SixLabors.ImageSharp.IO;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata;
@ -48,9 +49,9 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
}
/// <summary>
/// Gets or sets the number of bits for each sample of the pixel format used to encode the image.
/// Gets or sets the number of bits per component of the pixel format used to decode the image.
/// </summary>
public ushort[] BitsPerSample { get; set; }
public TiffBitsPerSample BitsPerSample { get; set; }
/// <summary>
/// Gets or sets the bits per pixel.
@ -154,7 +155,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
ImageMetadata metadata = TiffDecoderMetadataCreator.Create(framesMetadata, this.ignoreMetadata, reader.ByteOrder);
TiffFrameMetadata root = framesMetadata[0];
return new ImageInfo(new PixelTypeInfo(root.BitsPerPixel), (int)root.Width, (int)root.Height, metadata);
return new ImageInfo(new PixelTypeInfo(root.BitsPerSample.BitsPerPixel()), (int)root.Width, (int)root.Height, metadata);
}
/// <summary>
@ -213,7 +214,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
}
else
{
bitsPerPixel = this.BitsPerSample[plane];
bitsPerPixel = this.BitsPerSample.Bits()[plane];
}
int bytesPerRow = ((width * bitsPerPixel) + 7) / 8;
@ -233,7 +234,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
private void DecodeStripsPlanar<TPixel>(ImageFrame<TPixel> frame, int rowsPerStrip, Number[] stripOffsets, Number[] stripByteCounts)
where TPixel : unmanaged, IPixel<TPixel>
{
int stripsPerPixel = this.BitsPerSample.Length;
int stripsPerPixel = this.BitsPerSample.Bits().Length;
int stripsPerPlane = stripOffsets.Length / stripsPerPixel;
int bitsPerPixel = this.BitsPerPixel;
@ -251,7 +252,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
using TiffBaseDecompresor decompressor = TiffDecompressorsFactory.Create(this.CompressionType, this.memoryAllocator, this.PhotometricInterpretation, frame.Width, bitsPerPixel, this.Predictor, this.FaxCompressionOptions);
RgbPlanarTiffColor<TPixel> colorDecoder = TiffColorDecoderFactory<TPixel>.CreatePlanar(this.ColorType, this.BitsPerSample, this.ColorMap);
RgbPlanarTiffColor<TPixel> colorDecoder = TiffColorDecoderFactory<TPixel>.CreatePlanar(this.ColorType, this.BitsPerSample.Bits(), this.ColorMap);
for (int i = 0; i < stripsPerPlane; i++)
{
@ -294,7 +295,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
using TiffBaseDecompresor decompressor = TiffDecompressorsFactory.Create(this.CompressionType, this.memoryAllocator, this.PhotometricInterpretation, frame.Width, bitsPerPixel, this.Predictor, this.FaxCompressionOptions);
TiffBaseColorDecoder<TPixel> colorDecoder = TiffColorDecoderFactory<TPixel>.Create(this.ColorType, this.BitsPerSample, this.ColorMap);
TiffBaseColorDecoder<TPixel> colorDecoder = TiffColorDecoderFactory<TPixel>.Create(this.ColorType, this.BitsPerSample.Bits(), this.ColorMap);
for (int stripIndex = 0; stripIndex < stripOffsets.Length; stripIndex++)
{

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

@ -4,7 +4,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using SixLabors.ImageSharp.Formats.Tiff;
using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.Metadata.Profiles.Exif;
using SixLabors.ImageSharp.Metadata.Profiles.Icc;
@ -129,6 +129,6 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
}
private static TiffBitsPerPixel GetBitsPerPixel(TiffFrameMetadata firstFrameMetaData)
=> (TiffBitsPerPixel)firstFrameMetaData.BitsPerPixel;
=> (TiffBitsPerPixel)firstFrameMetaData.BitsPerSample.BitsPerPixel();
}
}

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

@ -3,6 +3,7 @@
using SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression;
using SixLabors.ImageSharp.Formats.Experimental.Tiff.Constants;
using SixLabors.ImageSharp.Formats.Tiff;
using SixLabors.ImageSharp.Metadata.Profiles.Exif;
namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
@ -59,7 +60,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
options.Predictor = entries.Predictor;
options.PhotometricInterpretation = entries.PhotometricInterpretation;
options.BitsPerSample = entries.BitsPerSample;
options.BitsPerPixel = entries.BitsPerPixel;
options.BitsPerPixel = entries.BitsPerSample.BitsPerPixel();
ParseColorType(options, entries);
ParseCompression(options, entries);
@ -71,38 +72,36 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
{
case TiffPhotometricInterpretation.WhiteIsZero:
{
if (options.BitsPerSample.Length == 1)
if (options.BitsPerSample.Bits().Length != 1)
{
switch (options.BitsPerSample[0])
{
case 8:
{
options.ColorType = TiffColorType.WhiteIsZero8;
break;
}
case 4:
{
options.ColorType = TiffColorType.WhiteIsZero4;
break;
}
case 1:
{
options.ColorType = TiffColorType.WhiteIsZero1;
break;
}
default:
{
options.ColorType = TiffColorType.WhiteIsZero;
break;
}
}
TiffThrowHelper.ThrowNotSupported("The number of samples in the TIFF BitsPerSample entry is not supported.");
}
else
switch (options.BitsPerSample)
{
TiffThrowHelper.ThrowNotSupported("The number of samples in the TIFF BitsPerSample entry is not supported.");
case TiffBitsPerSample.Eight:
{
options.ColorType = TiffColorType.WhiteIsZero8;
break;
}
case TiffBitsPerSample.Four:
{
options.ColorType = TiffColorType.WhiteIsZero4;
break;
}
case TiffBitsPerSample.One:
{
options.ColorType = TiffColorType.WhiteIsZero1;
break;
}
default:
{
options.ColorType = TiffColorType.WhiteIsZero;
break;
}
}
break;
@ -110,38 +109,36 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
case TiffPhotometricInterpretation.BlackIsZero:
{
if (options.BitsPerSample.Length == 1)
if (options.BitsPerSample.Bits().Length != 1)
{
switch (options.BitsPerSample[0])
{
case 8:
{
options.ColorType = TiffColorType.BlackIsZero8;
break;
}
case 4:
{
options.ColorType = TiffColorType.BlackIsZero4;
break;
}
case 1:
{
options.ColorType = TiffColorType.BlackIsZero1;
break;
}
default:
{
options.ColorType = TiffColorType.BlackIsZero;
break;
}
}
TiffThrowHelper.ThrowNotSupported("The number of samples in the TIFF BitsPerSample entry is not supported.");
}
else
switch (options.BitsPerSample)
{
TiffThrowHelper.ThrowNotSupported("The number of samples in the TIFF BitsPerSample entry is not supported.");
case TiffBitsPerSample.Eight:
{
options.ColorType = TiffColorType.BlackIsZero8;
break;
}
case TiffBitsPerSample.Four:
{
options.ColorType = TiffColorType.BlackIsZero4;
break;
}
case TiffBitsPerSample.One:
{
options.ColorType = TiffColorType.BlackIsZero1;
break;
}
default:
{
options.ColorType = TiffColorType.BlackIsZero;
break;
}
}
break;
@ -149,27 +146,18 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
case TiffPhotometricInterpretation.Rgb:
{
if (options.BitsPerSample.Length == 3)
if (options.BitsPerSample.Bits().Length != 3)
{
if (options.PlanarConfiguration == TiffPlanarConfiguration.Chunky)
{
if (options.BitsPerSample[0] == 8 && options.BitsPerSample[1] == 8 && options.BitsPerSample[2] == 8)
{
options.ColorType = TiffColorType.Rgb888;
}
else
{
options.ColorType = TiffColorType.Rgb;
}
}
else
{
options.ColorType = TiffColorType.RgbPlanar;
}
TiffThrowHelper.ThrowNotSupported("The number of samples in the TIFF BitsPerSample entry is not supported.");
}
if (options.PlanarConfiguration == TiffPlanarConfiguration.Chunky)
{
options.ColorType = options.BitsPerSample == TiffBitsPerSample.Rgb888 ? TiffColorType.Rgb888 : TiffColorType.Rgb;
}
else
{
TiffThrowHelper.ThrowNotSupported("The number of samples in the TIFF BitsPerSample entry is not supported.");
options.ColorType = TiffColorType.RgbPlanar;
}
break;
@ -180,21 +168,12 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
options.ColorMap = entries.ColorMap;
if (options.ColorMap != null)
{
if (options.BitsPerSample.Length == 1)
{
switch (options.BitsPerSample[0])
{
default:
{
options.ColorType = TiffColorType.PaletteColor;
break;
}
}
}
else
if (options.BitsPerSample.Bits().Length != 1)
{
TiffThrowHelper.ThrowNotSupported("The number of samples in the TIFF BitsPerSample entry is not supported.");
}
options.ColorType = TiffColorType.PaletteColor;
}
else
{
@ -206,7 +185,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
default:
{
TiffThrowHelper.ThrowNotSupported("The specified TIFF photometric interpretation is not supported: " + options.PhotometricInterpretation);
TiffThrowHelper.ThrowNotSupported($"The specified TIFF photometric interpretation is not supported: {options.PhotometricInterpretation}");
}
break;

30
src/ImageSharp/Formats/Tiff/TiffFrameMetadata.cs

@ -4,6 +4,7 @@
using System.Collections.Generic;
using System.Linq;
using SixLabors.ImageSharp.Formats.Experimental.Tiff.Constants;
using SixLabors.ImageSharp.Formats.Tiff;
using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.Metadata.Profiles.Exif;
@ -88,7 +89,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
/// <summary>
/// Gets the number of bits per component.
/// </summary>
public ushort[] BitsPerSample
public TiffBitsPerSample BitsPerSample
{
get
{
@ -98,32 +99,21 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
if (this.PhotometricInterpretation == TiffPhotometricInterpretation.WhiteIsZero
|| this.PhotometricInterpretation == TiffPhotometricInterpretation.BlackIsZero)
{
bits = new[] { (ushort)1 };
return TiffBitsPerSample.One;
}
else
{
TiffThrowHelper.ThrowNotSupported("The TIFF BitsPerSample entry is missing.");
}
}
return bits;
}
}
internal int BitsPerPixel
{
get
{
int bitsPerPixel = 0;
foreach (var bits in this.BitsPerSample)
{
bitsPerPixel += bits;
TiffThrowHelper.ThrowNotSupported("The TIFF BitsPerSample entry is missing which is required to decode the image.");
}
return bitsPerPixel;
return bits.GetBitsPerSample();
}
}
/// <summary>
/// Gets the bits per pixel.
/// </summary>
public int BitsPerPixel => this.BitsPerSample.BitsPerPixel();
/// <summary>
/// Gets the compression scheme used on the image data.
/// </summary>

3
tests/ImageSharp.Tests/Formats/Tiff/TiffMetadataTests.cs

@ -8,6 +8,7 @@ using System.Linq;
using SixLabors.ImageSharp.Formats.Experimental.Tiff;
using SixLabors.ImageSharp.Formats.Experimental.Tiff.Constants;
using SixLabors.ImageSharp.Formats.Tiff;
using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.Metadata.Profiles.Exif;
using SixLabors.ImageSharp.Metadata.Profiles.Icc;
@ -187,7 +188,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
Assert.Equal(32u, frame.Width);
Assert.Equal(32u, frame.Height);
Assert.Equal(new ushort[] { 4 }, frame.BitsPerSample);
Assert.Equal(TiffBitsPerSample.Four, frame.BitsPerSample);
Assert.Equal(TiffCompression.Lzw, frame.Compression);
Assert.Equal(TiffPhotometricInterpretation.PaletteColor, frame.PhotometricInterpretation);
Assert.Equal("This is Название", frame.ImageDescription);

Loading…
Cancel
Save