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 System.Threading;
using SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression; using SixLabors.ImageSharp.Formats.Experimental.Tiff.Compression;
using SixLabors.ImageSharp.Formats.Experimental.Tiff.Constants; using SixLabors.ImageSharp.Formats.Experimental.Tiff.Constants;
using SixLabors.ImageSharp.Formats.Tiff;
using SixLabors.ImageSharp.IO; using SixLabors.ImageSharp.IO;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.Metadata;
@ -48,9 +49,9 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
} }
/// <summary> /// <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> /// </summary>
public ushort[] BitsPerSample { get; set; } public TiffBitsPerSample BitsPerSample { get; set; }
/// <summary> /// <summary>
/// Gets or sets the bits per pixel. /// 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); ImageMetadata metadata = TiffDecoderMetadataCreator.Create(framesMetadata, this.ignoreMetadata, reader.ByteOrder);
TiffFrameMetadata root = framesMetadata[0]; 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> /// <summary>
@ -213,7 +214,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
} }
else else
{ {
bitsPerPixel = this.BitsPerSample[plane]; bitsPerPixel = this.BitsPerSample.Bits()[plane];
} }
int bytesPerRow = ((width * bitsPerPixel) + 7) / 8; 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) private void DecodeStripsPlanar<TPixel>(ImageFrame<TPixel> frame, int rowsPerStrip, Number[] stripOffsets, Number[] stripByteCounts)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
int stripsPerPixel = this.BitsPerSample.Length; int stripsPerPixel = this.BitsPerSample.Bits().Length;
int stripsPerPlane = stripOffsets.Length / stripsPerPixel; int stripsPerPlane = stripOffsets.Length / stripsPerPixel;
int bitsPerPixel = this.BitsPerPixel; 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); 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++) 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); 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++) for (int stripIndex = 0; stripIndex < stripOffsets.Length; stripIndex++)
{ {

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

@ -4,7 +4,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using SixLabors.ImageSharp.Formats.Tiff;
using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.Metadata.Profiles.Exif; using SixLabors.ImageSharp.Metadata.Profiles.Exif;
using SixLabors.ImageSharp.Metadata.Profiles.Icc; using SixLabors.ImageSharp.Metadata.Profiles.Icc;
@ -129,6 +129,6 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
} }
private static TiffBitsPerPixel GetBitsPerPixel(TiffFrameMetadata firstFrameMetaData) 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.Compression;
using SixLabors.ImageSharp.Formats.Experimental.Tiff.Constants; using SixLabors.ImageSharp.Formats.Experimental.Tiff.Constants;
using SixLabors.ImageSharp.Formats.Tiff;
using SixLabors.ImageSharp.Metadata.Profiles.Exif; using SixLabors.ImageSharp.Metadata.Profiles.Exif;
namespace SixLabors.ImageSharp.Formats.Experimental.Tiff namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
@ -59,7 +60,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
options.Predictor = entries.Predictor; options.Predictor = entries.Predictor;
options.PhotometricInterpretation = entries.PhotometricInterpretation; options.PhotometricInterpretation = entries.PhotometricInterpretation;
options.BitsPerSample = entries.BitsPerSample; options.BitsPerSample = entries.BitsPerSample;
options.BitsPerPixel = entries.BitsPerPixel; options.BitsPerPixel = entries.BitsPerSample.BitsPerPixel();
ParseColorType(options, entries); ParseColorType(options, entries);
ParseCompression(options, entries); ParseCompression(options, entries);
@ -71,38 +72,36 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
{ {
case TiffPhotometricInterpretation.WhiteIsZero: case TiffPhotometricInterpretation.WhiteIsZero:
{ {
if (options.BitsPerSample.Length == 1) if (options.BitsPerSample.Bits().Length != 1)
{ {
switch (options.BitsPerSample[0]) TiffThrowHelper.ThrowNotSupported("The number of samples in the TIFF BitsPerSample entry is not supported.");
{
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;
}
}
} }
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; break;
@ -110,38 +109,36 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
case TiffPhotometricInterpretation.BlackIsZero: case TiffPhotometricInterpretation.BlackIsZero:
{ {
if (options.BitsPerSample.Length == 1) if (options.BitsPerSample.Bits().Length != 1)
{ {
switch (options.BitsPerSample[0]) TiffThrowHelper.ThrowNotSupported("The number of samples in the TIFF BitsPerSample entry is not supported.");
{
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;
}
}
} }
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; break;
@ -149,27 +146,18 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
case TiffPhotometricInterpretation.Rgb: case TiffPhotometricInterpretation.Rgb:
{ {
if (options.BitsPerSample.Length == 3) if (options.BitsPerSample.Bits().Length != 3)
{ {
if (options.PlanarConfiguration == TiffPlanarConfiguration.Chunky) TiffThrowHelper.ThrowNotSupported("The number of samples in the TIFF BitsPerSample entry is not supported.");
{ }
if (options.BitsPerSample[0] == 8 && options.BitsPerSample[1] == 8 && options.BitsPerSample[2] == 8)
{ if (options.PlanarConfiguration == TiffPlanarConfiguration.Chunky)
options.ColorType = TiffColorType.Rgb888; {
} options.ColorType = options.BitsPerSample == TiffBitsPerSample.Rgb888 ? TiffColorType.Rgb888 : TiffColorType.Rgb;
else
{
options.ColorType = TiffColorType.Rgb;
}
}
else
{
options.ColorType = TiffColorType.RgbPlanar;
}
} }
else else
{ {
TiffThrowHelper.ThrowNotSupported("The number of samples in the TIFF BitsPerSample entry is not supported."); options.ColorType = TiffColorType.RgbPlanar;
} }
break; break;
@ -180,21 +168,12 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
options.ColorMap = entries.ColorMap; options.ColorMap = entries.ColorMap;
if (options.ColorMap != null) if (options.ColorMap != null)
{ {
if (options.BitsPerSample.Length == 1) if (options.BitsPerSample.Bits().Length != 1)
{
switch (options.BitsPerSample[0])
{
default:
{
options.ColorType = TiffColorType.PaletteColor;
break;
}
}
}
else
{ {
TiffThrowHelper.ThrowNotSupported("The number of samples in the TIFF BitsPerSample entry is not supported."); TiffThrowHelper.ThrowNotSupported("The number of samples in the TIFF BitsPerSample entry is not supported.");
} }
options.ColorType = TiffColorType.PaletteColor;
} }
else else
{ {
@ -206,7 +185,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Tiff
default: 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; break;

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

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

Loading…
Cancel
Save