diff --git a/src/ImageProcessorCore/Common/Helpers/ImageMaths.cs b/src/ImageProcessorCore/Common/Helpers/ImageMaths.cs
index 207ff61a77..662a41f1b2 100644
--- a/src/ImageProcessorCore/Common/Helpers/ImageMaths.cs
+++ b/src/ImageProcessorCore/Common/Helpers/ImageMaths.cs
@@ -19,6 +19,19 @@ namespace ImageProcessorCore
// ReSharper disable once InconsistentNaming
public const float PI = 3.1415926535897931f;
+ ///
+ /// Returns how many bits are required to store the specified number of colors.
+ /// Performs a Log2() on the value.
+ ///
+ /// The number of colors.
+ ///
+ /// The
+ ///
+ public static int GetBitsNeededForColorDepth(int colors)
+ {
+ return (int)Math.Ceiling(Math.Log(colors, 2));
+ }
+
///
/// Implementation of 1D Gaussian G(x) function
///
diff --git a/src/ImageProcessorCore/Formats/Gif/GifEncoder.cs b/src/ImageProcessorCore/Formats/Gif/GifEncoder.cs
index 4dd43f30f7..7a1c81c2b7 100644
--- a/src/ImageProcessorCore/Formats/Gif/GifEncoder.cs
+++ b/src/ImageProcessorCore/Formats/Gif/GifEncoder.cs
@@ -7,8 +7,6 @@ namespace ImageProcessorCore.Formats
{
using System;
using System.IO;
- using System.Linq;
- using System.Threading.Tasks;
using ImageProcessorCore.Quantizers;
@@ -49,308 +47,16 @@ namespace ImageProcessorCore.Formats
}
///
- public void Encode(ImageBase imageBase, Stream stream)
+ public void Encode(ImageBase image, Stream stream)
{
- Guard.NotNull(imageBase, nameof(imageBase));
- Guard.NotNull(stream, nameof(stream));
-
- Image image = (Image)imageBase;
-
- if (this.Quantizer == null)
- {
- this.Quantizer = new OctreeQuantizer { Threshold = this.Threshold };
- }
-
- // Write the header.
- // File Header signature and version.
- this.WriteString(stream, GifConstants.FileType);
- this.WriteString(stream, GifConstants.FileVersion);
-
- // Calculate the quality.
- int quality = this.Quality > 0 ? this.Quality : imageBase.Quality;
- quality = quality > 0 ? quality.Clamp(1, 256) : 256;
-
- // Get the number of bits.
- int bitDepth = this.GetBitsNeededForColorDepth(quality);
-
- // Write the LSD and check to see if we need a global color table.
- // Always true just now.
- this.WriteGlobalLogicalScreenDescriptor(image, stream, bitDepth);
- QuantizedImage quantized = this.WriteColorTable(imageBase, stream, quality, bitDepth);
-
- this.WriteGraphicalControlExtension(imageBase, stream, quantized.TransparentIndex);
- this.WriteImageDescriptor(quantized, quality, stream);
-
- if (image.Frames.Any())
- {
- this.WriteApplicationExtension(stream, image.RepeatCount, image.Frames.Count);
- foreach (ImageFrame frame in image.Frames)
- {
- this.WriteGraphicalControlExtension(frame, stream, quantized.TransparentIndex);
- this.WriteFrameImageDescriptor(frame, stream);
- }
- }
-
- // TODO: Write Comments extension etc
- this.WriteByte(stream, GifConstants.EndIntroducer);
- }
-
- ///
- /// Writes the logical screen descriptor to the stream.
- ///
- /// The image to encode.
- /// The stream to write to.
- /// The bit depth.
- /// The
- private bool WriteGlobalLogicalScreenDescriptor(Image image, Stream stream, int bitDepth)
- {
- Guard.NotNull(image, nameof(image));
- Guard.NotNull(stream, nameof(stream));
-
- GifLogicalScreenDescriptor descriptor = new GifLogicalScreenDescriptor
- {
- Width = (short)image.Width,
- Height = (short)image.Height,
- GlobalColorTableFlag = true,
- GlobalColorTableSize = bitDepth
- };
-
- this.WriteShort(stream, descriptor.Width);
- this.WriteShort(stream, descriptor.Height);
-
- int packed = 0x80 | // 1 : Global color table flag = 1 (GCT used)
- bitDepth - 1 | // 2-4 : color resolution
- 0x00 | // 5 : GCT sort flag = 0
- bitDepth - 1; // 6-8 : GCT size TODO: Check this.
-
- this.WriteByte(stream, packed);
- this.WriteByte(stream, descriptor.BackgroundColorIndex); // Background Color Index
- this.WriteByte(stream, descriptor.PixelAspectRatio); // Pixel aspect ratio. Assume 1:1
-
- return descriptor.GlobalColorTableFlag;
- }
-
- ///
- /// Writes the color table to the stream.
- ///
- /// The to encode.
- /// The stream to write to.
- /// The quality (number of colors) to encode the image to.
- /// The bit depth.
- /// The
- private QuantizedImage WriteColorTable(ImageBase image, Stream stream, int quality, int bitDepth)
- {
- // Quantize the image returning a palette.
- QuantizedImage quantizedImage = this.Quantizer.Quantize(image, quality);
-
- // Grab the palette and write it to the stream.
- Bgra32[] palette = quantizedImage.Palette;
- int pixelCount = palette.Length;
-
- // Get max colors for bit depth.
- int colorTableLength = (int)Math.Pow(2, bitDepth) * 3;
- byte[] colorTable = new byte[colorTableLength];
-
- Parallel.For(0, pixelCount,
- i =>
- {
- int offset = i * 3;
- Bgra32 color = palette[i];
-
- colorTable[offset] = color.R;
- colorTable[offset + 1] = color.G;
- colorTable[offset + 2] = color.B;
- });
-
- stream.Write(colorTable, 0, colorTableLength);
-
- return quantizedImage;
- }
-
- ///
- /// Writes the graphics control extension to the stream.
- ///
- /// The to encode.
- /// The stream to write to.
- /// The index of the color in the color palette to make transparent.
- private void WriteGraphicalControlExtension(ImageBase image, Stream stream, int transparencyIndex)
- {
- // TODO: Check transparency logic.
- bool hasTransparent = transparencyIndex > -1;
- DisposalMethod disposalMethod = hasTransparent
- ? DisposalMethod.RestoreToBackground
- : DisposalMethod.Unspecified;
-
- GifGraphicsControlExtension extension = new GifGraphicsControlExtension()
+ GifEncoderCore encoder = new GifEncoderCore
{
- DisposalMethod = disposalMethod,
- TransparencyFlag = hasTransparent,
- TransparencyIndex = transparencyIndex,
- DelayTime = image.FrameDelay
+ Quality = this.Quality,
+ Quantizer = this.Quantizer,
+ Threshold = this.Threshold
};
- this.WriteByte(stream, GifConstants.ExtensionIntroducer);
- this.WriteByte(stream, GifConstants.GraphicControlLabel);
- this.WriteByte(stream, 4); // Size
-
- int packed = 0 | // 1-3 : Reserved
- (int)extension.DisposalMethod << 2 | // 4-6 : Disposal
- 0 | // 7 : User input - 0 = none
- (extension.TransparencyFlag ? 1 : 0); // 8: Has transparent.
-
- this.WriteByte(stream, packed);
- this.WriteShort(stream, extension.DelayTime);
- this.WriteByte(stream, extension.TransparencyIndex == -1 ? 255 : extension.TransparencyIndex);
- this.WriteByte(stream, GifConstants.Terminator);
- }
-
- ///
- /// Writes the application exstension to the stream.
- ///
- /// The stream to write to.
- /// The animated image repeat count.
- /// Th number of image frames.
- private void WriteApplicationExtension(Stream stream, ushort repeatCount, int frames)
- {
- // Application Extension Header
- if (repeatCount != 1 && frames > 0)
- {
- // 0 means loop indefinitely. count is set as play n + 1 times.
- // TODO: Check this as the correct value might be pulled from the decoder.
- repeatCount = (ushort)Math.Max(0, repeatCount - 1);
- this.WriteByte(stream, GifConstants.ExtensionIntroducer); // NETSCAPE2.0
- this.WriteByte(stream, GifConstants.ApplicationExtensionLabel);
- this.WriteByte(stream, GifConstants.ApplicationBlockSize);
-
- this.WriteString(stream, GifConstants.ApplicationIdentification);
- this.WriteByte(stream, 3); // Application block length
- this.WriteByte(stream, 1); // Data sub-block index (always 1)
- this.WriteShort(stream, repeatCount); // Repeat count for images.
-
- this.WriteByte(stream, GifConstants.Terminator); // Terminator
- }
- }
-
- ///
- /// Writes the image descriptor to the stream.
- ///
- /// The containing indexed pixels.
- /// The quality (number of colors) to encode the image to.
- /// The stream to write to.
- private void WriteImageDescriptor(QuantizedImage image, int quality, Stream stream)
- {
- this.WriteByte(stream, GifConstants.ImageDescriptorLabel); // 2c
- // TODO: Can we capture this?
- this.WriteShort(stream, 0); // Left position
- this.WriteShort(stream, 0); // Top position
- this.WriteShort(stream, image.Width);
- this.WriteShort(stream, image.Height);
-
- // Calculate the quality.
- int bitDepth = this.GetBitsNeededForColorDepth(quality);
-
- // No LCT use GCT.
- this.WriteByte(stream, 0);
-
- // Write the image data.
- this.WriteImageData(image, stream, bitDepth);
- }
-
- ///
- /// Writes the image descriptor to the stream.
- ///
- /// The to be encoded.
- /// The stream to write to.
- private void WriteFrameImageDescriptor(ImageBase image, Stream stream)
- {
- this.WriteByte(stream, GifConstants.ImageDescriptorLabel); // 2c
- // TODO: Can we capture this?
- this.WriteShort(stream, 0); // Left position
- this.WriteShort(stream, 0); // Top position
- this.WriteShort(stream, image.Width);
- this.WriteShort(stream, image.Height);
-
- // Calculate the quality.
- int quality = this.Quality > 0 ? this.Quality : image.Quality;
- quality = quality > 0 ? quality.Clamp(1, 256) : 256;
- int bitDepth = this.GetBitsNeededForColorDepth(quality);
-
- int packed = 0x80 | // 1: Local color table flag = 1 (LCT used)
- 0x00 | // 2: Interlace flag 0
- 0x00 | // 3: Sort flag 0
- 0 | // 4-5: Reserved
- bitDepth - 1;
-
- this.WriteByte(stream, packed);
-
- // Now immediately follow with the color table.
- QuantizedImage quantized = this.WriteColorTable(image, stream, quality, bitDepth);
- this.WriteImageData(quantized, stream, bitDepth);
- }
-
- ///
- /// Writes the image pixel data to the stream.
- ///
- /// The containing indexed pixels.
- /// The stream to write to.
- /// The bit depth of the image.
- private void WriteImageData(QuantizedImage image, Stream stream, int bitDepth)
- {
- byte[] indexedPixels = image.Pixels;
-
- LzwEncoder encoder = new LzwEncoder(indexedPixels, (byte)bitDepth);
- encoder.Encode(stream);
-
- this.WriteByte(stream, GifConstants.Terminator);
- }
-
- ///
- /// Writes a short to the given stream.
- ///
- /// The containing image data.
- /// The value to write.
- private void WriteShort(Stream stream, int value)
- {
- // Leave only one significant byte.
- stream.WriteByte(Convert.ToByte(value & 0xff));
- stream.WriteByte(Convert.ToByte((value >> 8) & 0xff));
- }
-
- ///
- /// Writes a byte to the given stream.
- ///
- /// The containing image data.
- /// The value to write.
- private void WriteByte(Stream stream, int value)
- {
- stream.WriteByte(Convert.ToByte(value));
- }
-
- ///
- /// Writes a string to the given stream.
- ///
- /// The containing image data.
- /// The value to write.
- private void WriteString(Stream stream, string value)
- {
- char[] chars = value.ToCharArray();
- foreach (char c in chars)
- {
- stream.WriteByte((byte)c);
- }
- }
-
- ///
- /// Returns how many bits are required to store the specified number of colors.
- /// Performs a Log2() on the value.
- ///
- /// The number of colors.
- ///
- /// The
- ///
- private int GetBitsNeededForColorDepth(int colors)
- {
- return (int)Math.Ceiling(Math.Log(colors, 2));
+ encoder.Encode(image, stream);
}
}
}
diff --git a/src/ImageProcessorCore/Formats/Gif/GifEncoderCore.cs b/src/ImageProcessorCore/Formats/Gif/GifEncoderCore.cs
new file mode 100644
index 0000000000..19e2f1df99
--- /dev/null
+++ b/src/ImageProcessorCore/Formats/Gif/GifEncoderCore.cs
@@ -0,0 +1,343 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageProcessorCore.Formats
+{
+ using System;
+ using System.IO;
+ using System.Linq;
+ using System.Threading.Tasks;
+
+ using ImageProcessorCore.Quantizers;
+
+ ///
+ /// Performs the gif encoding operation.
+ ///
+ internal sealed class GifEncoderCore
+ {
+ ///
+ /// The number of bits requires to store the image palette.
+ ///
+ private int bitDepth;
+
+ ///
+ /// Gets or sets the quality of output for images.
+ ///
+ /// For gifs the value ranges from 1 to 256.
+ public int Quality { get; set; }
+
+ ///
+ /// Gets or sets the transparency threshold.
+ ///
+ public byte Threshold { get; set; } = 128;
+
+ ///
+ /// The quantizer for reducing the color count.
+ ///
+ public IQuantizer Quantizer { get; set; }
+
+ ///
+ /// Encodes the image to the specified stream from the .
+ ///
+ /// The to encode from.
+ /// The to encode the image data to.
+ public void Encode(ImageBase imageBase, Stream stream)
+ {
+ Guard.NotNull(imageBase, nameof(imageBase));
+ Guard.NotNull(stream, nameof(stream));
+
+ Image image = (Image)imageBase;
+
+ if (this.Quantizer == null)
+ {
+ this.Quantizer = new OctreeQuantizer { Threshold = this.Threshold };
+ }
+
+ // Write the header.
+ // File Header signature and version.
+ this.WriteString(stream, GifConstants.FileType);
+ this.WriteString(stream, GifConstants.FileVersion);
+
+ // Ensure that quality can be set but has a fallback.
+ int quality = this.Quality > 0 ? this.Quality : imageBase.Quality;
+ quality = quality > 0 ? quality.Clamp(1, 256) : 256;
+
+ // Get the number of bits.
+ this.bitDepth = ImageMaths.GetBitsNeededForColorDepth(quality);
+
+ // Write the LSD and check to see if we need a global color table.
+ // Always true just now.
+ this.WriteGlobalLogicalScreenDescriptor(image, stream);
+ QuantizedImage quantized = this.WriteColorTable(imageBase, stream, quality);
+
+ this.WriteGraphicalControlExtension(imageBase, stream, quantized.TransparentIndex);
+ this.WriteImageDescriptor(quantized, quality, stream);
+
+ if (image.Frames.Any())
+ {
+ this.WriteApplicationExtension(stream, image.RepeatCount, image.Frames.Count);
+ foreach (ImageFrame frame in image.Frames)
+ {
+ this.WriteGraphicalControlExtension(frame, stream, quantized.TransparentIndex);
+ this.WriteFrameImageDescriptor(frame, stream);
+ }
+ }
+
+ // TODO: Write Comments extension etc
+ this.WriteByte(stream, GifConstants.EndIntroducer);
+ }
+
+ ///
+ /// Writes the logical screen descriptor to the stream.
+ ///
+ /// The image to encode.
+ /// The stream to write to.
+ /// The
+ private bool WriteGlobalLogicalScreenDescriptor(Image image, Stream stream)
+ {
+ Guard.NotNull(image, nameof(image));
+ Guard.NotNull(stream, nameof(stream));
+
+ GifLogicalScreenDescriptor descriptor = new GifLogicalScreenDescriptor
+ {
+ Width = (short)image.Width,
+ Height = (short)image.Height,
+ GlobalColorTableFlag = true,
+ GlobalColorTableSize = this.bitDepth
+ };
+
+ this.WriteShort(stream, descriptor.Width);
+ this.WriteShort(stream, descriptor.Height);
+
+ int packed = 0x80 | // 1 : Global color table flag = 1 (GCT used)
+ this.bitDepth - 1 | // 2-4 : color resolution
+ 0x00 | // 5 : GCT sort flag = 0
+ this.bitDepth - 1; // 6-8 : GCT size TODO: Check this.
+
+ this.WriteByte(stream, packed);
+ this.WriteByte(stream, descriptor.BackgroundColorIndex); // Background Color Index
+ this.WriteByte(stream, descriptor.PixelAspectRatio); // Pixel aspect ratio. Assume 1:1
+
+ return descriptor.GlobalColorTableFlag;
+ }
+
+ ///
+ /// Writes the color table to the stream.
+ ///
+ /// The to encode.
+ /// The stream to write to.
+ /// The quality (number of colors) to encode the image to.
+ /// The
+ private QuantizedImage WriteColorTable(ImageBase image, Stream stream, int quality)
+ {
+ // Quantize the image returning a palette.
+ QuantizedImage quantizedImage = this.Quantizer.Quantize(image, quality);
+
+ // Grab the palette and write it to the stream.
+ Bgra32[] palette = quantizedImage.Palette;
+ int pixelCount = palette.Length;
+
+ // Get max colors for bit depth.
+ int colorTableLength = (int)Math.Pow(2, this.bitDepth) * 3;
+ byte[] colorTable = new byte[colorTableLength];
+
+ Parallel.For(0, pixelCount,
+ i =>
+ {
+ int offset = i * 3;
+ Bgra32 color = palette[i];
+
+ colorTable[offset] = color.R;
+ colorTable[offset + 1] = color.G;
+ colorTable[offset + 2] = color.B;
+ });
+
+ stream.Write(colorTable, 0, colorTableLength);
+
+ return quantizedImage;
+ }
+
+ ///
+ /// Writes the graphics control extension to the stream.
+ ///
+ /// The to encode.
+ /// The stream to write to.
+ /// The index of the color in the color palette to make transparent.
+ private void WriteGraphicalControlExtension(ImageBase image, Stream stream, int transparencyIndex)
+ {
+ // TODO: Check transparency logic.
+ bool hasTransparent = transparencyIndex > -1;
+ DisposalMethod disposalMethod = hasTransparent
+ ? DisposalMethod.RestoreToBackground
+ : DisposalMethod.Unspecified;
+
+ GifGraphicsControlExtension extension = new GifGraphicsControlExtension()
+ {
+ DisposalMethod = disposalMethod,
+ TransparencyFlag = hasTransparent,
+ TransparencyIndex = transparencyIndex,
+ DelayTime = image.FrameDelay
+ };
+
+ this.WriteByte(stream, GifConstants.ExtensionIntroducer);
+ this.WriteByte(stream, GifConstants.GraphicControlLabel);
+ this.WriteByte(stream, 4); // Size
+
+ int packed = 0 | // 1-3 : Reserved
+ (int)extension.DisposalMethod << 2 | // 4-6 : Disposal
+ 0 | // 7 : User input - 0 = none
+ (extension.TransparencyFlag ? 1 : 0); // 8: Has transparent.
+
+ this.WriteByte(stream, packed);
+ this.WriteShort(stream, extension.DelayTime);
+ this.WriteByte(stream, extension.TransparencyIndex == -1 ? 255 : extension.TransparencyIndex);
+ this.WriteByte(stream, GifConstants.Terminator);
+ }
+
+ ///
+ /// Writes the application exstension to the stream.
+ ///
+ /// The stream to write to.
+ /// The animated image repeat count.
+ /// Th number of image frames.
+ private void WriteApplicationExtension(Stream stream, ushort repeatCount, int frames)
+ {
+ // Application Extension Header
+ if (repeatCount != 1 && frames > 0)
+ {
+ // 0 means loop indefinitely. count is set as play n + 1 times.
+ // TODO: Check this as the correct value might be pulled from the decoder.
+ repeatCount = (ushort)Math.Max(0, repeatCount - 1);
+ this.WriteByte(stream, GifConstants.ExtensionIntroducer); // NETSCAPE2.0
+ this.WriteByte(stream, GifConstants.ApplicationExtensionLabel);
+ this.WriteByte(stream, GifConstants.ApplicationBlockSize);
+
+ this.WriteString(stream, GifConstants.ApplicationIdentification);
+ this.WriteByte(stream, 3); // Application block length
+ this.WriteByte(stream, 1); // Data sub-block index (always 1)
+ this.WriteShort(stream, repeatCount); // Repeat count for images.
+
+ this.WriteByte(stream, GifConstants.Terminator); // Terminator
+ }
+ }
+
+ ///
+ /// Writes the image descriptor to the stream.
+ ///
+ /// The containing indexed pixels.
+ /// The quality (number of colors) to encode the image to.
+ /// The stream to write to.
+ private void WriteImageDescriptor(QuantizedImage image, int quality, Stream stream)
+ {
+ this.WriteByte(stream, GifConstants.ImageDescriptorLabel); // 2c
+ // TODO: Can we capture this?
+ this.WriteShort(stream, 0); // Left position
+ this.WriteShort(stream, 0); // Top position
+ this.WriteShort(stream, image.Width);
+ this.WriteShort(stream, image.Height);
+
+ // No LCT use GCT.
+ this.WriteByte(stream, 0);
+
+ // Write the image data.
+ this.WriteImageData(image, stream);
+ }
+
+ ///
+ /// Writes the image descriptor to the stream.
+ ///
+ /// The to be encoded.
+ /// The stream to write to.
+ private void WriteFrameImageDescriptor(ImageBase image, Stream stream)
+ {
+ this.WriteByte(stream, GifConstants.ImageDescriptorLabel); // 2c
+ // TODO: Can we capture this?
+ this.WriteShort(stream, 0); // Left position
+ this.WriteShort(stream, 0); // Top position
+ this.WriteShort(stream, image.Width);
+ this.WriteShort(stream, image.Height);
+
+ // Calculate the quality.
+ int quality = this.Quality > 0 ? this.Quality : image.Quality;
+ quality = quality > 0 ? quality.Clamp(1, 256) : 256;
+
+ int packed = 0x80 | // 1: Local color table flag = 1 (LCT used)
+ 0x00 | // 2: Interlace flag 0
+ 0x00 | // 3: Sort flag 0
+ 0 | // 4-5: Reserved
+ this.bitDepth - 1;
+
+ this.WriteByte(stream, packed);
+
+ // Now immediately follow with the color table.
+ QuantizedImage quantized = this.WriteColorTable(image, stream, quality);
+ this.WriteImageData(quantized, stream);
+ }
+
+ ///
+ /// Writes the image pixel data to the stream.
+ ///
+ /// The containing indexed pixels.
+ /// The stream to write to.
+ private void WriteImageData(QuantizedImage image, Stream stream)
+ {
+ byte[] indexedPixels = image.Pixels;
+
+ LzwEncoder encoder = new LzwEncoder(indexedPixels, (byte)this.bitDepth);
+ encoder.Encode(stream);
+
+ this.WriteByte(stream, GifConstants.Terminator);
+ }
+
+ ///
+ /// Writes a short to the given stream.
+ ///
+ /// The containing image data.
+ /// The value to write.
+ private void WriteShort(Stream stream, int value)
+ {
+ // Leave only one significant byte.
+ stream.WriteByte(Convert.ToByte(value & 0xff));
+ stream.WriteByte(Convert.ToByte((value >> 8) & 0xff));
+ }
+
+ ///
+ /// Writes a byte to the given stream.
+ ///
+ /// The containing image data.
+ /// The value to write.
+ private void WriteByte(Stream stream, int value)
+ {
+ stream.WriteByte(Convert.ToByte(value));
+ }
+
+ ///
+ /// Writes a string to the given stream.
+ ///
+ /// The containing image data.
+ /// The value to write.
+ private void WriteString(Stream stream, string value)
+ {
+ char[] chars = value.ToCharArray();
+ foreach (char c in chars)
+ {
+ stream.WriteByte((byte)c);
+ }
+ }
+
+ ///
+ /// Returns how many bits are required to store the specified number of colors.
+ /// Performs a Log2() on the value.
+ ///
+ /// The number of colors.
+ ///
+ /// The
+ ///
+ private int GetBitsNeededForColorDepth(int colors)
+ {
+ return (int)Math.Ceiling(Math.Log(colors, 2));
+ }
+ }
+}
diff --git a/src/ImageProcessorCore/Formats/Png/PngEncoderCore.cs b/src/ImageProcessorCore/Formats/Png/PngEncoderCore.cs
index c5c03991dd..89e3883b35 100644
--- a/src/ImageProcessorCore/Formats/Png/PngEncoderCore.cs
+++ b/src/ImageProcessorCore/Formats/Png/PngEncoderCore.cs
@@ -15,7 +15,7 @@ namespace ImageProcessorCore.Formats
/// Performs the png encoding operation.
/// TODO: Perf. There's lots of array parsing going on here. This should be unmanaged.
///
- internal class PngEncoderCore
+ internal sealed class PngEncoderCore
{
///
/// The maximum block size, defaults at 64k for uncompressed blocks.
@@ -89,14 +89,12 @@ namespace ImageProcessorCore.Formats
0,
8);
- if (image.Quality > 0)
- {
-
- this.Quality = image.Quality.Clamp(1, int.MaxValue);
- }
+ // Ensure that quality can be set but has a fallback.
+ int quality = this.Quality > 0 ? this.Quality : image.Quality;
+ this.Quality = quality > 0 ? quality.Clamp(1, int.MaxValue) : int.MaxValue;
this.bitDepth = this.Quality <= 256
- ? (byte)(this.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
@@ -463,18 +461,5 @@ namespace ImageProcessorCore.Formats
WriteInteger(stream, (uint)crc32.Value);
}
-
- ///
- /// Returns how many bits are required to store the specified number of colors.
- /// Performs a Log2() on the value.
- ///
- /// The number of colors.
- ///
- /// The
- ///
- private int GetBitsNeededForColorDepth(int colors)
- {
- return (int)Math.Ceiling(Math.Log(colors, 2));
- }
}
}