|
|
|
@ -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; |
|
|
|
} |
|
|
|
} |
|
|
|
|