mirror of https://github.com/SixLabors/ImageSharp
Browse Source
Better organisation, handles all color types + maintains image quality. Former-commit-id: 27d65b60f5e468e9678d0f9dd0314700e658036e Former-commit-id: 1ed0afaccc0218f60cdc749a83725c9f9693ab4a Former-commit-id: d20d7fd77362ad6cbb570b46105f2817df99c85cpull/1/head
7 changed files with 265 additions and 491 deletions
@ -1,76 +0,0 @@ |
|||||
// <copyright file="GrayscaleReader.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageProcessorCore.Formats |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Color reader for reading grayscale colors from a png file.
|
|
||||
/// </summary>
|
|
||||
internal sealed class GrayscaleReader : IColorReader |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Whether t also read the alpha channel.
|
|
||||
/// </summary>
|
|
||||
private readonly bool useAlpha; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The current row.
|
|
||||
/// </summary>
|
|
||||
private int row; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Initializes a new instance of the <see cref="GrayscaleReader"/> class.
|
|
||||
/// </summary>
|
|
||||
/// <param name="useAlpha">
|
|
||||
/// If set to <c>true</c> the color reader will also read the
|
|
||||
/// alpha channel from the scanline.
|
|
||||
/// </param>
|
|
||||
public GrayscaleReader(bool useAlpha) |
|
||||
{ |
|
||||
this.useAlpha = useAlpha; |
|
||||
} |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public void ReadScanline<T, TP>(byte[] scanline, T[] pixels, PngHeader header) |
|
||||
where T : IPackedVector<TP> |
|
||||
where TP : struct |
|
||||
{ |
|
||||
int offset; |
|
||||
|
|
||||
byte[] newScanline = scanline.ToArrayByBitsLength(header.BitDepth); |
|
||||
|
|
||||
// Stored in r-> g-> b-> a order.
|
|
||||
if (this.useAlpha) |
|
||||
{ |
|
||||
for (int x = 0; x < header.Width / 2; x++) |
|
||||
{ |
|
||||
offset = (this.row * header.Width) + x; |
|
||||
|
|
||||
byte rgb = newScanline[x * 2]; |
|
||||
byte a = newScanline[(x * 2) + 1]; |
|
||||
|
|
||||
T color = default(T); |
|
||||
color.PackFromBytes(rgb, rgb, rgb, a); |
|
||||
pixels[offset] = color; |
|
||||
} |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
for (int x = 0; x < header.Width; x++) |
|
||||
{ |
|
||||
offset = (this.row * header.Width) + x; |
|
||||
byte rgb = newScanline[x]; |
|
||||
|
|
||||
T color = default(T); |
|
||||
color.PackFromBytes(rgb, rgb, rgb, 255); |
|
||||
|
|
||||
pixels[offset] = color; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
this.row++; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,29 +0,0 @@ |
|||||
// <copyright file="IColorReader.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageProcessorCore.Formats |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Encapsulates methods for color readers, which are responsible for reading
|
|
||||
/// different color formats from a png file.
|
|
||||
/// </summary>
|
|
||||
public interface IColorReader |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Reads the specified scanline.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="T">The pixel format.</typeparam>
|
|
||||
/// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam>
|
|
||||
/// <param name="scanline">The scanline.</param>
|
|
||||
/// <param name="pixels">The pixels to read the image row to.</param>
|
|
||||
/// <param name="header">
|
|
||||
/// The header, which contains information about the png file, like
|
|
||||
/// the width of the image and the height.
|
|
||||
/// </param>
|
|
||||
void ReadScanline<T, TP>(byte[] scanline, T[] pixels, PngHeader header) |
|
||||
where T : IPackedVector<TP> |
|
||||
where TP : struct; |
|
||||
} |
|
||||
} |
|
||||
@ -1,95 +0,0 @@ |
|||||
// <copyright file="PaletteIndexReader.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageProcessorCore.Formats |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// A color reader for reading palette indices from the png file.
|
|
||||
/// </summary>
|
|
||||
internal sealed class PaletteIndexReader : IColorReader |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// The palette.
|
|
||||
/// </summary>
|
|
||||
private readonly byte[] palette; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The alpha palette.
|
|
||||
/// </summary>
|
|
||||
private readonly byte[] paletteAlpha; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The current row.
|
|
||||
/// </summary>
|
|
||||
private int row; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Initializes a new instance of the <see cref="PaletteIndexReader"/> class.
|
|
||||
/// </summary>
|
|
||||
/// <param name="palette">The palette as simple byte array. It will contains 3 values for each
|
|
||||
/// color, which represents the red-, the green- and the blue channel.</param>
|
|
||||
/// <param name="paletteAlpha">The alpha palette. Can be null, if the image does not have an
|
|
||||
/// alpha channel and can contain less entries than the number of colors in the palette.</param>
|
|
||||
public PaletteIndexReader(byte[] palette, byte[] paletteAlpha) |
|
||||
{ |
|
||||
this.palette = palette; |
|
||||
this.paletteAlpha = paletteAlpha; |
|
||||
} |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public void ReadScanline<T, TP>(byte[] scanline, T[] pixels, PngHeader header) |
|
||||
where T : IPackedVector<TP> |
|
||||
where TP : struct |
|
||||
{ |
|
||||
byte[] newScanline = scanline.ToArrayByBitsLength(header.BitDepth); |
|
||||
int offset, index; |
|
||||
|
|
||||
if (this.paletteAlpha != null && this.paletteAlpha.Length > 0) |
|
||||
{ |
|
||||
// If the alpha palette is not null and does one or
|
|
||||
// more entries, this means, that the image contains and alpha
|
|
||||
// channel and we should try to read it.
|
|
||||
for (int i = 0; i < header.Width; i++) |
|
||||
{ |
|
||||
index = newScanline[i]; |
|
||||
|
|
||||
offset = (this.row * header.Width) + i; |
|
||||
int pixelOffset = index * 3; |
|
||||
|
|
||||
byte r = this.palette[pixelOffset]; |
|
||||
byte g = this.palette[pixelOffset + 1]; |
|
||||
byte b = this.palette[pixelOffset + 2]; |
|
||||
byte a = this.paletteAlpha.Length > index |
|
||||
? this.paletteAlpha[index] |
|
||||
: (byte)255; |
|
||||
|
|
||||
T color = default(T); |
|
||||
color.PackFromBytes(r, g, b, a); |
|
||||
pixels[offset] = color; |
|
||||
} |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
for (int i = 0; i < header.Width; i++) |
|
||||
{ |
|
||||
index = newScanline[i]; |
|
||||
|
|
||||
offset = (this.row * header.Width) + i; |
|
||||
int pixelOffset = index * 3; |
|
||||
|
|
||||
byte r = this.palette[pixelOffset]; |
|
||||
byte g = this.palette[pixelOffset + 1]; |
|
||||
byte b = this.palette[pixelOffset + 2]; |
|
||||
|
|
||||
T color = default(T); |
|
||||
color.PackFromBytes(r, g, b, 255); |
|
||||
pixels[offset] = color; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
this.row++; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,61 +0,0 @@ |
|||||
// <copyright file="PngColorTypeInformation.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageProcessorCore.Formats |
|
||||
{ |
|
||||
using System; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Contains information that are required when loading a png with a specific color type.
|
|
||||
/// </summary>
|
|
||||
internal sealed class PngColorTypeInformation |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Initializes a new instance of the <see cref="PngColorTypeInformation"/> class with
|
|
||||
/// the scanline factory, the function to create the color reader and the supported bit depths.
|
|
||||
/// </summary>
|
|
||||
/// <param name="scanlineFactor">The scanline factor.</param>
|
|
||||
/// <param name="supportedBitDepths">The supported bit depths.</param>
|
|
||||
/// <param name="scanlineReaderFactory">The factory to create the color reader.</param>
|
|
||||
public PngColorTypeInformation(int scanlineFactor, int[] supportedBitDepths, Func<byte[], byte[], IColorReader> scanlineReaderFactory) |
|
||||
{ |
|
||||
this.ChannelsPerColor = scanlineFactor; |
|
||||
this.ScanlineReaderFactory = scanlineReaderFactory; |
|
||||
this.SupportedBitDepths = supportedBitDepths; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets an array with the bit depths that are supported for the color type
|
|
||||
/// where this object is created for.
|
|
||||
/// </summary>
|
|
||||
/// <value>The supported bit depths that can be used in combination with this color type.</value>
|
|
||||
public int[] SupportedBitDepths { get; private set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets a function that is used the create the color reader for the color type where
|
|
||||
/// this object is created for.
|
|
||||
/// </summary>
|
|
||||
/// <value>The factory function to create the color type.</value>
|
|
||||
public Func<byte[], byte[], IColorReader> ScanlineReaderFactory { get; private set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets a factor that is used when iterating through the scan lines.
|
|
||||
/// </summary>
|
|
||||
/// <value>The scanline factor.</value>
|
|
||||
public int ChannelsPerColor { get; private set; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Creates the color reader for the color type where this object is create for.
|
|
||||
/// </summary>
|
|
||||
/// <param name="palette">The palette of the image. Can be null when no palette is used.</param>
|
|
||||
/// <param name="paletteAlpha">The alpha palette of the image. Can be null when
|
|
||||
/// no palette is used for the image or when the image has no alpha.</param>
|
|
||||
/// <returns>The color reader for the image.</returns>
|
|
||||
public IColorReader CreateColorReader(byte[] palette, byte[] paletteAlpha) |
|
||||
{ |
|
||||
return this.ScanlineReaderFactory(palette, paletteAlpha); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,81 +0,0 @@ |
|||||
// <copyright file="TrueColorReader.cs" company="James Jackson-South">
|
|
||||
// Copyright (c) James Jackson-South and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
// </copyright>
|
|
||||
|
|
||||
namespace ImageProcessorCore.Formats |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Color reader for reading true colors from a png file. Only colors
|
|
||||
/// with 24 or 32 bit (3 or 4 bytes) per pixel are supported at the moment.
|
|
||||
/// </summary>
|
|
||||
internal sealed class TrueColorReader : IColorReader |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Whether t also read the alpha channel.
|
|
||||
/// </summary>
|
|
||||
private readonly bool useAlpha; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// The current row.
|
|
||||
/// </summary>
|
|
||||
private int row; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Initializes a new instance of the <see cref="TrueColorReader"/> class.
|
|
||||
/// </summary>
|
|
||||
/// <param name="useAlpha">if set to <c>true</c> the color reader will also read the
|
|
||||
/// alpha channel from the scanline.</param>
|
|
||||
public TrueColorReader(bool useAlpha) |
|
||||
{ |
|
||||
this.useAlpha = useAlpha; |
|
||||
} |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
public void ReadScanline<T, TP>(byte[] scanline, T[] pixels, PngHeader header) |
|
||||
where T : IPackedVector<TP> |
|
||||
where TP : struct |
|
||||
{ |
|
||||
int offset; |
|
||||
|
|
||||
byte[] newScanline = scanline.ToArrayByBitsLength(header.BitDepth); |
|
||||
|
|
||||
if (this.useAlpha) |
|
||||
{ |
|
||||
for (int x = 0; x < newScanline.Length; x += 4) |
|
||||
{ |
|
||||
offset = (this.row * header.Width) + (x >> 2); |
|
||||
|
|
||||
// We want to convert to premultiplied alpha here.
|
|
||||
byte r = newScanline[x]; |
|
||||
byte g = newScanline[x + 1]; |
|
||||
byte b = newScanline[x + 2]; |
|
||||
byte a = newScanline[x + 3]; |
|
||||
|
|
||||
T color = default(T); |
|
||||
color.PackFromBytes(r, g, b, a); |
|
||||
|
|
||||
pixels[offset] = color; |
|
||||
} |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
for (int x = 0; x < newScanline.Length / 3; x++) |
|
||||
{ |
|
||||
offset = (this.row * header.Width) + x; |
|
||||
int pixelOffset = x * 3; |
|
||||
|
|
||||
byte r = newScanline[pixelOffset]; |
|
||||
byte g = newScanline[pixelOffset + 1]; |
|
||||
byte b = newScanline[pixelOffset + 2]; |
|
||||
|
|
||||
T color = default(T); |
|
||||
color.PackFromBytes(r, g, b, 255); |
|
||||
pixels[offset] = color; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
this.row++; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
Loading…
Reference in new issue