Browse Source

Port Pbm decoder

pull/2180/head
James Jackson-South 4 years ago
parent
commit
d453922250
  1. 23
      src/ImageSharp/Formats/Gif/IGifDecoderOptions.cs
  2. 24
      src/ImageSharp/Formats/Pbm/PbmDecoder.cs
  3. 105
      src/ImageSharp/Formats/Pbm/PbmDecoderCore.cs
  4. 14
      src/ImageSharp/Formats/Pbm/PbmDecoderOptions.cs

23
src/ImageSharp/Formats/Gif/IGifDecoderOptions.cs

@ -1,23 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Metadata;
namespace SixLabors.ImageSharp.Formats.Gif
{
/// <summary>
/// Decoder for generating an image out of a gif encoded stream.
/// </summary>
internal interface IGifDecoderOptions
{
/// <summary>
/// Gets a value indicating whether the metadata should be ignored when the image is being decoded.
/// </summary>
bool IgnoreMetadata { get; }
/// <summary>
/// Gets the decoding mode for multi-frame images.
/// </summary>
FrameDecodingMode DecodingMode { get; }
}
}

24
src/ImageSharp/Formats/Pbm/PbmDecoder.cs

@ -26,29 +26,29 @@ namespace SixLabors.ImageSharp.Formats.Pbm
/// </list>
/// The specification of these images is found at <seealso href="http://netpbm.sourceforge.net/doc/pnm.html"/>.
/// </summary>
public sealed class PbmDecoder : IImageDecoder, IImageInfoDetector
public sealed class PbmDecoder : ImageDecoder<PbmDecoderOptions>
{
/// <inheritdoc/>
public Image<TPixel> Decode<TPixel>(Configuration configuration, Stream stream, CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel<TPixel>
/// <inheritdoc />
public override Image<TPixel> DecodeSpecialized<TPixel>(PbmDecoderOptions options, Stream stream, CancellationToken cancellationToken)
{
Guard.NotNull(stream, nameof(stream));
PbmDecoderCore decoder = new(options);
Image<TPixel> image = decoder.Decode<PbmDecoderOptions, TPixel>(options.GeneralOptions.Configuration, stream, cancellationToken);
Resize(options.GeneralOptions, image);
var decoder = new PbmDecoderCore(configuration);
return decoder.Decode<TPixel>(configuration, stream, cancellationToken);
return image;
}
/// <inheritdoc />
public Image Decode(Configuration configuration, Stream stream, CancellationToken cancellationToken)
=> this.Decode<Rgb24>(configuration, stream, cancellationToken);
public override Image DecodeSpecialized(PbmDecoderOptions options, Stream stream, CancellationToken cancellationToken)
=> this.DecodeSpecialized<Rgb24>(options, stream, cancellationToken);
/// <inheritdoc/>
public IImageInfo Identify(Configuration configuration, Stream stream, CancellationToken cancellationToken)
public override IImageInfo IdentifySpecialized(PbmDecoderOptions options, Stream stream, CancellationToken cancellationToken)
{
Guard.NotNull(stream, nameof(stream));
var decoder = new PbmDecoderCore(configuration);
return decoder.Identify(configuration, stream, cancellationToken);
return new PbmDecoderCore(options).Identify(options.GeneralOptions.Configuration, stream, cancellationToken);
}
}
}

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

@ -14,48 +14,55 @@ namespace SixLabors.ImageSharp.Formats.Pbm
/// <summary>
/// Performs the PBM decoding operation.
/// </summary>
internal sealed class PbmDecoderCore : IImageDecoderInternals
internal sealed class PbmDecoderCore : IImageDecoderInternals<PbmDecoderOptions>
{
private int maxPixelValue;
/// <summary>
/// Initializes a new instance of the <see cref="PbmDecoderCore" /> class.
/// The general configuration.
/// </summary>
/// <param name="configuration">The configuration.</param>
public PbmDecoderCore(Configuration configuration) => this.Configuration = configuration ?? Configuration.Default;
private readonly Configuration configuration;
/// <inheritdoc />
public Configuration Configuration { get; }
/// <summary>
/// The colortype to use
/// </summary>
private PbmColorType colorType;
/// <summary>
/// Gets the colortype to use
/// The size of the pixel array
/// </summary>
public PbmColorType ColorType { get; private set; }
private Size pixelSize;
/// <summary>
/// Gets the size of the pixel array
/// The component data type
/// </summary>
public Size PixelSize { get; private set; }
private PbmComponentType componentType;
/// <summary>
/// Gets the component data type
/// The Encoding of pixels
/// </summary>
public PbmComponentType ComponentType { get; private set; }
private PbmEncoding encoding;
/// <summary>
/// Gets the Encoding of pixels
/// The <see cref="ImageMetadata"/> decoded by this decoder instance.
/// </summary>
public PbmEncoding Encoding { get; private set; }
private ImageMetadata metadata;
/// <summary>
/// Gets the <see cref="ImageMetadata"/> decoded by this decoder instance.
/// Initializes a new instance of the <see cref="PbmDecoderCore" /> class.
/// </summary>
public ImageMetadata Metadata { get; private set; }
/// <param name="options">The decoder options.</param>
public PbmDecoderCore(PbmDecoderOptions options)
{
this.Options = options;
this.configuration = options.GeneralOptions.Configuration;
}
/// <inheritdoc/>
Size IImageDecoderInternals.Dimensions => this.PixelSize;
public PbmDecoderOptions Options { get; }
private bool NeedsUpscaling => this.ColorType != PbmColorType.BlackAndWhite && this.maxPixelValue is not 255 and not 65535;
/// <inheritdoc/>
public Size Dimensions => this.pixelSize;
/// <inheritdoc/>
public Image<TPixel> Decode<TPixel>(BufferedReadStream stream, CancellationToken cancellationToken)
@ -63,12 +70,12 @@ namespace SixLabors.ImageSharp.Formats.Pbm
{
this.ProcessHeader(stream);
var image = new Image<TPixel>(this.Configuration, this.PixelSize.Width, this.PixelSize.Height, this.Metadata);
var image = new Image<TPixel>(this.configuration, this.pixelSize.Width, this.pixelSize.Height, this.metadata);
Buffer2D<TPixel> pixels = image.GetRootFramePixelBuffer();
this.ProcessPixels(stream, pixels);
if (this.NeedsUpscaling)
if (this.NeedsUpscaling())
{
this.ProcessUpscaling(image);
}
@ -82,8 +89,8 @@ namespace SixLabors.ImageSharp.Formats.Pbm
this.ProcessHeader(stream);
// 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);
int bitsPerPixel = this.componentType == PbmComponentType.Short ? 16 : 8;
return new ImageInfo(new PixelTypeInfo(bitsPerPixel), this.pixelSize.Width, this.pixelSize.Height, this.metadata);
}
/// <summary>
@ -104,33 +111,33 @@ namespace SixLabors.ImageSharp.Formats.Pbm
{
case '1':
// Plain PBM format: 1 component per pixel, boolean value ('0' or '1').
this.ColorType = PbmColorType.BlackAndWhite;
this.Encoding = PbmEncoding.Plain;
this.colorType = PbmColorType.BlackAndWhite;
this.encoding = PbmEncoding.Plain;
break;
case '2':
// Plain PGM format: 1 component per pixel, in decimal text.
this.ColorType = PbmColorType.Grayscale;
this.Encoding = PbmEncoding.Plain;
this.colorType = PbmColorType.Grayscale;
this.encoding = PbmEncoding.Plain;
break;
case '3':
// Plain PPM format: 3 components per pixel, in decimal text.
this.ColorType = PbmColorType.Rgb;
this.Encoding = PbmEncoding.Plain;
this.colorType = PbmColorType.Rgb;
this.encoding = PbmEncoding.Plain;
break;
case '4':
// Binary PBM format: 1 component per pixel, 8 pixels per byte.
this.ColorType = PbmColorType.BlackAndWhite;
this.Encoding = PbmEncoding.Binary;
this.colorType = PbmColorType.BlackAndWhite;
this.encoding = PbmEncoding.Binary;
break;
case '5':
// Binary PGM format: 1 components per pixel, in binary integers.
this.ColorType = PbmColorType.Grayscale;
this.Encoding = PbmEncoding.Binary;
this.colorType = PbmColorType.Grayscale;
this.encoding = PbmEncoding.Binary;
break;
case '6':
// Binary PPM format: 3 components per pixel, in binary integers.
this.ColorType = PbmColorType.Rgb;
this.Encoding = PbmEncoding.Binary;
this.colorType = PbmColorType.Rgb;
this.encoding = PbmEncoding.Binary;
break;
case '7':
// PAM image: sequence of images.
@ -144,52 +151,54 @@ namespace SixLabors.ImageSharp.Formats.Pbm
stream.SkipWhitespaceAndComments();
int height = stream.ReadDecimal();
stream.SkipWhitespaceAndComments();
if (this.ColorType != PbmColorType.BlackAndWhite)
if (this.colorType != PbmColorType.BlackAndWhite)
{
this.maxPixelValue = stream.ReadDecimal();
if (this.maxPixelValue > 255)
{
this.ComponentType = PbmComponentType.Short;
this.componentType = PbmComponentType.Short;
}
else
{
this.ComponentType = PbmComponentType.Byte;
this.componentType = PbmComponentType.Byte;
}
stream.SkipWhitespaceAndComments();
}
else
{
this.ComponentType = PbmComponentType.Bit;
this.componentType = PbmComponentType.Bit;
}
this.PixelSize = new Size(width, height);
this.Metadata = new ImageMetadata();
PbmMetadata meta = this.Metadata.GetPbmMetadata();
meta.Encoding = this.Encoding;
meta.ColorType = this.ColorType;
meta.ComponentType = this.ComponentType;
this.pixelSize = new Size(width, height);
this.metadata = new ImageMetadata();
PbmMetadata meta = this.metadata.GetPbmMetadata();
meta.Encoding = this.encoding;
meta.ColorType = this.colorType;
meta.ComponentType = this.componentType;
}
private void ProcessPixels<TPixel>(BufferedReadStream stream, Buffer2D<TPixel> pixels)
where TPixel : unmanaged, IPixel<TPixel>
{
if (this.Encoding == PbmEncoding.Binary)
if (this.encoding == PbmEncoding.Binary)
{
BinaryDecoder.Process(this.Configuration, pixels, stream, this.ColorType, this.ComponentType);
BinaryDecoder.Process(this.configuration, pixels, stream, this.colorType, this.componentType);
}
else
{
PlainDecoder.Process(this.Configuration, pixels, stream, this.ColorType, this.ComponentType);
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.ComponentType == PbmComponentType.Short ? 65535 : 255;
int maxAllocationValue = this.componentType == PbmComponentType.Short ? 65535 : 255;
float factor = maxAllocationValue / this.maxPixelValue;
image.Mutate(x => x.Brightness(factor));
}
private bool NeedsUpscaling() => this.colorType != PbmColorType.BlackAndWhite && this.maxPixelValue is not 255 and not 65535;
}
}

14
src/ImageSharp/Formats/Pbm/PbmDecoderOptions.cs

@ -0,0 +1,14 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.Formats.Pbm
{
/// <summary>
/// Configuration options for decoding Pbm images.
/// </summary>
public sealed class PbmDecoderOptions : ISpecializedDecoderOptions
{
/// <inheritdoc/>
public DecoderOptions GeneralOptions { get; set; } = new();
}
}
Loading…
Cancel
Save