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>rrggbb</Value>
<Value>rrggbbaa</Value>
<Value>scanline</Value>
<Value>scanlines</Value>
<Value>png's</Value>
</CollectionProperty>
</GlobalSettings>
<Analyzers>

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

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

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

@ -2,7 +2,6 @@
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageProcessorCore.Formats
{
using System;
@ -27,7 +26,7 @@ namespace ImageProcessorCore.Formats
/// <summary>
/// Contains the raw pixel data from the image.
/// </summary>
byte[] pixelData;
private byte[] pixelData;
/// <summary>
/// The image width.
@ -60,7 +59,7 @@ namespace ImageProcessorCore.Formats
public PngColorType PngColorType { get; set; }
/// <summary>
/// The compression level 1-9.
/// Gets or sets the compression level 1-9.
/// <remarks>Defaults to 6.</remarks>
/// </summary>
public int CompressionLevel { get; set; } = 6;
@ -80,7 +79,7 @@ namespace ImageProcessorCore.Formats
public float Gamma { get; set; } = 2.2F;
/// <summary>
/// The quantizer for reducing the color count.
/// Gets or sets the quantizer for reducing the color count.
/// </summary>
public IQuantizer Quantizer { get; set; }
@ -134,7 +133,7 @@ namespace ImageProcessorCore.Formats
// Set correct bit depth.
this.bitDepth = this.Quality <= 256
? (byte)(ImageMaths.GetBitsNeededForColorDepth(this.Quality).Clamp(1, 8))
? (byte)ImageMaths.GetBitsNeededForColorDepth(this.Quality).Clamp(1, 8)
: (byte)8;
// 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.bytesPerPixel = CalculateBytesPerPixel();
this.bytesPerPixel = this.CalculateBytesPerPixel();
PngHeader header = new PngHeader
{
@ -183,6 +182,48 @@ namespace ImageProcessorCore.Formats
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>
/// Collects the indexed pixel data.
/// </summary>
@ -197,7 +238,7 @@ namespace ImageProcessorCore.Formats
{
// Quatize the image and get the pixels
QuantizedImage<TColor, TPacked> quantized = this.WritePaletteChunk(stream, header, image);
pixelData = quantized.Pixels;
this.pixelData = quantized.Pixels;
}
/// <summary>
@ -291,12 +332,12 @@ namespace ImageProcessorCore.Formats
{
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[] filteredScanline = GetOptimalFilteredScanline(rawScanline, previousScanline, this.bytesPerPixel);
byte[] rawScanline = this.GetRawScanline(y);
byte[] filteredScanline = this.GetOptimalFilteredScanline(rawScanline, previousScanline, this.bytesPerPixel);
filteredScanlines.Add(filteredScanline);
@ -320,22 +361,22 @@ namespace ImageProcessorCore.Formats
/// <param name="rawScanline">The raw scanline</param>
/// <param name="previousScanline">The previous scanline</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)
{
List<Tuple<byte[], int>> candidates = new List<Tuple<byte[], int>>();
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);
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);
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);
candidates.Add(new Tuple<byte[], int>(paeth, CalculateTotalVariation(paeth)));
candidates.Add(new Tuple<byte[], int>(paeth, this.CalculateTotalVariation(paeth)));
int lowestTotalVariation = int.MaxValue;
int lowestTotalVariationIndex = 0;
@ -354,7 +395,7 @@ namespace ImageProcessorCore.Formats
/// <summary>
/// Calculates the total variation of given byte array. Total variation is the sum of the absolute values of
/// neighbour differences.
/// neighbor differences.
/// </summary>
/// <param name="input">The scanline bytes</param>
/// <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>
/// Writes the header chunk to the stream.
/// </summary>
@ -482,6 +481,7 @@ namespace ImageProcessorCore.Formats
/// <param name="stream">The <see cref="Stream"/> containing image data.</param>
/// <param name="header">The <see cref="PngHeader"/>.</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)
where TColor : IPackedVector<TPacked>
where TPacked : struct
@ -600,6 +600,7 @@ namespace ImageProcessorCore.Formats
/// <summary>
/// Writes the pixel information to the stream.
/// </summary>
/// <param name="stream">The stream.</param>
private void WriteDataChunks(Stream stream)
{
byte[] data = this.EncodePixelData();

Loading…
Cancel
Save