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

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

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