Browse Source

Add 1,2, and 4 bit grayscale

af/merge-core
James Jackson-South 8 years ago
parent
commit
c5e5f4734c
  1. 71
      src/ImageSharp/Formats/Png/PngEncoderCore.cs

71
src/ImageSharp/Formats/Png/PngEncoderCore.cs

@ -3,7 +3,9 @@
using System; using System;
using System.Buffers.Binary; using System.Buffers.Binary;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Advanced;
@ -23,6 +25,18 @@ namespace SixLabors.ImageSharp.Formats.Png
/// </summary> /// </summary>
internal sealed class PngEncoderCore : IDisposable internal sealed class PngEncoderCore : IDisposable
{ {
/// <summary>
/// The dictionary of available color types.
/// </summary>
private static readonly Dictionary<PngColorType, byte[]> ColorTypes = new Dictionary<PngColorType, byte[]>()
{
[PngColorType.Grayscale] = new byte[] { 1, 2, 4, 8, 16 },
[PngColorType.Rgb] = new byte[] { 8, 16 },
[PngColorType.Palette] = new byte[] { 1, 2, 4, 8 },
[PngColorType.GrayscaleWithAlpha] = new byte[] { 8, 16 },
[PngColorType.RgbWithAlpha] = new byte[] { 8, 16 }
};
/// <summary> /// <summary>
/// Used the manage memory allocations. /// Used the manage memory allocations.
/// </summary> /// </summary>
@ -198,19 +212,27 @@ namespace SixLabors.ImageSharp.Formats.Png
this.pngBitDepth = this.pngBitDepth ?? pngMetaData.BitDepth; this.pngBitDepth = this.pngBitDepth ?? pngMetaData.BitDepth;
this.use16Bit = this.pngBitDepth.Equals(PngBitDepth.Bit16); this.use16Bit = this.pngBitDepth.Equals(PngBitDepth.Bit16);
// Ensure we are not allowing impossible combinations.
if (!ColorTypes.ContainsKey(this.pngColorType.Value))
{
throw new NotSupportedException("Color type is not supported or not valid.");
}
stream.Write(PngConstants.HeaderBytes, 0, PngConstants.HeaderBytes.Length); stream.Write(PngConstants.HeaderBytes, 0, PngConstants.HeaderBytes.Length);
QuantizedFrame<TPixel> quantized = null; QuantizedFrame<TPixel> quantized = null;
if (this.pngColorType == PngColorType.Palette) if (this.pngColorType == PngColorType.Palette)
{ {
byte bits = (byte)Math.Min(8u, (short)this.pngBitDepth); byte bits = (byte)this.pngBitDepth;
if (!ColorTypes[this.pngColorType.Value].Contains(bits))
{
throw new NotSupportedException("Bit depth is not supported or not valid.");
}
// Use the metadata to determine what quantization depth to use if no quantizer has been set. // Use the metadata to determine what quantization depth to use if no quantizer has been set.
if (this.quantizer == null) if (this.quantizer == null)
{ {
bits = (byte)Math.Min(8u, (short)this.pngBitDepth); this.quantizer = new WuQuantizer(ImageMaths.GetColorCountForBitDepth(bits));
int colorSize = ImageMaths.GetColorCountForBitDepth(bits);
this.quantizer = new WuQuantizer(colorSize);
} }
// Create quantized frame returning the palette and set the bit depth. // Create quantized frame returning the palette and set the bit depth.
@ -234,8 +256,11 @@ namespace SixLabors.ImageSharp.Formats.Png
} }
else else
{ {
// TODO: Get the correct bit depth for grayscale images. this.bitDepth = (byte)this.pngBitDepth;
this.bitDepth = (byte)(this.use16Bit ? 16 : 8); if (!ColorTypes[this.pngColorType.Value].Contains(this.bitDepth))
{
throw new NotSupportedException("Bit depth is not supported or not valid.");
}
} }
this.bytesPerPixel = this.CalculateBytesPerPixel(); this.bytesPerPixel = this.CalculateBytesPerPixel();
@ -295,9 +320,7 @@ namespace SixLabors.ImageSharp.Formats.Png
if (this.pngColorType.Equals(PngColorType.Grayscale)) if (this.pngColorType.Equals(PngColorType.Grayscale))
{ {
// TODO: Realistically we should support 1, 2, 4, 8, and 16 bit grayscale images. // TODO: Research and add support for grayscale plus tRNS
// we currently do the other types via palette. Maybe RC as I don't understand how the data is packed yet
// for 1, 2, and 4 bit grayscale images.
if (this.use16Bit) if (this.use16Bit)
{ {
// 16 bit grayscale // 16 bit grayscale
@ -311,12 +334,32 @@ namespace SixLabors.ImageSharp.Formats.Png
} }
else else
{ {
// 8 bit grayscale if (this.bitDepth == 8)
Rgb24 rgb = default;
for (int x = 0; x < rowSpan.Length; x++)
{ {
rowSpan[x].ToRgb24(ref rgb); // 8 bit grayscale
rawScanlineSpan[x] = (byte)((RX * rgb.R) + (GX * rgb.G) + (BX * rgb.B)); Rgb24 rgb = default;
for (int x = 0; x < rowSpan.Length; x++)
{
rowSpan[x].ToRgb24(ref rgb);
rawScanlineSpan[x] = (byte)((RX * rgb.R) + (GX * rgb.G) + (BX * rgb.B));
}
}
else
{
// 1, 2, and 4 bit grayscale
using (IManagedByteBuffer temp = this.memoryAllocator.AllocateManagedByteBuffer(rowSpan.Length, AllocationOptions.Clean))
{
int scaleFactor = 255 / (ImageMaths.GetColorCountForBitDepth(this.bitDepth) - 1);
Span<byte> tempSpan = temp.GetSpan();
Rgb24 rgb = default;
for (int x = 0; x < rowSpan.Length; x++)
{
rowSpan[x].ToRgb24(ref rgb);
float luminance = ((RX * rgb.R) + (GX * rgb.G) + (BX * rgb.B)) / scaleFactor;
tempSpan[x] = (byte)luminance;
this.ScaleDownFrom8BitArray(tempSpan, rawScanlineSpan, this.bitDepth);
}
}
} }
} }
} }

Loading…
Cancel
Save