Browse Source

Png stylecop

Former-commit-id: 7d13b3c396b75143108bb9e5df6b03bbc0085095
Former-commit-id: 40f802aea39d038f8908e50c364fe161b4978b44
Former-commit-id: af2b3ed36a98b84eea71484582b718dea2f240cb
pull/1/head
James Jackson-South 10 years ago
parent
commit
436a105af7
  1. 3
      Settings.StyleCop
  2. 73
      src/ImageProcessorCore/Formats/Png/PngDecoderCore.cs
  3. 119
      src/ImageProcessorCore/Formats/Png/PngEncoderCore.cs

3
Settings.StyleCop

@ -16,6 +16,9 @@
<Value>Scharr</Value> <Value>Scharr</Value>
<Value>rrggbb</Value> <Value>rrggbb</Value>
<Value>rrggbbaa</Value> <Value>rrggbbaa</Value>
<Value>scanline</Value>
<Value>scanlines</Value>
<Value>png's</Value>
</CollectionProperty> </CollectionProperty>
</GlobalSettings> </GlobalSettings>
<Analyzers> <Analyzers>

73
src/ImageProcessorCore/Formats/Png/PngDecoderCore.cs

@ -2,15 +2,13 @@
// Copyright (c) James Jackson-South and contributors. // Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
using System.Numerics;
namespace ImageProcessorCore.Formats namespace ImageProcessorCore.Formats
{ {
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Numerics;
using System.Text; using System.Text;
/// <summary> /// <summary>
@ -18,9 +16,9 @@ namespace ImageProcessorCore.Formats
/// </summary> /// </summary>
internal class PngDecoderCore internal class PngDecoderCore
{ {
///// <summary> /// <summary>
///// The dictionary of available color types. /// The dictionary of available color types.
///// </summary> /// </summary>
private static readonly Dictionary<int, byte[]> ColorTypes = new Dictionary<int, byte[]>(); private static readonly Dictionary<int, byte[]> ColorTypes = new Dictionary<int, byte[]>();
/// <summary> /// <summary>
@ -49,20 +47,15 @@ namespace ImageProcessorCore.Formats
private int bytesPerScanline; private int bytesPerScanline;
/// <summary> /// <summary>
/// The palette containing color information for indexed pngs /// The palette containing color information for indexed png's
/// </summary> /// </summary>
private byte[] palette; private byte[] palette;
/// <summary> /// <summary>
/// The palette containing alpha channel color information for indexed pngs /// The palette containing alpha channel color information for indexed png's
/// </summary> /// </summary>
private byte[] paletteAlpha; private byte[] paletteAlpha;
/// <summary>
/// Gets or sets the png color type
/// </summary>
public PngColorType PngColorType { get; set; }
/// <summary> /// <summary>
/// Initializes static members of the <see cref="PngDecoderCore"/> class. /// Initializes static members of the <see cref="PngDecoderCore"/> class.
/// </summary> /// </summary>
@ -79,6 +72,11 @@ namespace ImageProcessorCore.Formats
ColorTypes.Add((int)PngColorType.RgbWithAlpha, new byte[] { 8 }); ColorTypes.Add((int)PngColorType.RgbWithAlpha, new byte[] { 8 });
} }
/// <summary>
/// Gets or sets the png color type
/// </summary>
public PngColorType PngColorType { get; set; }
/// <summary> /// <summary>
/// Decodes the stream to the image. /// Decodes the stream to the image.
/// </summary> /// </summary>
@ -237,7 +235,7 @@ namespace ImageProcessorCore.Formats
this.bytesPerSample = 1; this.bytesPerSample = 1;
if (this.header.BitDepth >= 8) if (this.header.BitDepth >= 8)
{ {
this.bytesPerSample = (this.header.BitDepth) / 8; this.bytesPerSample = this.header.BitDepth / 8;
} }
dataStream.Position = 0; dataStream.Position = 0;
@ -249,7 +247,7 @@ namespace ImageProcessorCore.Formats
decompressedStream.Flush(); decompressedStream.Flush();
byte[] decompressedBytes = decompressedStream.ToArray(); byte[] decompressedBytes = decompressedStream.ToArray();
DecodePixelData<TColor, TPacked>(decompressedBytes, pixels); this.DecodePixelData<TColor, TPacked>(decompressedBytes, pixels);
} }
} }
} }
@ -284,7 +282,7 @@ namespace ImageProcessorCore.Formats
case FilterType.Sub: case FilterType.Sub:
defilteredScanline = SubFilter.Decode(scanline, bytesPerPixel); defilteredScanline = SubFilter.Decode(scanline, this.bytesPerPixel);
break; break;
@ -296,13 +294,13 @@ namespace ImageProcessorCore.Formats
case FilterType.Average: case FilterType.Average:
defilteredScanline = AverageFilter.Decode(scanline, previousScanline, bytesPerPixel); defilteredScanline = AverageFilter.Decode(scanline, previousScanline, this.bytesPerPixel);
break; break;
case FilterType.Paeth: case FilterType.Paeth:
defilteredScanline = PaethFilter.Decode(scanline, previousScanline, bytesPerPixel); defilteredScanline = PaethFilter.Decode(scanline, previousScanline, this.bytesPerPixel);
break; break;
@ -311,16 +309,16 @@ namespace ImageProcessorCore.Formats
} }
previousScanline = defilteredScanline; previousScanline = defilteredScanline;
ProcessDefilteredScanline<TColor, TPacked>(defilteredScanline, y, pixels); this.ProcessDefilteredScanline<TColor, TPacked>(defilteredScanline, y, pixels);
} }
} }
/// <summary> /// <summary>
/// Processes the defiltered scanline filling the image pixel data /// Processes the de-filtered scanline filling the image pixel data
/// </summary> /// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam> /// <typeparam name="TColor">The pixel format.</typeparam>
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam> /// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
/// <param name="defilteredScanline"></param> /// <param name="defilteredScanline">The de-filtered scanline</param>
/// <param name="row">The current image row.</param> /// <param name="row">The current image row.</param>
/// <param name="pixels">The image pixels</param> /// <param name="pixels">The image pixels</param>
private void ProcessDefilteredScanline<TColor, TPacked>(byte[] defilteredScanline, int row, TColor[] pixels) private void ProcessDefilteredScanline<TColor, TPacked>(byte[] defilteredScanline, int row, TColor[] pixels)
@ -333,7 +331,7 @@ namespace ImageProcessorCore.Formats
for (int x = 0; x < this.header.Width; x++) for (int x = 0; x < this.header.Width; x++)
{ {
int offset = 1 + (x * bytesPerPixel); int offset = 1 + (x * this.bytesPerPixel);
byte intensity = defilteredScanline[offset]; byte intensity = defilteredScanline[offset];
@ -348,10 +346,10 @@ namespace ImageProcessorCore.Formats
for (int x = 0; x < this.header.Width; x++) for (int x = 0; x < this.header.Width; x++)
{ {
int offset = 1 + (x * bytesPerPixel); int offset = 1 + (x * this.bytesPerPixel);
byte intensity = defilteredScanline[offset]; byte intensity = defilteredScanline[offset];
byte alpha = defilteredScanline[offset + bytesPerSample]; byte alpha = defilteredScanline[offset + this.bytesPerSample];
TColor color = default(TColor); TColor color = default(TColor);
color.PackFromVector4(new Vector4(intensity, intensity, intensity, alpha) / 255F); color.PackFromVector4(new Vector4(intensity, intensity, intensity, alpha) / 255F);
@ -362,16 +360,16 @@ namespace ImageProcessorCore.Formats
case PngColorType.Palette: case PngColorType.Palette:
byte[] newScanline = defilteredScanline.ToArrayByBitsLength(header.BitDepth); byte[] newScanline = defilteredScanline.ToArrayByBitsLength(this.header.BitDepth);
if (this.paletteAlpha != null && this.paletteAlpha.Length > 0) if (this.paletteAlpha != null && this.paletteAlpha.Length > 0)
{ {
// If the alpha palette is not null and has one or more entries, this means, that the image contains an alpha // If the alpha palette is not null and has one or more entries, this means, that the image contains an alpha
// channel and we should try to read it. // channel and we should try to read it.
for (int i = 0; i < header.Width; i++) for (int i = 0; i < this.header.Width; i++)
{ {
int index = newScanline[i]; int index = newScanline[i];
int offset = (row * header.Width) + i; int offset = (row * this.header.Width) + i;
int pixelOffset = index * 3; int pixelOffset = index * 3;
byte a = this.paletteAlpha.Length > index ? this.paletteAlpha[index] : (byte)255; byte a = this.paletteAlpha.Length > index ? this.paletteAlpha[index] : (byte)255;
@ -389,10 +387,10 @@ namespace ImageProcessorCore.Formats
} }
else else
{ {
for (int i = 0; i < header.Width; i++) for (int i = 0; i < this.header.Width; i++)
{ {
int index = newScanline[i]; int index = newScanline[i];
int offset = (row * header.Width) + i; int offset = (row * this.header.Width) + i;
int pixelOffset = index * 3; int pixelOffset = index * 3;
byte r = this.palette[pixelOffset]; byte r = this.palette[pixelOffset];
@ -411,11 +409,11 @@ namespace ImageProcessorCore.Formats
for (int x = 0; x < this.header.Width; x++) for (int x = 0; x < this.header.Width; x++)
{ {
int offset = 1 + (x * bytesPerPixel); int offset = 1 + (x * this.bytesPerPixel);
byte r = defilteredScanline[offset]; byte r = defilteredScanline[offset];
byte g = defilteredScanline[offset + bytesPerSample]; byte g = defilteredScanline[offset + this.bytesPerSample];
byte b = defilteredScanline[offset + 2 * bytesPerSample]; byte b = defilteredScanline[offset + (2 * this.bytesPerSample)];
TColor color = default(TColor); TColor color = default(TColor);
color.PackFromVector4(new Vector4(r, g, b, 255) / 255F); color.PackFromVector4(new Vector4(r, g, b, 255) / 255F);
@ -428,12 +426,12 @@ namespace ImageProcessorCore.Formats
for (int x = 0; x < this.header.Width; x++) for (int x = 0; x < this.header.Width; x++)
{ {
int offset = 1 + (x * bytesPerPixel); int offset = 1 + (x * this.bytesPerPixel);
byte r = defilteredScanline[offset]; byte r = defilteredScanline[offset];
byte g = defilteredScanline[offset + bytesPerSample]; byte g = defilteredScanline[offset + this.bytesPerSample];
byte b = defilteredScanline[offset + 2 * bytesPerSample]; byte b = defilteredScanline[offset + (2 * this.bytesPerSample)];
byte a = defilteredScanline[offset + 3 * bytesPerSample]; byte a = defilteredScanline[offset + (3 * this.bytesPerSample)];
TColor color = default(TColor); TColor color = default(TColor);
color.PackFromVector4(new Vector4(r, g, b, a) / 255F); color.PackFromVector4(new Vector4(r, g, b, a) / 255F);
@ -441,9 +439,6 @@ namespace ImageProcessorCore.Formats
} }
break; break;
default:
break;
} }
} }

119
src/ImageProcessorCore/Formats/Png/PngEncoderCore.cs

@ -2,7 +2,6 @@
// Copyright (c) James Jackson-South and contributors. // Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
namespace ImageProcessorCore.Formats namespace ImageProcessorCore.Formats
{ {
using System; using System;
@ -27,7 +26,7 @@ namespace ImageProcessorCore.Formats
/// <summary> /// <summary>
/// Contains the raw pixel data from the image. /// Contains the raw pixel data from the image.
/// </summary> /// </summary>
byte[] pixelData; private byte[] pixelData;
/// <summary> /// <summary>
/// The image width. /// The image width.
@ -60,7 +59,7 @@ namespace ImageProcessorCore.Formats
public PngColorType PngColorType { get; set; } public PngColorType PngColorType { get; set; }
/// <summary> /// <summary>
/// The compression level 1-9. /// Gets or sets the compression level 1-9.
/// <remarks>Defaults to 6.</remarks> /// <remarks>Defaults to 6.</remarks>
/// </summary> /// </summary>
public int CompressionLevel { get; set; } = 6; public int CompressionLevel { get; set; } = 6;
@ -80,7 +79,7 @@ namespace ImageProcessorCore.Formats
public float Gamma { get; set; } = 2.2F; public float Gamma { get; set; } = 2.2F;
/// <summary> /// <summary>
/// The quantizer for reducing the color count. /// Gets or sets the quantizer for reducing the color count.
/// </summary> /// </summary>
public IQuantizer Quantizer { get; set; } public IQuantizer Quantizer { get; set; }
@ -134,7 +133,7 @@ namespace ImageProcessorCore.Formats
// Set correct bit depth. // Set correct bit depth.
this.bitDepth = this.Quality <= 256 this.bitDepth = this.Quality <= 256
? (byte)(ImageMaths.GetBitsNeededForColorDepth(this.Quality).Clamp(1, 8)) ? (byte)ImageMaths.GetBitsNeededForColorDepth(this.Quality).Clamp(1, 8)
: (byte)8; : (byte)8;
// Png only supports in four pixel depths: 1, 2, 4, and 8 bits when using the PLTE chunk // Png only supports in four pixel depths: 1, 2, 4, and 8 bits when using the PLTE chunk
@ -147,7 +146,7 @@ namespace ImageProcessorCore.Formats
this.bitDepth = 8; this.bitDepth = 8;
} }
this.bytesPerPixel = CalculateBytesPerPixel(); this.bytesPerPixel = this.CalculateBytesPerPixel();
PngHeader header = new PngHeader PngHeader header = new PngHeader
{ {
@ -183,6 +182,48 @@ namespace ImageProcessorCore.Formats
stream.Flush(); stream.Flush();
} }
/// <summary>
/// Writes an integer to the byte array.
/// </summary>
/// <param name="data">The <see cref="T:byte[]"/> containing image data.</param>
/// <param name="offset">The amount to offset by.</param>
/// <param name="value">The value to write.</param>
private static void WriteInteger(byte[] data, int offset, int value)
{
byte[] buffer = BitConverter.GetBytes(value);
Array.Reverse(buffer);
Array.Copy(buffer, 0, data, offset, 4);
}
/// <summary>
/// Writes an integer to the stream.
/// </summary>
/// <param name="stream">The <see cref="Stream"/> containing image data.</param>
/// <param name="value">The value to write.</param>
private static void WriteInteger(Stream stream, int value)
{
byte[] buffer = BitConverter.GetBytes(value);
Array.Reverse(buffer);
stream.Write(buffer, 0, 4);
}
/// <summary>
/// Writes an unsigned integer to the stream.
/// </summary>
/// <param name="stream">The <see cref="Stream"/> containing image data.</param>
/// <param name="value">The value to write.</param>
private static void WriteInteger(Stream stream, uint value)
{
byte[] buffer = BitConverter.GetBytes(value);
Array.Reverse(buffer);
stream.Write(buffer, 0, 4);
}
/// <summary> /// <summary>
/// Collects the indexed pixel data. /// Collects the indexed pixel data.
/// </summary> /// </summary>
@ -197,7 +238,7 @@ namespace ImageProcessorCore.Formats
{ {
// Quatize the image and get the pixels // Quatize the image and get the pixels
QuantizedImage<TColor, TPacked> quantized = this.WritePaletteChunk(stream, header, image); QuantizedImage<TColor, TPacked> quantized = this.WritePaletteChunk(stream, header, image);
pixelData = quantized.Pixels; this.pixelData = quantized.Pixels;
} }
/// <summary> /// <summary>
@ -291,12 +332,12 @@ namespace ImageProcessorCore.Formats
{ {
List<byte[]> filteredScanlines = new List<byte[]>(); List<byte[]> filteredScanlines = new List<byte[]>();
byte[] previousScanline = new byte[width * this.bytesPerPixel]; byte[] previousScanline = new byte[this.width * this.bytesPerPixel];
for (int y = 0; y < height; y++) for (int y = 0; y < this.height; y++)
{ {
byte[] rawScanline = GetRawScanline(y); byte[] rawScanline = this.GetRawScanline(y);
byte[] filteredScanline = GetOptimalFilteredScanline(rawScanline, previousScanline, this.bytesPerPixel); byte[] filteredScanline = this.GetOptimalFilteredScanline(rawScanline, previousScanline, this.bytesPerPixel);
filteredScanlines.Add(filteredScanline); filteredScanlines.Add(filteredScanline);
@ -320,22 +361,22 @@ namespace ImageProcessorCore.Formats
/// <param name="rawScanline">The raw scanline</param> /// <param name="rawScanline">The raw scanline</param>
/// <param name="previousScanline">The previous scanline</param> /// <param name="previousScanline">The previous scanline</param>
/// <param name="byteCount">The number of bytes per pixel</param> /// <param name="byteCount">The number of bytes per pixel</param>
/// <returns></returns> /// <returns>The <see cref="T:byte[]"/></returns>
private byte[] GetOptimalFilteredScanline(byte[] rawScanline, byte[] previousScanline, int byteCount) private byte[] GetOptimalFilteredScanline(byte[] rawScanline, byte[] previousScanline, int byteCount)
{ {
List<Tuple<byte[], int>> candidates = new List<Tuple<byte[], int>>(); List<Tuple<byte[], int>> candidates = new List<Tuple<byte[], int>>();
byte[] sub = SubFilter.Encode(rawScanline, byteCount); byte[] sub = SubFilter.Encode(rawScanline, byteCount);
candidates.Add(new Tuple<byte[], int>(sub, CalculateTotalVariation(sub))); candidates.Add(new Tuple<byte[], int>(sub, this.CalculateTotalVariation(sub)));
byte[] up = UpFilter.Encode(rawScanline, previousScanline); byte[] up = UpFilter.Encode(rawScanline, previousScanline);
candidates.Add(new Tuple<byte[], int>(up, CalculateTotalVariation(up))); candidates.Add(new Tuple<byte[], int>(up, this.CalculateTotalVariation(up)));
byte[] average = AverageFilter.Encode(rawScanline, previousScanline, byteCount); byte[] average = AverageFilter.Encode(rawScanline, previousScanline, byteCount);
candidates.Add(new Tuple<byte[], int>(average, CalculateTotalVariation(average))); candidates.Add(new Tuple<byte[], int>(average, this.CalculateTotalVariation(average)));
byte[] paeth = PaethFilter.Encode(rawScanline, previousScanline, byteCount); byte[] paeth = PaethFilter.Encode(rawScanline, previousScanline, byteCount);
candidates.Add(new Tuple<byte[], int>(paeth, CalculateTotalVariation(paeth))); candidates.Add(new Tuple<byte[], int>(paeth, this.CalculateTotalVariation(paeth)));
int lowestTotalVariation = int.MaxValue; int lowestTotalVariation = int.MaxValue;
int lowestTotalVariationIndex = 0; int lowestTotalVariationIndex = 0;
@ -354,7 +395,7 @@ namespace ImageProcessorCore.Formats
/// <summary> /// <summary>
/// Calculates the total variation of given byte array. Total variation is the sum of the absolute values of /// Calculates the total variation of given byte array. Total variation is the sum of the absolute values of
/// neighbour differences. /// neighbor differences.
/// </summary> /// </summary>
/// <param name="input">The scanline bytes</param> /// <param name="input">The scanline bytes</param>
/// <returns>The <see cref="int"/></returns> /// <returns>The <see cref="int"/></returns>
@ -411,48 +452,6 @@ namespace ImageProcessorCore.Formats
} }
} }
/// <summary>
/// Writes an integer to the byte array.
/// </summary>
/// <param name="data">The <see cref="T:byte[]"/> containing image data.</param>
/// <param name="offset">The amount to offset by.</param>
/// <param name="value">The value to write.</param>
private static void WriteInteger(byte[] data, int offset, int value)
{
byte[] buffer = BitConverter.GetBytes(value);
Array.Reverse(buffer);
Array.Copy(buffer, 0, data, offset, 4);
}
/// <summary>
/// Writes an integer to the stream.
/// </summary>
/// <param name="stream">The <see cref="Stream"/> containing image data.</param>
/// <param name="value">The value to write.</param>
private static void WriteInteger(Stream stream, int value)
{
byte[] buffer = BitConverter.GetBytes(value);
Array.Reverse(buffer);
stream.Write(buffer, 0, 4);
}
/// <summary>
/// Writes an unsigned integer to the stream.
/// </summary>
/// <param name="stream">The <see cref="Stream"/> containing image data.</param>
/// <param name="value">The value to write.</param>
private static void WriteInteger(Stream stream, uint value)
{
byte[] buffer = BitConverter.GetBytes(value);
Array.Reverse(buffer);
stream.Write(buffer, 0, 4);
}
/// <summary> /// <summary>
/// Writes the header chunk to the stream. /// Writes the header chunk to the stream.
/// </summary> /// </summary>
@ -482,6 +481,7 @@ namespace ImageProcessorCore.Formats
/// <param name="stream">The <see cref="Stream"/> containing image data.</param> /// <param name="stream">The <see cref="Stream"/> containing image data.</param>
/// <param name="header">The <see cref="PngHeader"/>.</param> /// <param name="header">The <see cref="PngHeader"/>.</param>
/// <param name="image">The image to encode.</param> /// <param name="image">The image to encode.</param>
/// <returns>The <see cref="QuantizedImage{TColor, TPacked}"/></returns>
private QuantizedImage<TColor, TPacked> WritePaletteChunk<TColor, TPacked>(Stream stream, PngHeader header, ImageBase<TColor, TPacked> image) private QuantizedImage<TColor, TPacked> WritePaletteChunk<TColor, TPacked>(Stream stream, PngHeader header, ImageBase<TColor, TPacked> image)
where TColor : IPackedVector<TPacked> where TColor : IPackedVector<TPacked>
where TPacked : struct where TPacked : struct
@ -600,6 +600,7 @@ namespace ImageProcessorCore.Formats
/// <summary> /// <summary>
/// Writes the pixel information to the stream. /// Writes the pixel information to the stream.
/// </summary> /// </summary>
/// <param name="stream">The stream.</param>
private void WriteDataChunks(Stream stream) private void WriteDataChunks(Stream stream)
{ {
byte[] data = this.EncodePixelData(); byte[] data = this.EncodePixelData();

Loading…
Cancel
Save