Browse Source

Refactor Pbm option enums

pull/1851/head
Ynse Hoornenborg 4 years ago
parent
commit
f6301d4b67
  1. 12
      src/ImageSharp/Formats/Pbm/BinaryDecoder.cs
  2. 8
      src/ImageSharp/Formats/Pbm/BinaryEncoder.cs
  3. 4
      src/ImageSharp/Formats/Pbm/IPbmEncoderOptions.cs
  4. 26
      src/ImageSharp/Formats/Pbm/PbmComponentType.cs
  5. 34
      src/ImageSharp/Formats/Pbm/PbmDecoderCore.cs
  6. 4
      src/ImageSharp/Formats/Pbm/PbmEncoder.cs
  7. 16
      src/ImageSharp/Formats/Pbm/PbmEncoderCore.cs
  8. 9
      src/ImageSharp/Formats/Pbm/PbmMetadata.cs
  9. 8
      src/ImageSharp/Formats/Pbm/PlainDecoder.cs
  10. 8
      src/ImageSharp/Formats/Pbm/PlainEncoder.cs
  11. 50
      tests/ImageSharp.Tests/Formats/Pbm/PbmDecoderTests.cs
  12. 20
      tests/ImageSharp.Tests/Formats/Pbm/PbmMetadataTests.cs

12
src/ImageSharp/Formats/Pbm/BinaryDecoder.cs

@ -14,8 +14,8 @@ namespace SixLabors.ImageSharp.Formats.Pbm
/// </summary>
internal class BinaryDecoder
{
private static L8 white = new L8(255);
private static L8 black = new L8(0);
private static L8 white = new(255);
private static L8 black = new(0);
/// <summary>
/// Decode the specified pixels.
@ -25,16 +25,16 @@ namespace SixLabors.ImageSharp.Formats.Pbm
/// <param name="pixels">The pixel array to encode into.</param>
/// <param name="stream">The stream to read the data from.</param>
/// <param name="colorType">The ColorType to decode.</param>
/// <param name="maxPixelValue">The maximum expected pixel value</param>
/// <param name="componentType">Data type of the pixles components.</param>
/// <exception cref="InvalidImageContentException">
/// Thrown if an invalid combination of setting is requested.
/// </exception>
public static void Process<TPixel>(Configuration configuration, Buffer2D<TPixel> pixels, BufferedReadStream stream, PbmColorType colorType, int maxPixelValue)
public static void Process<TPixel>(Configuration configuration, Buffer2D<TPixel> pixels, BufferedReadStream stream, PbmColorType colorType, PbmComponentType componentType)
where TPixel : unmanaged, IPixel<TPixel>
{
if (colorType == PbmColorType.Grayscale)
{
if (maxPixelValue < 256)
if (componentType == PbmComponentType.Byte)
{
ProcessGrayscale(configuration, pixels, stream);
}
@ -45,7 +45,7 @@ namespace SixLabors.ImageSharp.Formats.Pbm
}
else if (colorType == PbmColorType.Rgb)
{
if (maxPixelValue < 256)
if (componentType == PbmComponentType.Byte)
{
ProcessRgb(configuration, pixels, stream);
}

8
src/ImageSharp/Formats/Pbm/BinaryEncoder.cs

@ -22,16 +22,16 @@ namespace SixLabors.ImageSharp.Formats.Pbm
/// <param name="stream">The bytestream to write to.</param>
/// <param name="image">The input image.</param>
/// <param name="colorType">The ColorType to use.</param>
/// <param name="maxPixelValue">The maximum expected pixel value</param>
/// <param name="componentType">Data type of the pixles components.</param>
/// <exception cref="InvalidImageContentException">
/// Thrown if an invalid combination of setting is requested.
/// </exception>
public static void WritePixels<TPixel>(Configuration configuration, Stream stream, ImageFrame<TPixel> image, PbmColorType colorType, int maxPixelValue)
public static void WritePixels<TPixel>(Configuration configuration, Stream stream, ImageFrame<TPixel> image, PbmColorType colorType, PbmComponentType componentType)
where TPixel : unmanaged, IPixel<TPixel>
{
if (colorType == PbmColorType.Grayscale)
{
if (maxPixelValue < 256)
if (componentType == PbmComponentType.Byte)
{
WriteGrayscale(configuration, stream, image);
}
@ -42,7 +42,7 @@ namespace SixLabors.ImageSharp.Formats.Pbm
}
else if (colorType == PbmColorType.Rgb)
{
if (maxPixelValue < 256)
if (componentType == PbmComponentType.Byte)
{
WriteRgb(configuration, stream, image);
}

4
src/ImageSharp/Formats/Pbm/IPbmEncoderOptions.cs

@ -19,8 +19,8 @@ namespace SixLabors.ImageSharp.Formats.Pbm
PbmColorType? ColorType { get; }
/// <summary>
/// Gets the maximum pixel value, per component.
/// Gets the Data Type of the pixel components.
/// </summary>
int? MaxPixelValue { get; }
PbmComponentType? ComponentType { get; }
}
}

26
src/ImageSharp/Formats/Pbm/PbmComponentType.cs

@ -0,0 +1,26 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.Formats.Pbm
{
/// <summary>
/// The data type of the components of the pixels.
/// </summary>
public enum PbmComponentType : byte
{
/// <summary>
/// Single bit per pixel, exclusively for <see cref="PbmColorType.BlackAndWhite"/>.
/// </summary>
Bit = 0,
/// <summary>
/// 8 bits unsigned integer per component.
/// </summary>
Byte = 1,
/// <summary>
/// 16 bits unsigned integer per component.
/// </summary>
Short = 2
}
}

34
src/ImageSharp/Formats/Pbm/PbmDecoderCore.cs

@ -16,6 +16,8 @@ namespace SixLabors.ImageSharp.Formats.Pbm
/// </summary>
internal sealed class PbmDecoderCore : IImageDecoderInternals
{
private int maxPixelValue;
/// <summary>
/// Initializes a new instance of the <see cref="PbmDecoderCore" /> class.
/// </summary>
@ -36,9 +38,9 @@ namespace SixLabors.ImageSharp.Formats.Pbm
public Size PixelSize { get; private set; }
/// <summary>
/// Gets the maximum pixel value
/// Gets the component data type
/// </summary>
public int MaxPixelValue { get; private set; }
public PbmComponentType ComponentType { get; private set; }
/// <summary>
/// Gets the Encoding of pixels
@ -53,7 +55,7 @@ namespace SixLabors.ImageSharp.Formats.Pbm
/// <inheritdoc/>
Size IImageDecoderInternals.Dimensions => this.PixelSize;
private bool NeedsUpscaling => this.ColorType != PbmColorType.BlackAndWhite && this.MaxPixelValue is not 255 and not 65535;
private bool NeedsUpscaling => this.ColorType != PbmColorType.BlackAndWhite && this.maxPixelValue is not 255 and not 65535;
/// <inheritdoc/>
public Image<TPixel> Decode<TPixel>(BufferedReadStream stream, CancellationToken cancellationToken)
@ -79,7 +81,8 @@ namespace SixLabors.ImageSharp.Formats.Pbm
{
this.ProcessHeader(stream);
int bitsPerPixel = this.MaxPixelValue > 255 ? 16 : 8;
// BlackAndWhite pixels are encoded into a byte.
int bitsPerPixel = this.ComponentType == PbmComponentType.Short ? 16 : 8;
return new ImageInfo(new PixelTypeInfo(bitsPerPixel), this.PixelSize.Width, this.PixelSize.Height, this.Metadata);
}
@ -143,12 +146,21 @@ namespace SixLabors.ImageSharp.Formats.Pbm
stream.SkipWhitespaceAndComments();
if (this.ColorType != PbmColorType.BlackAndWhite)
{
this.MaxPixelValue = stream.ReadDecimal();
this.maxPixelValue = stream.ReadDecimal();
if (this.maxPixelValue > 255)
{
this.ComponentType = PbmComponentType.Short;
}
else
{
this.ComponentType = PbmComponentType.Byte;
}
stream.SkipWhitespaceAndComments();
}
else
{
this.MaxPixelValue = 1;
this.ComponentType = PbmComponentType.Bit;
}
this.PixelSize = new Size(width, height);
@ -156,7 +168,7 @@ namespace SixLabors.ImageSharp.Formats.Pbm
PbmMetadata meta = this.Metadata.GetPbmMetadata();
meta.Encoding = this.Encoding;
meta.ColorType = this.ColorType;
meta.MaxPixelValue = this.MaxPixelValue;
meta.ComponentType = this.ComponentType;
}
private void ProcessPixels<TPixel>(BufferedReadStream stream, Buffer2D<TPixel> pixels)
@ -164,19 +176,19 @@ namespace SixLabors.ImageSharp.Formats.Pbm
{
if (this.Encoding == PbmEncoding.Binary)
{
BinaryDecoder.Process(this.Configuration, pixels, stream, this.ColorType, this.MaxPixelValue);
BinaryDecoder.Process(this.Configuration, pixels, stream, this.ColorType, this.ComponentType);
}
else
{
PlainDecoder.Process(this.Configuration, pixels, stream, this.ColorType, this.MaxPixelValue);
PlainDecoder.Process(this.Configuration, pixels, stream, this.ColorType, this.ComponentType);
}
}
private void ProcessUpscaling<TPixel>(Image<TPixel> image)
where TPixel : unmanaged, IPixel<TPixel>
{
int maxAllocationValue = (this.MaxPixelValue > 255) ? 65535 : 255;
float factor = maxAllocationValue / this.MaxPixelValue;
int maxAllocationValue = this.ComponentType == PbmComponentType.Short ? 65535 : 255;
float factor = maxAllocationValue / this.maxPixelValue;
image.Mutate(x => x.Brightness(factor));
}
}

4
src/ImageSharp/Formats/Pbm/PbmEncoder.cs

@ -46,9 +46,9 @@ namespace SixLabors.ImageSharp.Formats.Pbm
public PbmColorType? ColorType { get; set; }
/// <summary>
/// Gets or sets the maximum pixel value, per component.
/// Gets or sets the data type of the pixels components.
/// </summary>
public int? MaxPixelValue { get; set; }
public PbmComponentType? ComponentType { get; set; }
/// <inheritdoc/>
public void Encode<TPixel>(Image<TPixel> image, Stream stream)

16
src/ImageSharp/Formats/Pbm/PbmEncoderCore.cs

@ -42,7 +42,7 @@ namespace SixLabors.ImageSharp.Formats.Pbm
/// <summary>
/// Gets the maximum pixel value, per component.
/// </summary>
private int maxPixelValue;
private PbmComponentType componentType;
/// <summary>
/// Initializes a new instance of the <see cref="PbmEncoderCore"/> class.
@ -87,8 +87,11 @@ namespace SixLabors.ImageSharp.Formats.Pbm
this.colorType = this.options.ColorType ?? metadata.ColorType;
if (this.colorType != PbmColorType.BlackAndWhite)
{
this.maxPixelValue = this.options.MaxPixelValue ?? metadata.MaxPixelValue;
this.maxPixelValue = Math.Max(this.maxPixelValue, PbmConstants.MaxLength);
this.componentType = this.options.ComponentType ?? metadata.ComponentType;
}
else
{
this.componentType = PbmComponentType.Bit;
}
}
@ -151,7 +154,8 @@ namespace SixLabors.ImageSharp.Formats.Pbm
if (this.colorType != PbmColorType.BlackAndWhite)
{
Utf8Formatter.TryFormat(this.maxPixelValue, buffer.Slice(written), out bytesWritten);
int maxPixelValue = this.componentType == PbmComponentType.Short ? 65535 : 255;
Utf8Formatter.TryFormat(maxPixelValue, buffer.Slice(written), out bytesWritten);
written += bytesWritten;
buffer[written++] = NewLine;
}
@ -172,11 +176,11 @@ namespace SixLabors.ImageSharp.Formats.Pbm
{
if (this.encoding == PbmEncoding.Plain)
{
PlainEncoder.WritePixels(this.configuration, stream, image, this.colorType, this.maxPixelValue);
PlainEncoder.WritePixels(this.configuration, stream, image, this.colorType, this.componentType);
}
else
{
BinaryEncoder.WritePixels(this.configuration, stream, image, this.colorType, this.maxPixelValue);
BinaryEncoder.WritePixels(this.configuration, stream, image, this.colorType, this.componentType);
}
}
}

9
src/ImageSharp/Formats/Pbm/PbmMetadata.cs

@ -11,7 +11,8 @@ namespace SixLabors.ImageSharp.Formats.Pbm
/// <summary>
/// Initializes a new instance of the <see cref="PbmMetadata"/> class.
/// </summary>
public PbmMetadata() => this.MaxPixelValue = this.ColorType == PbmColorType.BlackAndWhite ? 1 : 255;
public PbmMetadata() =>
this.ComponentType = this.ColorType == PbmColorType.BlackAndWhite ? PbmComponentType.Bit : PbmComponentType.Byte;
/// <summary>
/// Initializes a new instance of the <see cref="PbmMetadata"/> class.
@ -21,7 +22,7 @@ namespace SixLabors.ImageSharp.Formats.Pbm
{
this.Encoding = other.Encoding;
this.ColorType = other.ColorType;
this.MaxPixelValue = other.MaxPixelValue;
this.ComponentType = other.ComponentType;
}
/// <summary>
@ -35,9 +36,9 @@ namespace SixLabors.ImageSharp.Formats.Pbm
public PbmColorType ColorType { get; set; } = PbmColorType.Grayscale;
/// <summary>
/// Gets or sets the maximum pixel value.
/// Gets or sets the data type of the pixel components.
/// </summary>
public int MaxPixelValue { get; set; }
public PbmComponentType ComponentType { get; set; }
/// <inheritdoc/>
public IDeepCloneable DeepClone() => new PbmMetadata(this);

8
src/ImageSharp/Formats/Pbm/PlainDecoder.cs

@ -25,13 +25,13 @@ namespace SixLabors.ImageSharp.Formats.Pbm
/// <param name="pixels">The pixel array to encode into.</param>
/// <param name="stream">The stream to read the data from.</param>
/// <param name="colorType">The ColorType to decode.</param>
/// <param name="maxPixelValue">The maximum expected pixel value</param>
public static void Process<TPixel>(Configuration configuration, Buffer2D<TPixel> pixels, BufferedReadStream stream, PbmColorType colorType, int maxPixelValue)
/// <param name="componentType">Data type of the pixles components.</param>
public static void Process<TPixel>(Configuration configuration, Buffer2D<TPixel> pixels, BufferedReadStream stream, PbmColorType colorType, PbmComponentType componentType)
where TPixel : unmanaged, IPixel<TPixel>
{
if (colorType == PbmColorType.Grayscale)
{
if (maxPixelValue < 256)
if (componentType == PbmComponentType.Byte)
{
ProcessGrayscale(configuration, pixels, stream);
}
@ -42,7 +42,7 @@ namespace SixLabors.ImageSharp.Formats.Pbm
}
else if (colorType == PbmColorType.Rgb)
{
if (maxPixelValue < 256)
if (componentType == PbmComponentType.Byte)
{
ProcessRgb(configuration, pixels, stream);
}

8
src/ImageSharp/Formats/Pbm/PlainEncoder.cs

@ -36,13 +36,13 @@ namespace SixLabors.ImageSharp.Formats.Pbm
/// <param name="stream">The bytestream to write to.</param>
/// <param name="image">The input image.</param>
/// <param name="colorType">The ColorType to use.</param>
/// <param name="maxPixelValue">The maximum expected pixel value</param>
public static void WritePixels<TPixel>(Configuration configuration, Stream stream, ImageFrame<TPixel> image, PbmColorType colorType, int maxPixelValue)
/// <param name="componentType">Data type of the pixles components.</param>
public static void WritePixels<TPixel>(Configuration configuration, Stream stream, ImageFrame<TPixel> image, PbmColorType colorType, PbmComponentType componentType)
where TPixel : unmanaged, IPixel<TPixel>
{
if (colorType == PbmColorType.Grayscale)
{
if (maxPixelValue < 256)
if (componentType == PbmComponentType.Byte)
{
WriteGrayscale(configuration, stream, image);
}
@ -53,7 +53,7 @@ namespace SixLabors.ImageSharp.Formats.Pbm
}
else if (colorType == PbmColorType.Rgb)
{
if (maxPixelValue < 256)
if (componentType == PbmComponentType.Byte)
{
WriteRgb(configuration, stream, image);
}

50
tests/ImageSharp.Tests/Formats/Pbm/PbmDecoderTests.cs

@ -14,16 +14,16 @@ namespace SixLabors.ImageSharp.Tests.Formats.Pbm
public class PbmDecoderTests
{
[Theory]
[InlineData(BlackAndWhitePlain, PbmColorType.BlackAndWhite)]
[InlineData(BlackAndWhiteBinary, PbmColorType.BlackAndWhite)]
[InlineData(GrayscalePlain, PbmColorType.Grayscale)]
[InlineData(GrayscalePlainMagick, PbmColorType.Grayscale)]
[InlineData(GrayscaleBinary, PbmColorType.Grayscale)]
[InlineData(GrayscaleBinaryWide, PbmColorType.Grayscale)]
[InlineData(RgbPlain, PbmColorType.Rgb)]
[InlineData(RgbPlainMagick, PbmColorType.Rgb)]
[InlineData(RgbBinary, PbmColorType.Rgb)]
public void ImageLoadCanDecode(string imagePath, PbmColorType expectedColorType)
[InlineData(BlackAndWhitePlain, PbmColorType.BlackAndWhite, PbmComponentType.Bit)]
[InlineData(BlackAndWhiteBinary, PbmColorType.BlackAndWhite, PbmComponentType.Bit)]
[InlineData(GrayscalePlain, PbmColorType.Grayscale, PbmComponentType.Byte)]
[InlineData(GrayscalePlainMagick, PbmColorType.Grayscale, PbmComponentType.Byte)]
[InlineData(GrayscaleBinary, PbmColorType.Grayscale, PbmComponentType.Byte)]
[InlineData(GrayscaleBinaryWide, PbmColorType.Grayscale, PbmComponentType.Short)]
[InlineData(RgbPlain, PbmColorType.Rgb, PbmComponentType.Byte)]
[InlineData(RgbPlainMagick, PbmColorType.Rgb, PbmComponentType.Byte)]
[InlineData(RgbBinary, PbmColorType.Rgb, PbmComponentType.Byte)]
public void ImageLoadCanDecode(string imagePath, PbmColorType expectedColorType, PbmComponentType expectedComponentType)
{
// Arrange
var testFile = TestFile.Create(imagePath);
@ -34,9 +34,10 @@ namespace SixLabors.ImageSharp.Tests.Formats.Pbm
// Assert
Assert.NotNull(image);
PbmMetadata bitmapMetadata = image.Metadata.GetPbmMetadata();
Assert.NotNull(bitmapMetadata);
Assert.Equal(expectedColorType, bitmapMetadata.ColorType);
PbmMetadata metadata = image.Metadata.GetPbmMetadata();
Assert.NotNull(metadata);
Assert.Equal(expectedColorType, metadata.ColorType);
Assert.Equal(expectedComponentType, metadata.ComponentType);
}
[Theory]
@ -77,21 +78,22 @@ namespace SixLabors.ImageSharp.Tests.Formats.Pbm
}
[Theory]
[WithFile(BlackAndWhitePlain, PixelTypes.L8, true)]
[WithFile(BlackAndWhiteBinary, PixelTypes.L8, true)]
[WithFile(GrayscalePlain, PixelTypes.L8, true)]
[WithFile(GrayscalePlainNormalized, PixelTypes.L8, true)]
[WithFile(GrayscaleBinary, PixelTypes.L8, true)]
[WithFile(GrayscaleBinaryWide, PixelTypes.L16, true)]
[WithFile(RgbPlain, PixelTypes.Rgb24, false)]
[WithFile(RgbPlainNormalized, PixelTypes.Rgb24, false)]
[WithFile(RgbBinary, PixelTypes.Rgb24, false)]
public void DecodeReferenceImage<TPixel>(TestImageProvider<TPixel> provider, bool isGrayscale)
[WithFile(BlackAndWhitePlain, PixelTypes.L8, "pbm")]
[WithFile(BlackAndWhiteBinary, PixelTypes.L8, "pbm")]
[WithFile(GrayscalePlain, PixelTypes.L8, "pgm")]
[WithFile(GrayscalePlainNormalized, PixelTypes.L8, "pgm")]
[WithFile(GrayscaleBinary, PixelTypes.L8, "pgm")]
[WithFile(GrayscaleBinaryWide, PixelTypes.L16, "pgm")]
[WithFile(RgbPlain, PixelTypes.Rgb24, "ppm")]
[WithFile(RgbPlainNormalized, PixelTypes.Rgb24, "ppm")]
[WithFile(RgbBinary, PixelTypes.Rgb24, "ppm")]
public void DecodeReferenceImage<TPixel>(TestImageProvider<TPixel> provider, string extension)
where TPixel : unmanaged, IPixel<TPixel>
{
using Image<TPixel> image = provider.GetImage();
image.DebugSave(provider);
image.DebugSave(provider, extension: extension);
bool isGrayscale = extension is "pgm" or "pbm";
image.CompareToReferenceOutput(provider, grayscale: isGrayscale);
}
}

20
tests/ImageSharp.Tests/Formats/Pbm/PbmMetadataTests.cs

@ -20,8 +20,10 @@ namespace SixLabors.ImageSharp.Tests.Formats.Pbm
var clone = (PbmMetadata)meta.DeepClone();
clone.ColorType = PbmColorType.Rgb;
clone.ComponentType = PbmComponentType.Short;
Assert.False(meta.ColorType.Equals(clone.ColorType));
Assert.False(meta.ComponentType.Equals(clone.ComponentType));
}
[Theory]
@ -63,14 +65,14 @@ namespace SixLabors.ImageSharp.Tests.Formats.Pbm
}
[Theory]
[InlineData(BlackAndWhitePlain, 1)]
[InlineData(BlackAndWhiteBinary, 1)]
[InlineData(GrayscaleBinary, 255)]
[InlineData(GrayscaleBinaryWide, 65535)]
[InlineData(GrayscalePlain, 15)]
[InlineData(RgbBinary, 255)]
[InlineData(RgbPlain, 15)]
public void Identify_DetectsCorrectMaxPixelValue(string imagePath, int expectedMaxPixelValue)
[InlineData(BlackAndWhitePlain, PbmComponentType.Bit)]
[InlineData(BlackAndWhiteBinary, PbmComponentType.Bit)]
[InlineData(GrayscaleBinary, PbmComponentType.Byte)]
[InlineData(GrayscaleBinaryWide, PbmComponentType.Short)]
[InlineData(GrayscalePlain, PbmComponentType.Byte)]
[InlineData(RgbBinary, PbmComponentType.Byte)]
[InlineData(RgbPlain, PbmComponentType.Byte)]
public void Identify_DetectsCorrectComponentType(string imagePath, PbmComponentType expectedComponentType)
{
var testFile = TestFile.Create(imagePath);
using var stream = new MemoryStream(testFile.Bytes, false);
@ -78,7 +80,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Pbm
Assert.NotNull(imageInfo);
PbmMetadata bitmapMetadata = imageInfo.Metadata.GetPbmMetadata();
Assert.NotNull(bitmapMetadata);
Assert.Equal(expectedMaxPixelValue, bitmapMetadata.MaxPixelValue);
Assert.Equal(expectedComponentType, bitmapMetadata.ComponentType);
}
}
}

Loading…
Cancel
Save