From f9a6d87d52bb0cc117ae2595e2d26ea3a8e793ce Mon Sep 17 00:00:00 2001 From: James South Date: Thu, 6 Nov 2014 17:02:27 +0000 Subject: [PATCH] Moving exception to to the rest Former-commit-id: bdaf0e14099acbcf79e9dc1cfef8d051e70a174d Former-commit-id: 19d21cfd3784d77b1902b73cc5081365f1784536 --- .../Exceptions/QuantizationException.cs | 42 ++++ src/ImageProcessor/ImageProcessor.csproj | 2 +- .../Quantizers/WuQuantizer/ImageBuffer.cs | 2 + .../Quantizers/WuQuantizer/PaletteLookup.cs | 226 +++++++++++++----- .../WuQuantizer/QuantizationException.cs | 16 -- 5 files changed, 205 insertions(+), 83 deletions(-) create mode 100644 src/ImageProcessor/Common/Exceptions/QuantizationException.cs delete mode 100644 src/ImageProcessor/Imaging/Quantizers/WuQuantizer/QuantizationException.cs diff --git a/src/ImageProcessor/Common/Exceptions/QuantizationException.cs b/src/ImageProcessor/Common/Exceptions/QuantizationException.cs new file mode 100644 index 000000000..7c2e17946 --- /dev/null +++ b/src/ImageProcessor/Common/Exceptions/QuantizationException.cs @@ -0,0 +1,42 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// The exception that is thrown when quantizing an image has failed. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor.Common.Exceptions +{ + using System; + + /// + /// The exception that is thrown when quantizing an image has failed. + /// + [Serializable] + public class QuantizationException : Exception + { + /// + /// Initializes a new instance of the class. + /// + /// + /// The message. + /// + public QuantizationException(string message) + : base(message) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The error message that explains the reason for the exception. + /// The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified. + public QuantizationException(string message, Exception innerException) + : base(message, innerException) + { + } + } +} diff --git a/src/ImageProcessor/ImageProcessor.csproj b/src/ImageProcessor/ImageProcessor.csproj index fb8773734..d47dd3b5d 100644 --- a/src/ImageProcessor/ImageProcessor.csproj +++ b/src/ImageProcessor/ImageProcessor.csproj @@ -195,7 +195,7 @@ Code - + diff --git a/src/ImageProcessor/Imaging/Quantizers/WuQuantizer/ImageBuffer.cs b/src/ImageProcessor/Imaging/Quantizers/WuQuantizer/ImageBuffer.cs index 14dbbdf31..91e5c975b 100644 --- a/src/ImageProcessor/Imaging/Quantizers/WuQuantizer/ImageBuffer.cs +++ b/src/ImageProcessor/Imaging/Quantizers/WuQuantizer/ImageBuffer.cs @@ -18,6 +18,8 @@ namespace ImageProcessor.Imaging.Quantizers.WuQuantizer using System.Drawing.Imaging; using System.Runtime.InteropServices; + using ImageProcessor.Common.Exceptions; + /// /// The image buffer for storing pixel information. /// Adapted from diff --git a/src/ImageProcessor/Imaging/Quantizers/WuQuantizer/PaletteLookup.cs b/src/ImageProcessor/Imaging/Quantizers/WuQuantizer/PaletteLookup.cs index 43ba5d04b..d22486a6d 100644 --- a/src/ImageProcessor/Imaging/Quantizers/WuQuantizer/PaletteLookup.cs +++ b/src/ImageProcessor/Imaging/Quantizers/WuQuantizer/PaletteLookup.cs @@ -1,32 +1,78 @@ -namespace ImageProcessor.Imaging.Quantizers.WuQuantizer +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// Stores the indexed color palette of an image for fast access. +// Adapted from +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor.Imaging.Quantizers.WuQuantizer { using System; using System.Collections.Generic; using System.Linq; - class PaletteLookup + /// + /// Stores the indexed color palette of an image for fast access. + /// Adapted from + /// + internal class PaletteLookup { - private int mMask; - private Dictionary mLookup; - private LookupNode[] Palette { get; set; } + /// + /// The dictionary for caching lookup nodes. + /// + private Dictionary lookupNodes; + + /// + /// The palette mask. + /// + private int paletteMask; + /// + /// Initializes a new instance of the class. + /// + /// + /// The palette. + /// public PaletteLookup(Pixel[] palette) { - Palette = new LookupNode[palette.Length]; + this.Palette = new LookupNode[palette.Length]; for (int paletteIndex = 0; paletteIndex < palette.Length; paletteIndex++) { - Palette[paletteIndex] = new LookupNode { Pixel = palette[paletteIndex], PaletteIndex = (byte)paletteIndex }; + this.Palette[paletteIndex] = new LookupNode + { + Pixel = palette[paletteIndex], + PaletteIndex = (byte)paletteIndex + }; } - BuildLookup(palette); + + this.BuildLookup(palette); } + /// + /// Gets or sets the palette. + /// + private LookupNode[] Palette { get; set; } + + /// + /// Gets palette index for the given pixel. + /// + /// + /// The pixel to return the index for. + /// + /// + /// The representing the index. + /// public byte GetPaletteIndex(Pixel pixel) { - int pixelKey = pixel.Argb & mMask; + int pixelKey = pixel.Argb & this.paletteMask; LookupNode[] bucket; - if (!mLookup.TryGetValue(pixelKey, out bucket)) + if (!this.lookupNodes.TryGetValue(pixelKey, out bucket)) { - bucket = Palette; + bucket = this.Palette; } if (bucket.Length == 1) @@ -53,121 +99,169 @@ distance += deltaBlue * deltaBlue; if (distance >= bestDistance) + { continue; + } bestDistance = distance; bestMatch = lookup.PaletteIndex; } - if ((bucket == Palette) && (pixelKey != 0)) + if ((bucket == this.Palette) && (pixelKey != 0)) { - mLookup[pixelKey] = new LookupNode[] { bucket[bestMatch] }; + this.lookupNodes[pixelKey] = new[] { bucket[bestMatch] }; } return bestMatch; } - private void BuildLookup(Pixel[] palette) + /// + /// Computes the bit mask. + /// + /// + /// The maximum byte value. + /// + /// + /// The number of bits. + /// + /// + /// The . + /// + private static byte ComputeBitMask(byte max, int bits) { - int mask = GetMask(palette); - Dictionary> tempLookup = new Dictionary>(); - foreach (LookupNode lookup in Palette) + byte mask = 0; + + if (bits != 0) { - int pixelKey = lookup.Pixel.Argb & mask; + byte highestSetBitIndex = HighestSetBitIndex(max); - List bucket; - if (!tempLookup.TryGetValue(pixelKey, out bucket)) + for (int i = 0; i < bits; i++) { - bucket = new List(); - tempLookup[pixelKey] = bucket; + mask <<= 1; + mask++; } - bucket.Add(lookup); - } - mLookup = new Dictionary(tempLookup.Count); - foreach (var key in tempLookup.Keys) - { - mLookup[key] = tempLookup[key].ToArray(); + for (int i = 0; i <= highestSetBitIndex - bits; i++) + { + mask <<= 1; + } } - mMask = mask; + + return mask; } + /// + /// Gets the mask value from the palette. + /// + /// + /// The palette. + /// + /// + /// The representing the component value of the mask. + /// private static int GetMask(Pixel[] palette) { - IEnumerable alphas = from pixel in palette - select pixel.Alpha; + IEnumerable alphas = palette.Select(p => p.Alpha).ToArray(); byte maxAlpha = alphas.Max(); int uniqueAlphas = alphas.Distinct().Count(); - IEnumerable reds = from pixel in palette - select pixel.Red; + IEnumerable reds = palette.Select(p => p.Red).ToArray(); byte maxRed = reds.Max(); int uniqueReds = reds.Distinct().Count(); - IEnumerable greens = from pixel in palette - select pixel.Green; + IEnumerable greens = palette.Select(p => p.Green).ToArray(); byte maxGreen = greens.Max(); int uniqueGreens = greens.Distinct().Count(); - IEnumerable blues = from pixel in palette - select pixel.Blue; + IEnumerable blues = palette.Select(p => p.Green).ToArray(); byte maxBlue = blues.Max(); int uniqueBlues = blues.Distinct().Count(); double totalUniques = uniqueAlphas + uniqueReds + uniqueGreens + uniqueBlues; - double AvailableBits = 1.0 + Math.Log(uniqueAlphas * uniqueReds * uniqueGreens * uniqueBlues); + double availableBits = 1.0 + Math.Log(uniqueAlphas * uniqueReds * uniqueGreens * uniqueBlues); - byte alphaMask = ComputeBitMask(maxAlpha, Convert.ToInt32(Math.Round(uniqueAlphas / totalUniques * AvailableBits))); - byte redMask = ComputeBitMask(maxRed, Convert.ToInt32(Math.Round(uniqueReds / totalUniques * AvailableBits))); - byte greenMask = ComputeBitMask(maxGreen, Convert.ToInt32(Math.Round(uniqueGreens / totalUniques * AvailableBits))); - byte blueMask = ComputeBitMask(maxBlue, Convert.ToInt32(Math.Round(uniqueBlues / totalUniques * AvailableBits))); + byte alphaMask = ComputeBitMask(maxAlpha, Convert.ToInt32(Math.Round(uniqueAlphas / totalUniques * availableBits))); + byte redMask = ComputeBitMask(maxRed, Convert.ToInt32(Math.Round(uniqueReds / totalUniques * availableBits))); + byte greenMask = ComputeBitMask(maxGreen, Convert.ToInt32(Math.Round(uniqueGreens / totalUniques * availableBits))); + byte blueMask = ComputeBitMask(maxBlue, Convert.ToInt32(Math.Round(uniqueBlues / totalUniques * availableBits))); Pixel maskedPixel = new Pixel(alphaMask, redMask, greenMask, blueMask); return maskedPixel.Argb; } - private static byte ComputeBitMask(byte max, int bits) + /// + /// Gets the highest set bit index. + /// + /// + /// The value. + /// + /// + /// The . + /// + private static byte HighestSetBitIndex(byte value) { - byte mask = 0; - - if (bits != 0) + byte index = 0; + for (int i = 0; i < 8; i++) { - byte highestSetBitIndex = HighestSetBitIndex(max); - - - for (int i = 0; i < bits; i++) + if (0 != (value & 1)) { - mask <<= 1; - mask++; + index = (byte)i; } - for (int i = 0; i <= highestSetBitIndex - bits; i++) - { - mask <<= 1; - } + value >>= 1; } - return mask; + + return index; } - private static byte HighestSetBitIndex(byte value) + /// + /// The build lookup. + /// + /// + /// The palette. + /// + private void BuildLookup(Pixel[] palette) { - byte index = 0; - for (int i = 0; i < 8; i++) + int mask = GetMask(palette); + Dictionary> tempLookup = new Dictionary>(); + foreach (LookupNode lookup in this.Palette) { - if (0 != (value & 1)) + int pixelKey = lookup.Pixel.Argb & mask; + + List bucket; + if (!tempLookup.TryGetValue(pixelKey, out bucket)) { - index = (byte)i; + bucket = new List(); + tempLookup[pixelKey] = bucket; } - value >>= 1; + + bucket.Add(lookup); } - return index; + + this.lookupNodes = new Dictionary(tempLookup.Count); + foreach (var key in tempLookup.Keys) + { + this.lookupNodes[key] = tempLookup[key].ToArray(); + } + + this.paletteMask = mask; } + /// + /// Represents a single node containing the index and pixel. + /// private struct LookupNode { - public Pixel Pixel; + /// + /// The palette index. + /// public byte PaletteIndex; + + /// + /// The pixel. + /// + public Pixel Pixel; } } -} +} \ No newline at end of file diff --git a/src/ImageProcessor/Imaging/Quantizers/WuQuantizer/QuantizationException.cs b/src/ImageProcessor/Imaging/Quantizers/WuQuantizer/QuantizationException.cs deleted file mode 100644 index e723f7dc1..000000000 --- a/src/ImageProcessor/Imaging/Quantizers/WuQuantizer/QuantizationException.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace ImageProcessor.Imaging.Quantizers.WuQuantizer -{ - [Serializable] - public class QuantizationException : ApplicationException - { - public QuantizationException(string message) : base(message) - { - - } - } -}