diff --git a/src/ImageProcessor/Common/Helpers/Utils.cs b/src/ImageProcessor/Common/Helpers/Utils.cs
deleted file mode 100644
index c56129d3e..000000000
--- a/src/ImageProcessor/Common/Helpers/Utils.cs
+++ /dev/null
@@ -1,34 +0,0 @@
-// --------------------------------------------------------------------------------------------------------------------
-//
-// Copyright © James South and contributors.
-// Licensed under the Apache License, Version 2.0.
-//
-//
-// General utility methods.
-// TODO: I don't like having classes like this as they turn into a dumping ground. Investigate method usage.
-//
-// --------------------------------------------------------------------------------------------------------------------
-
-namespace ImageProcessor
-{
- ///
- /// General utility methods.
- /// TODO: I don't like having classes like this as they turn into a dumping ground. Investigate method usage.
- ///
- internal static class Utils
- {
- ///
- /// Swaps two references.
- ///
- /// The type of the references to swap.
- /// The first reference.
- /// The second reference.
- public static void Swap(ref TRef lhs, ref TRef rhs) where TRef : class
- {
- TRef tmp = lhs;
-
- lhs = rhs;
- rhs = tmp;
- }
- }
-}
diff --git a/src/ImageProcessor/Formats/Gif/BitEncoder.cs b/src/ImageProcessor/Formats/Gif/BitEncoder.cs
index 0ae595098..faf37108a 100644
--- a/src/ImageProcessor/Formats/Gif/BitEncoder.cs
+++ b/src/ImageProcessor/Formats/Gif/BitEncoder.cs
@@ -1,12 +1,7 @@
-// --------------------------------------------------------------------------------------------------------------------
-//
-// Copyright © James South and contributors.
-// Licensed under the Apache License, Version 2.0.
+//
+// Copyright © James South and contributors.
+// Licensed under the Apache License, Version 2.0.
//
-//
-// Handles the encoding of bits for compression.
-//
-// --------------------------------------------------------------------------------------------------------------------
namespace ImageProcessor.Formats
{
@@ -18,29 +13,19 @@ namespace ImageProcessor.Formats
internal class BitEncoder
{
///
- /// The current working bit.
- ///
- private int currentBit;
-
- ///
- /// The current value.
- ///
- private int currentValue;
-
- ///
- /// The inner list for collecting the bits.
+ /// The inner list for collecting the bits.
///
private readonly List list = new List();
///
- /// The number of bytes in the encoder.
+ /// The current working bit.
///
- internal int Length => this.list.Count;
+ private int currentBit;
///
- /// Gets or sets the intitial bit.
+ /// The current value.
///
- public int IntitialBit { get; set; }
+ private int currentValue;
///
/// Initializes a new instance of the class.
@@ -53,6 +38,16 @@ namespace ImageProcessor.Formats
this.IntitialBit = initial;
}
+ ///
+ /// Gets or sets the intitial bit.
+ ///
+ public int IntitialBit { get; set; }
+
+ ///
+ /// The number of bytes in the encoder.
+ ///
+ public int Length => this.list.Count;
+
///
/// Adds the current byte to the end of the encoder.
///
@@ -78,7 +73,7 @@ namespace ImageProcessor.Formats
/// Adds the collection of bytes to the end of the encoder.
///
///
- /// The collection of bytes to add.
+ /// The collection of bytes to add.
/// The collection itself cannot be null but can contain elements that are null.
public void AddRange(byte[] collection)
{
diff --git a/src/ImageProcessor/Formats/Gif/DisposalMethod.cs b/src/ImageProcessor/Formats/Gif/DisposalMethod.cs
index 2ce4a0523..055435f93 100644
--- a/src/ImageProcessor/Formats/Gif/DisposalMethod.cs
+++ b/src/ImageProcessor/Formats/Gif/DisposalMethod.cs
@@ -1,13 +1,7 @@
-// --------------------------------------------------------------------------------------------------------------------
-//
-// Copyright © James South and contributors.
-// Licensed under the Apache License, Version 2.0.
+//
+// Copyright © James South and contributors.
+// Licensed under the Apache License, Version 2.0.
//
-//
-// Provides enumeration for instructing the decoder what to do with the last image
-// in an animation sequence.
-//
-// --------------------------------------------------------------------------------------------------------------------
namespace ImageProcessor.Formats
{
diff --git a/src/ImageProcessor/Formats/Gif/GifConstants.cs b/src/ImageProcessor/Formats/Gif/GifConstants.cs
index eebbc5479..bae71dd2b 100644
--- a/src/ImageProcessor/Formats/Gif/GifConstants.cs
+++ b/src/ImageProcessor/Formats/Gif/GifConstants.cs
@@ -1,12 +1,7 @@
-// --------------------------------------------------------------------------------------------------------------------
-//
-// Copyright © James South and contributors.
-// Licensed under the Apache License, Version 2.0.
+//
+// Copyright © James South and contributors.
+// Licensed under the Apache License, Version 2.0.
//
-//
-// Constants that define specific points within a gif.
-//
-// --------------------------------------------------------------------------------------------------------------------
namespace ImageProcessor.Formats
{
@@ -30,11 +25,6 @@ namespace ImageProcessor.Formats
///
public const byte ExtensionIntroducer = 0x21;
- ///
- /// The end introducer trailer ;.
- ///
- public const byte EndIntroducer = 0x3B;
-
///
/// The graphic control label.
///
@@ -85,5 +75,9 @@ namespace ImageProcessor.Formats
///
public const byte Terminator = 0;
+ ///
+ /// The end introducer trailer ;.
+ ///
+ public const byte EndIntroducer = 0x3B;
}
}
diff --git a/src/ImageProcessor/Formats/Gif/GifDecoder.cs b/src/ImageProcessor/Formats/Gif/GifDecoder.cs
index d4c33fd2b..9757137d2 100644
--- a/src/ImageProcessor/Formats/Gif/GifDecoder.cs
+++ b/src/ImageProcessor/Formats/Gif/GifDecoder.cs
@@ -1,12 +1,7 @@
-// --------------------------------------------------------------------------------------------------------------------
-//
-// Copyright © James South and contributors.
-// Licensed under the Apache License, Version 2.0.
+//
+// Copyright © James South and contributors.
+// Licensed under the Apache License, Version 2.0.
//
-//
-// Encoder for generating an image out of a gif encoded stream.
-//
-// --------------------------------------------------------------------------------------------------------------------
namespace ImageProcessor.Formats
{
@@ -14,7 +9,7 @@ namespace ImageProcessor.Formats
using System.IO;
///
- /// Encoder for generating an image out of a gif encoded stream.
+ /// Decoder for generating an image out of a gif encoded stream.
///
public class GifDecoder : IImageDecoder
{
@@ -24,9 +19,6 @@ namespace ImageProcessor.Formats
/// The size of the header.
public int HeaderSize => 6;
- internal GifDecoderCore CoreDecoder { get; private set; }
-
-
///
/// Returns a value indicating whether the supports the specified
/// file header.
@@ -69,8 +61,7 @@ namespace ImageProcessor.Formats
/// The containing image data.
public void Decode(Image image, Stream stream)
{
- this.CoreDecoder = new GifDecoderCore();
- this.CoreDecoder.Decode(image, stream);
+ new GifDecoderCore().Decode(image, stream);
}
}
}
diff --git a/src/ImageProcessor/Formats/Gif/GifDecoderCore.cs b/src/ImageProcessor/Formats/Gif/GifDecoderCore.cs
index 3ae9e2628..41d9a3773 100644
--- a/src/ImageProcessor/Formats/Gif/GifDecoderCore.cs
+++ b/src/ImageProcessor/Formats/Gif/GifDecoderCore.cs
@@ -1,39 +1,56 @@
-namespace ImageProcessor.Formats
+//
+// Copyright © James South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageProcessor.Formats
{
using System;
using System.IO;
+ ///
+ /// Performs the gif decoding operation.
+ ///
internal class GifDecoderCore
{
///
- /// The maximum comment length.
+ /// The image to decode the information to.
+ ///
+ private Image decodedImage;
+
+ ///
+ /// The currently loaded stream.
///
- private const int MaxCommentLength = 1024 * 8;
-
- private const byte ExtensionIntroducer = 0x21;
- private const byte Terminator = 0;
- private const byte ImageLabel = 0x2C;
- private const byte EndIntroducer = 0x3B;
- private const byte ApplicationExtensionLabel = 0xFF;
- private const byte CommentLabel = 0xFE;
- private const byte ImageDescriptorLabel = 0x2C;
- private const byte PlainTextLabel = 0x01;
- private const byte GraphicControlLabel = 0xF9;
-
- private Image image;
private Stream currentStream;
+
+ ///
+ /// The global color table.
+ ///
private byte[] globalColorTable;
- private byte[] currentFrame;
- internal GifLogicalScreenDescriptor LogicalScreenDescriptor { get; set; }
+ ///
+ /// The current frame.
+ ///
+ private byte[] currentFrame;
- internal GifGraphicsControlExtension GraphicsControlExtension { get; set; }
+ ///
+ /// The logical screen descriptor.
+ ///
+ private GifLogicalScreenDescriptor logicalScreenDescriptor;
- internal byte Quality { get; set; }
+ ///
+ /// The graphics control extension.
+ ///
+ private GifGraphicsControlExtension graphicsControlExtension;
+ ///
+ /// Decodes the stream to the image.
+ ///
+ /// The image to decode to.
+ /// The stream containing image data.
public void Decode(Image image, Stream stream)
{
- this.image = image;
+ this.decodedImage = image;
this.currentStream = stream;
@@ -41,42 +58,42 @@
this.currentStream.Seek(6, SeekOrigin.Current);
this.ReadLogicalScreenDescriptor();
- if (this.LogicalScreenDescriptor.GlobalColorTableFlag)
+ if (this.logicalScreenDescriptor.GlobalColorTableFlag)
{
- this.globalColorTable = new byte[this.LogicalScreenDescriptor.GlobalColorTableSize * 3];
+ this.globalColorTable = new byte[this.logicalScreenDescriptor.GlobalColorTableSize * 3];
// Read the global color table from the stream
stream.Read(this.globalColorTable, 0, this.globalColorTable.Length);
}
+ // Loop though the respective gif parts and read the data.
int nextFlag = stream.ReadByte();
- while (nextFlag != Terminator)
+ while (nextFlag != GifConstants.Terminator)
{
- if (nextFlag == ImageLabel)
+ if (nextFlag == GifConstants.ImageLabel)
{
this.ReadFrame();
}
- else if (nextFlag == ExtensionIntroducer)
+ else if (nextFlag == GifConstants.ExtensionIntroducer)
{
int label = stream.ReadByte();
switch (label)
{
- case GraphicControlLabel:
+ case GifConstants.GraphicControlLabel:
this.ReadGraphicalControlExtension();
break;
- case CommentLabel:
+ case GifConstants.CommentLabel:
this.ReadComments();
break;
- case ApplicationExtensionLabel:
- // TODO: Read Application extension
- this.Skip(12);
+ case GifConstants.ApplicationExtensionLabel:
+ this.Skip(12); // No need to read.
break;
- case PlainTextLabel:
- this.Skip(13);
+ case GifConstants.PlainTextLabel:
+ this.Skip(13); // Not supported by any known decoder.
break;
}
}
- else if (nextFlag == EndIntroducer)
+ else if (nextFlag == GifConstants.EndIntroducer)
{
break;
}
@@ -85,6 +102,9 @@
}
}
+ ///
+ /// Reads the graphic control extension.
+ ///
private void ReadGraphicalControlExtension()
{
byte[] buffer = new byte[6];
@@ -93,7 +113,7 @@
byte packed = buffer[1];
- this.GraphicsControlExtension = new GifGraphicsControlExtension
+ this.graphicsControlExtension = new GifGraphicsControlExtension
{
DelayTime = BitConverter.ToInt16(buffer, 2),
TransparencyIndex = buffer[4],
@@ -102,12 +122,10 @@
};
}
- private void ReadApplicationBlockExtension()
- {
- // TODO: Implement
- throw new NotImplementedException();
- }
-
+ ///
+ /// Reads the image descriptor
+ ///
+ ///
private GifImageDescriptor ReadImageDescriptor()
{
byte[] buffer = new byte[9];
@@ -130,6 +148,9 @@
return imageDescriptor;
}
+ ///
+ /// Reads the logical screen descriptor.
+ ///
private void ReadLogicalScreenDescriptor()
{
byte[] buffer = new byte[7];
@@ -138,7 +159,7 @@
byte packed = buffer[4];
- this.LogicalScreenDescriptor = new GifLogicalScreenDescriptor
+ this.logicalScreenDescriptor = new GifLogicalScreenDescriptor
{
Width = BitConverter.ToInt16(buffer, 0),
Height = BitConverter.ToInt16(buffer, 2),
@@ -148,19 +169,23 @@
GlobalColorTableSize = 2 << (packed & 0x07)
};
- if (this.LogicalScreenDescriptor.GlobalColorTableSize > 255 * 4)
+ if (this.logicalScreenDescriptor.GlobalColorTableSize > 255 * 4)
{
throw new ImageFormatException(
- $"Invalid gif colormap size '{this.LogicalScreenDescriptor.GlobalColorTableSize}'");
+ $"Invalid gif colormap size '{this.logicalScreenDescriptor.GlobalColorTableSize}'");
}
- if (this.LogicalScreenDescriptor.Width > ImageBase.MaxWidth || this.LogicalScreenDescriptor.Height > ImageBase.MaxHeight)
+ if (this.logicalScreenDescriptor.Width > ImageBase.MaxWidth || this.logicalScreenDescriptor.Height > ImageBase.MaxHeight)
{
throw new ArgumentOutOfRangeException(
- $"The input gif '{this.LogicalScreenDescriptor.Width}x{this.LogicalScreenDescriptor.Height}' is bigger then the max allowed size '{ImageBase.MaxWidth}x{ImageBase.MaxHeight}'");
+ $"The input gif '{this.logicalScreenDescriptor.Width}x{this.logicalScreenDescriptor.Height}' is bigger then the max allowed size '{ImageBase.MaxWidth}x{ImageBase.MaxHeight}'");
}
}
+ ///
+ /// Skips the designated number of bytes in the stream.
+ ///
+ /// The number of bytes to skip.
private void Skip(int length)
{
this.currentStream.Seek(length, SeekOrigin.Current);
@@ -173,25 +198,31 @@
}
}
+ ///
+ /// Reads the gif comments.
+ ///
private void ReadComments()
{
int flag;
while ((flag = this.currentStream.ReadByte()) != 0)
{
- if (flag > MaxCommentLength)
+ if (flag > GifConstants.MaxCommentLength)
{
- throw new ImageFormatException($"Gif comment length '{flag}' exceeds max '{MaxCommentLength}'");
+ throw new ImageFormatException($"Gif comment length '{flag}' exceeds max '{GifConstants.MaxCommentLength}'");
}
byte[] buffer = new byte[flag];
this.currentStream.Read(buffer, 0, flag);
- this.image.Properties.Add(new ImageProperty("Comments", BitConverter.ToString(buffer)));
+ this.decodedImage.Properties.Add(new ImageProperty("Comments", BitConverter.ToString(buffer)));
}
}
+ ///
+ /// Reads an individual gif frame.
+ ///
private void ReadFrame()
{
GifImageDescriptor imageDescriptor = this.ReadImageDescriptor();
@@ -210,6 +241,11 @@
this.Skip(0);
}
+ ///
+ /// Reads the frame indices marking the color to use for each pixel.
+ ///
+ /// The .
+ /// The
private byte[] ReadFrameIndices(GifImageDescriptor imageDescriptor)
{
int dataSize = this.currentStream.ReadByte();
@@ -220,6 +256,11 @@
return indices;
}
+ ///
+ /// Reads the local color table from the current frame.
+ ///
+ /// The .
+ /// The
private byte[] ReadFrameLocalColorTable(GifImageDescriptor imageDescriptor)
{
byte[] localColorTable = null;
@@ -234,10 +275,16 @@
return localColorTable;
}
+ ///
+ /// Reads the frames colors, mapping indices to colors.
+ ///
+ /// The indexed pixels.
+ /// The color table containing the available colors.
+ /// The
private void ReadFrameColors(byte[] indices, byte[] colorTable, GifImageDescriptor descriptor)
{
- int imageWidth = this.LogicalScreenDescriptor.Width;
- int imageHeight = this.LogicalScreenDescriptor.Height;
+ int imageWidth = this.logicalScreenDescriptor.Width;
+ int imageHeight = this.logicalScreenDescriptor.Height;
if (this.currentFrame == null)
{
@@ -246,51 +293,50 @@
byte[] lastFrame = null;
- if (this.GraphicsControlExtension != null &&
- this.GraphicsControlExtension.DisposalMethod == DisposalMethod.RestoreToPrevious)
+ if (this.graphicsControlExtension != null &&
+ this.graphicsControlExtension.DisposalMethod == DisposalMethod.RestoreToPrevious)
{
lastFrame = new byte[imageWidth * imageHeight * 4];
Array.Copy(this.currentFrame, lastFrame, lastFrame.Length);
}
- int offset = 0, i = 0, index = -1;
-
- int iPass = 0; // the interlace pass
- int iInc = 8; // the interlacing line increment
- int iY = 0; // the current interlaced line
- int writeY = 0; // the target y offset to write to
+ int offset, i = 0;
+ int interlacePass = 0; // The interlace pass
+ int interlaceIncrement = 8; // The interlacing line increment
+ int interlaceY = 0; // The current interlaced line
for (int y = descriptor.Top; y < descriptor.Top + descriptor.Height; y++)
{
// Check if this image is interlaced.
+ int writeY; // the target y offset to write to
if (descriptor.InterlaceFlag)
{
// If so then we read lines at predetermined offsets.
// When an entire image height worth of offset lines has been read we consider this a pass.
// With each pass the number of offset lines changes and the starting line changes.
- if (iY >= descriptor.Height)
+ if (interlaceY >= descriptor.Height)
{
- iPass++;
- switch (iPass)
+ interlacePass++;
+ switch (interlacePass)
{
case 1:
- iY = 4;
+ interlaceY = 4;
break;
case 2:
- iY = 2;
- iInc = 4;
+ interlaceY = 2;
+ interlaceIncrement = 4;
break;
case 3:
- iY = 1;
- iInc = 2;
+ interlaceY = 1;
+ interlaceIncrement = 2;
break;
}
}
- writeY = iY + descriptor.Top;
+ writeY = interlaceY + descriptor.Top;
- iY += iInc;
+ interlaceY += interlaceIncrement;
}
else
{
@@ -299,18 +345,18 @@
for (int x = descriptor.Left; x < descriptor.Left + descriptor.Width; x++)
{
- offset = (writeY * imageWidth) + x;
-
- index = indices[i];
+ offset = ((writeY * imageWidth) + x) * 4;
+ int index = indices[i];
- if (this.GraphicsControlExtension == null ||
- this.GraphicsControlExtension.TransparencyFlag == false ||
- this.GraphicsControlExtension.TransparencyIndex != index)
+ if (this.graphicsControlExtension == null ||
+ this.graphicsControlExtension.TransparencyFlag == false ||
+ this.graphicsControlExtension.TransparencyIndex != index)
{
- this.currentFrame[offset * 4 + 0] = colorTable[index * 3 + 2];
- this.currentFrame[offset * 4 + 1] = colorTable[index * 3 + 1];
- this.currentFrame[offset * 4 + 2] = colorTable[index * 3 + 0];
- this.currentFrame[offset * 4 + 3] = (byte)255;
+ int indexOffset = index * 3;
+ this.currentFrame[offset + 0] = colorTable[indexOffset + 2];
+ this.currentFrame[offset + 1] = colorTable[indexOffset + 1];
+ this.currentFrame[offset + 2] = colorTable[indexOffset + 0];
+ this.currentFrame[offset + 3] = 255;
}
i++;
@@ -323,15 +369,15 @@
ImageBase currentImage;
- if (this.image.Pixels == null)
+ if (this.decodedImage.Pixels == null)
{
- currentImage = this.image;
+ currentImage = this.decodedImage;
currentImage.SetPixels(imageWidth, imageHeight, pixels);
currentImage.Quality = colorTable.Length / 3;
- if (this.GraphicsControlExtension != null && this.GraphicsControlExtension.DelayTime > 0)
+ if (this.graphicsControlExtension != null && this.graphicsControlExtension.DelayTime > 0)
{
- this.image.FrameDelay = this.GraphicsControlExtension.DelayTime;
+ this.decodedImage.FrameDelay = this.graphicsControlExtension.DelayTime;
}
}
else
@@ -342,32 +388,32 @@
currentImage.SetPixels(imageWidth, imageHeight, pixels);
currentImage.Quality = colorTable.Length / 3;
- if (this.GraphicsControlExtension != null && this.GraphicsControlExtension.DelayTime > 0)
+ if (this.graphicsControlExtension != null && this.graphicsControlExtension.DelayTime > 0)
{
- currentImage.FrameDelay = this.GraphicsControlExtension.DelayTime;
+ currentImage.FrameDelay = this.graphicsControlExtension.DelayTime;
}
- this.image.Frames.Add(frame);
+ this.decodedImage.Frames.Add(frame);
}
- if (this.GraphicsControlExtension != null)
+ if (this.graphicsControlExtension != null)
{
- if (this.GraphicsControlExtension.DisposalMethod == DisposalMethod.RestoreToBackground)
+ if (this.graphicsControlExtension.DisposalMethod == DisposalMethod.RestoreToBackground)
{
for (int y = descriptor.Top; y < descriptor.Top + descriptor.Height; y++)
{
for (int x = descriptor.Left; x < descriptor.Left + descriptor.Width; x++)
{
- offset = (y * imageWidth) + x;
+ offset = ((y * imageWidth) + x) * 4;
- this.currentFrame[offset * 4 + 0] = 0;
- this.currentFrame[offset * 4 + 1] = 0;
- this.currentFrame[offset * 4 + 2] = 0;
- this.currentFrame[offset * 4 + 3] = 0;
+ this.currentFrame[offset + 0] = 0;
+ this.currentFrame[offset + 1] = 0;
+ this.currentFrame[offset + 2] = 0;
+ this.currentFrame[offset + 3] = 0;
}
}
}
- else if (this.GraphicsControlExtension.DisposalMethod == DisposalMethod.RestoreToPrevious)
+ else if (this.graphicsControlExtension.DisposalMethod == DisposalMethod.RestoreToPrevious)
{
this.currentFrame = lastFrame;
}
diff --git a/src/ImageProcessor/Formats/Gif/GifEncoder.cs b/src/ImageProcessor/Formats/Gif/GifEncoder.cs
index 46bb8dd31..1870b1151 100644
--- a/src/ImageProcessor/Formats/Gif/GifEncoder.cs
+++ b/src/ImageProcessor/Formats/Gif/GifEncoder.cs
@@ -10,7 +10,7 @@ namespace ImageProcessor.Formats
using System.Linq;
///
- /// The Gif encoder
+ /// Image encoder for writing image data to a stream in gif format.
///
public class GifEncoder : IImageEncoder
{
@@ -63,12 +63,12 @@ namespace ImageProcessor.Formats
quality = quality > 0 ? quality.Clamp(1, 256) : 256;
// Get the number of bits.
- int bitdepth = this.GetBitsNeededForColorDepth(quality);
+ int bitDepth = this.GetBitsNeededForColorDepth(quality);
// Write the LSD and check to see if we need a global color table.
// Always true just now.
- bool globalColor = this.WriteGlobalLogicalScreenDescriptor(image, stream, bitdepth);
- QuantizedImage quantized = this.WriteColorTable(imageBase, stream, quality, bitdepth);
+ bool globalColor = this.WriteGlobalLogicalScreenDescriptor(image, stream, bitDepth);
+ QuantizedImage quantized = this.WriteColorTable(imageBase, stream, quality, bitDepth);
this.WriteGraphicalControlExtension(imageBase, stream);
this.WriteImageDescriptor(quantized, quality, stream);
@@ -238,13 +238,13 @@ namespace ImageProcessor.Formats
this.WriteShort(stream, image.Height);
// Calculate the quality.
- int bitdepth = this.GetBitsNeededForColorDepth(quality);
+ int bitDepth = this.GetBitsNeededForColorDepth(quality);
// No LCT use GCT.
this.WriteByte(stream, 0);
- // Write the image data..
- this.WriteImageData(image, stream, bitdepth);
+ // Write the image data.
+ this.WriteImageData(image, stream, bitDepth);
}
///
@@ -264,19 +264,19 @@ namespace ImageProcessor.Formats
// 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 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;
+ 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);
+ QuantizedImage quantized = this.WriteColorTable(image, stream, quality, bitDepth);
+ this.WriteImageData(quantized, stream, bitDepth);
}
///
diff --git a/src/ImageProcessor/Formats/Gif/LzwDecoder.cs b/src/ImageProcessor/Formats/Gif/LzwDecoder.cs
index 4d6cfd4fb..ce28d36d4 100644
--- a/src/ImageProcessor/Formats/Gif/LzwDecoder.cs
+++ b/src/ImageProcessor/Formats/Gif/LzwDecoder.cs
@@ -1,12 +1,7 @@
-// --------------------------------------------------------------------------------------------------------------------
-//
-// Copyright © James South and contributors.
-// Licensed under the Apache License, Version 2.0.
+//
+// Copyright © James South and contributors.
+// Licensed under the Apache License, Version 2.0.
//
-//
-// Decompresses data using the LZW algorithms.
-//
-// --------------------------------------------------------------------------------------------------------------------
namespace ImageProcessor.Formats
{
@@ -19,9 +14,9 @@ namespace ImageProcessor.Formats
internal sealed class LzwDecoder
{
///
- /// The stack size.
+ /// One more than the maximum value 12 bit integer.
///
- private const int StackSize = 4096;
+ private const int MaxStackSize = 4096;
///
/// The null code.
@@ -37,18 +32,19 @@ namespace ImageProcessor.Formats
/// Initializes a new instance of the class
/// and sets the stream, where the compressed data should be read from.
///
- /// The stream. where to read from.
- /// is null
- /// (Nothing in Visual Basic).
+ /// The stream to read from.
+ /// is null.
public LzwDecoder(Stream stream)
{
- Guard.NotNull(stream, "stream");
+ Guard.NotNull(stream, nameof(stream));
this.stream = stream;
}
///
/// Decodes and decompresses all pixel indices from the stream.
+ ///
+ ///
///
/// The width of the pixel index array.
/// The height of the pixel index array.
@@ -72,7 +68,7 @@ namespace ImageProcessor.Formats
// Calculate the available code.
int availableCode = clearCode + 2;
- #region Jillzhangs Code (Not From Me) see: http://giflib.codeplex.com/
+ // Jillzhangs Code (Not From Me) see: http://giflib.codeplex.com/
// TODO: It's imperative that this close is cleaned up and commented properly.
// TODO: Unfortunately I can't figure out the character encoding to translate from the original Chinese.
int code; // ÓÃÓÚ´æ´¢µ±Ç°µÄ±àÂëÖµ
@@ -80,10 +76,9 @@ namespace ImageProcessor.Formats
int codeMask = (1 << codeSize) - 1; // ±íʾ±àÂëµÄ×î´óÖµ£¬Èç¹ûcodeSize=5,Ôòcode_mask=31
int bits = 0; // ÔÚ±àÂëÁ÷ÖÐÊý¾ÝµÄ±£´æÐÎʽΪbyte£¬¶øÊµ¼Ê±àÂë¹ý³ÌÖÐÊÇÕÒʵ¼Ê±àÂëλÀ´´æ´¢µÄ£¬±ÈÈçµ±codeSize=5µÄʱºò£¬ÄÇôʵ¼ÊÉÏ5bitµÄÊý¾Ý¾ÍÓ¦¸Ã¿ÉÒÔ±íʾһ¸ö±àÂ룬ÕâÑùÈ¡³öÀ´µÄ1¸ö×ֽھ͸»ÓàÁË3¸öbit£¬Õâ3¸öbitÓÃÓں͵ڶþ¸ö×ֽڵĺóÁ½¸öbit½øÐÐ×éºÏ£¬ÔÙ´ÎÐγɱàÂëÖµ£¬Èç´ËÀàÍÆ
-
- int[] prefix = new int[StackSize]; // ÓÃÓÚ±£´æÇ°×ºµÄ¼¯ºÏ
- int[] suffix = new int[StackSize]; // ÓÃÓÚ±£´æºó׺
- int[] pixelStatck = new int[StackSize + 1]; // ÓÃÓÚÁÙʱ±£´æÊý¾ÝÁ÷
+ int[] prefix = new int[MaxStackSize]; // ÓÃÓÚ±£´æÇ°×ºµÄ¼¯ºÏ
+ int[] suffix = new int[MaxStackSize]; // ÓÃÓÚ±£´æºó׺
+ int[] pixelStatck = new int[MaxStackSize + 1]; // ÓÃÓÚÁÙʱ±£´æÊý¾ÝÁ÷
int top = 0;
int count = 0; // ÔÚÏÂÃæµÄÑ»·ÖУ¬Ã¿´Î»á»ñȡһ¶¨Á¿µÄ±àÂëµÄ×Ö½ÚÊý×飬¶ø´¦ÀíÕâЩÊý×éµÄʱºòÐèÒª1¸ö¸ö×Ö½ÚÀ´´¦Àí£¬count¾ÍÊDZíʾ»¹Òª´¦ÀíµÄ×Ö½ÚÊýÄ¿
@@ -92,7 +87,6 @@ namespace ImageProcessor.Formats
int data = 0; // ±íʾµ±Ç°´¦ÀíµÄÊý¾ÝµÄÖµ
int first = 0; // Ò»¸ö×Ö·û´®ÖصĵÚÒ»¸ö×Ö½Ú
- int inCode; // ÔÚlzwÖУ¬Èç¹ûÈÏʶÁËÒ»¸ö±àÂëËù´ú±íµÄÊý¾Ýentry£¬Ôò½«±àÂë×÷ΪÏÂÒ»´ÎµÄprefix£¬´Ë´¦inCode´ú±í´«µÝ¸øÏÂÒ»´Î×÷Ϊǰ׺µÄ±àÂëÖµ
// ÏÈÉú³ÉÔªÊý¾ÝµÄǰ׺¼¯ºÏºÍºó׺¼¯ºÏ£¬ÔªÊý¾ÝµÄǰ׺¾ùΪ0£¬¶øºó׺ÓëÔªÊý¾ÝÏàµÈ£¬Í¬Ê±±àÂëÒ²ÓëÔªÊý¾ÝÏàµÈ
for (code = 0; code < clearCode; code++)
@@ -129,8 +123,12 @@ namespace ImageProcessor.Formats
}
// »ñÈ¡±¾´ÎÒª´¦ÀíµÄÊý¾ÝµÄÖµ
- data += buffer[bi] << bits; // ´Ë´¦ÎªºÎÒªÒÆÎ»ÄØ£¬±ÈÈçµÚÒ»´Î´¦ÀíÁË1¸ö×Ö½ÚΪ176£¬µÚÒ»´ÎÖ»Òª´¦Àí5bit¾Í¹»ÁË£¬Ê£ÏÂ3bitÁô¸øÏ¸ö×Ö½Ú½øÐÐ×éºÏ¡£Ò²¾ÍÊǵڶþ¸ö×ֽڵĺóÁ½Î»+µÚÒ»¸ö×Ö½ÚµÄǰÈýλ×é³ÉµÚ¶þ´ÎÊä³öÖµ
- bits += 8; // ±¾´ÎÓÖ´¦ÀíÁËÒ»¸ö×Ö½Ú£¬ËùÒÔÐèÒª+8
+ if (buffer != null)
+ {
+ data += buffer[bi] << bits; // ´Ë´¦ÎªºÎÒªÒÆÎ»ÄØ£¬±ÈÈçµÚÒ»´Î´¦ÀíÁË1¸ö×Ö½ÚΪ176£¬µÚÒ»´ÎÖ»Òª´¦Àí5bit¾Í¹»ÁË£¬Ê£ÏÂ3bitÁô¸øÏ¸ö×Ö½Ú½øÐÐ×éºÏ¡£Ò²¾ÍÊǵڶþ¸ö×ֽڵĺóÁ½Î»+µÚÒ»¸ö×Ö½ÚµÄǰÈýλ×é³ÉµÚ¶þ´ÎÊä³öÖµ
+ }
+
+ bits += 8; // ±¾´ÎÓÖ´¦ÀíÁËÒ»¸ö×Ö½Ú£¬ËùÒÔÐèÒª+8
bi++; // ½«´¦ÀíÏÂÒ»¸ö×Ö½Ú
count--; // ÒѾ´¦Àí¹ýµÄ×Ö½ÚÊý+1
continue;
@@ -145,7 +143,7 @@ namespace ImageProcessor.Formats
// ÏÂÃæ¸ù¾Ý»ñÈ¡µÄcodeÖµÀ´½øÐд¦Àí
if (code > availableCode || code == endCode)
{
- // µ±±àÂëÖµ´óÓÚ×î´ó±àÂëÖµ»òÕßΪ½áÊø±ê¼ÇµÄʱºò£¬Í£Ö¹´¦Àí
+ // µ±±àÂëÖµ´óÓÚ×î´ó±àÂëÖµ»òÕßΪ½áÊø±ê¼ÇµÄʱºò£¬Í£Ö¹´¦Àí
break;
}
@@ -179,7 +177,7 @@ namespace ImageProcessor.Formats
continue;
}
- inCode = code;
+ int inCode = code; // ÔÚlzwÖУ¬Èç¹ûÈÏʶÁËÒ»¸ö±àÂëËù´ú±íµÄÊý¾Ýentry£¬Ôò½«±àÂë×÷ΪÏÂÒ»´ÎµÄprefix£¬´Ë´¦inCode´ú±í´«µÝ¸øÏÂÒ»´Î×÷Ϊǰ׺µÄ±àÂëÖµ
if (code == availableCode)
{
// Èç¹ûµ±Ç°±àÂëºÍ±¾´ÎÓ¦¸ÃÉú³ÉµÄ±àÂëÏàͬ
@@ -201,8 +199,9 @@ namespace ImageProcessor.Formats
// »ñÈ¡ÏÂÒ»¸öÊý¾Ý
pixelStatck[top++] = suffix[code];
- // Fix for Gifs that have "deferred clear code" as per here : https://bugzilla.mozilla.org/show_bug.cgi?id=55918
- if (availableCode < StackSize)
+ // Fix for Gifs that have "deferred clear code" as per here :
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=55918
+ if (availableCode < MaxStackSize)
{
// ÉèÖõ±Ç°Ó¦¸Ã±àÂëλÖõÄǰ׺
prefix[availableCode] = oldCode;
@@ -212,7 +211,7 @@ namespace ImageProcessor.Formats
// Ï´ÎÓ¦¸ÃµÃµ½µÄ±àÂëÖµ
availableCode++;
- if (availableCode == codeMask + 1 && availableCode < StackSize)
+ if (availableCode == codeMask + 1 && availableCode < MaxStackSize)
{
// Ôö¼Ó±àÂëλÊý
codeSize++;
@@ -229,12 +228,10 @@ namespace ImageProcessor.Formats
// »ØËݵ½ÉÏÒ»¸ö´¦ÀíλÖÃ
top--;
- // »ñȡԪÊý¾Ý
+ // »ñȡԪÊý¾Ý
pixels[xyz++] = (byte)pixelStatck[top];
}
- #endregion
-
return pixels;
}
diff --git a/src/ImageProcessor/Formats/Gif/LzwEncoder.cs b/src/ImageProcessor/Formats/Gif/LzwEncoder.cs
index e4e8b08d5..27f33389c 100644
--- a/src/ImageProcessor/Formats/Gif/LzwEncoder.cs
+++ b/src/ImageProcessor/Formats/Gif/LzwEncoder.cs
@@ -1,16 +1,11 @@
-// --------------------------------------------------------------------------------------------------------------------
-//
-// Copyright © James South and contributors.
-// Licensed under the Apache License, Version 2.0.
+//
+// Copyright © James South and contributors.
+// Licensed under the Apache License, Version 2.0.
//
-//
-// Encodes an image pixels used on a method based on LZW compression.
-//
-//
-// --------------------------------------------------------------------------------------------------------------------
namespace ImageProcessor.Formats
{
+ using System;
using System.Collections.Generic;
using System.IO;
@@ -52,8 +47,15 @@ namespace ImageProcessor.Formats
this.initDataSize = this.colorDepth;
}
+ ///
+ /// Encodes the compressed indexed pixel data to the given stream.
+ ///
+ /// The stream to add the data to.
+ /// is null.
public void Encode(Stream stream)
{
+ Guard.NotNull(stream, nameof(stream));
+
// Whether it is a first step.
bool first = true;
diff --git a/src/ImageProcessor/Formats/Gif/Quantizer/IQuantizer.cs b/src/ImageProcessor/Formats/Gif/Quantizer/IQuantizer.cs
index face314ae..26f4f8bf4 100644
--- a/src/ImageProcessor/Formats/Gif/Quantizer/IQuantizer.cs
+++ b/src/ImageProcessor/Formats/Gif/Quantizer/IQuantizer.cs
@@ -1,12 +1,7 @@
-// --------------------------------------------------------------------------------------------------------------------
-//
-// Copyright © James South and contributors.
-// Licensed under the Apache License, Version 2.0.
+//
+// Copyright © James South and contributors.
+// Licensed under the Apache License, Version 2.0.
//
-//
-// Provides methods for allowing quantization of images pixels.
-//
-// --------------------------------------------------------------------------------------------------------------------
namespace ImageProcessor.Formats
{
diff --git a/src/ImageProcessor/Formats/Gif/Quantizer/OctreeQuantizer.cs b/src/ImageProcessor/Formats/Gif/Quantizer/OctreeQuantizer.cs
index 1cf697589..bdf9cf767 100644
--- a/src/ImageProcessor/Formats/Gif/Quantizer/OctreeQuantizer.cs
+++ b/src/ImageProcessor/Formats/Gif/Quantizer/OctreeQuantizer.cs
@@ -1,13 +1,7 @@
-// --------------------------------------------------------------------------------------------------------------------
-//
-// Copyright © James South and contributors.
-// Licensed under the Apache License, Version 2.0.
+//
+// Copyright © James South and contributors.
+// Licensed under the Apache License, Version 2.0.
//
-//
-// Encapsulates methods to calculate the color palette of an image using an Octree pattern.
-//
-//
-// --------------------------------------------------------------------------------------------------------------------
namespace ImageProcessor.Formats
{
diff --git a/src/ImageProcessor/Formats/Gif/Quantizer/QuantizedImage.cs b/src/ImageProcessor/Formats/Gif/Quantizer/QuantizedImage.cs
index 6dc5dec03..e2ed9273d 100644
--- a/src/ImageProcessor/Formats/Gif/Quantizer/QuantizedImage.cs
+++ b/src/ImageProcessor/Formats/Gif/Quantizer/QuantizedImage.cs
@@ -1,12 +1,7 @@
-// --------------------------------------------------------------------------------------------------------------------
-//
-// Copyright © James South and contributors.
-// Licensed under the Apache License, Version 2.0.
+//
+// Copyright © James South and contributors.
+// Licensed under the Apache License, Version 2.0.
//
-//
-// Provides methods for allowing quantization of images pixels.
-//
-// --------------------------------------------------------------------------------------------------------------------
namespace ImageProcessor.Formats
{
diff --git a/src/ImageProcessor/Formats/Gif/Quantizer/Quantizer.cs b/src/ImageProcessor/Formats/Gif/Quantizer/Quantizer.cs
index 9efe62ec3..cfbd23223 100644
--- a/src/ImageProcessor/Formats/Gif/Quantizer/Quantizer.cs
+++ b/src/ImageProcessor/Formats/Gif/Quantizer/Quantizer.cs
@@ -1,12 +1,7 @@
-// --------------------------------------------------------------------------------------------------------------------
-//
-// Copyright © James South and contributors.
-// Licensed under the Apache License, Version 2.0.
+//
+// Copyright © James South and contributors.
+// Licensed under the Apache License, Version 2.0.
//
-//
-// Encapsulates methods to calculate the color palette of an image.
-//
-// --------------------------------------------------------------------------------------------------------------------
namespace ImageProcessor.Formats
{
diff --git a/src/ImageProcessor/Formats/Gif/README.md b/src/ImageProcessor/Formats/Gif/README.md
new file mode 100644
index 000000000..d47a4c683
--- /dev/null
+++ b/src/ImageProcessor/Formats/Gif/README.md
@@ -0,0 +1,4 @@
+Encoder/Decoder adapted and extended from:
+
+https://github.com/yufeih/Nine.Imaging/
+https://imagetools.codeplex.com/
diff --git a/src/ImageProcessor/Formats/Gif/Sections/GifGraphicsControlExtension.cs b/src/ImageProcessor/Formats/Gif/Sections/GifGraphicsControlExtension.cs
index 7b7bfc153..006d8e291 100644
--- a/src/ImageProcessor/Formats/Gif/Sections/GifGraphicsControlExtension.cs
+++ b/src/ImageProcessor/Formats/Gif/Sections/GifGraphicsControlExtension.cs
@@ -1,13 +1,7 @@
-// --------------------------------------------------------------------------------------------------------------------
-//
-// Copyright © James South and contributors.
-// Licensed under the Apache License, Version 2.0.
+//
+// Copyright © James South and contributors.
+// Licensed under the Apache License, Version 2.0.
//
-//
-// The Graphic Control Extension contains parameters used when
-// processing a graphic rendering block.
-//
-// --------------------------------------------------------------------------------------------------------------------
namespace ImageProcessor.Formats
{
diff --git a/src/ImageProcessor/Formats/Gif/Sections/GifImageDescriptor.cs b/src/ImageProcessor/Formats/Gif/Sections/GifImageDescriptor.cs
index cdd768250..199424893 100644
--- a/src/ImageProcessor/Formats/Gif/Sections/GifImageDescriptor.cs
+++ b/src/ImageProcessor/Formats/Gif/Sections/GifImageDescriptor.cs
@@ -1,15 +1,7 @@
-// --------------------------------------------------------------------------------------------------------------------
-//
-// Copyright © James South and contributors.
-// Licensed under the Apache License, Version 2.0.
+//
+// Copyright © James South and contributors.
+// Licensed under the Apache License, Version 2.0.
//
-//
-// Each image in the Data Stream is composed of an Image Descriptor,
-// an optional Local Color Table, and the image data.
-// Each image must fit within the boundaries of the
-// Logical Screen, as defined in the Logical Screen Descriptor.
-//
-// --------------------------------------------------------------------------------------------------------------------
namespace ImageProcessor.Formats
{
diff --git a/src/ImageProcessor/Formats/Png/PngDecoderCore.cs b/src/ImageProcessor/Formats/Png/PngDecoderCore.cs
index e1a75c825..aa0f37990 100644
--- a/src/ImageProcessor/Formats/Png/PngDecoderCore.cs
+++ b/src/ImageProcessor/Formats/Png/PngDecoderCore.cs
@@ -57,38 +57,22 @@ namespace ImageProcessor.Formats
{
ColorTypes.Add(
0,
- new PngColorTypeInformation(
- 1,
- new[] { 1, 2, 4, 8 },
- (p, a) => new GrayscaleReader(false)));
+ new PngColorTypeInformation(1, new[] { 1, 2, 4, 8 }, (p, a) => new GrayscaleReader(false)));
ColorTypes.Add(
2,
- new PngColorTypeInformation(
- 3,
- new[] { 8 },
- (p, a) => new TrueColorReader(false)));
+ new PngColorTypeInformation(3, new[] { 8 }, (p, a) => new TrueColorReader(false)));
ColorTypes.Add(
3,
- new PngColorTypeInformation(
- 1,
- new[] { 1, 2, 4, 8 },
- (p, a) => new PaletteIndexReader(p, a)));
+ new PngColorTypeInformation(1, new[] { 1, 2, 4, 8 }, (p, a) => new PaletteIndexReader(p, a)));
ColorTypes.Add(
4,
- new PngColorTypeInformation(
- 2,
- new[] { 8 },
- (p, a) => new GrayscaleReader(true)));
+ new PngColorTypeInformation(2, new[] { 8 }, (p, a) => new GrayscaleReader(true)));
- ColorTypes.Add(
- 6,
- new PngColorTypeInformation(
- 4,
- new[] { 8 },
- (p, a) => new TrueColorReader(true)));
+ ColorTypes.Add(6,
+ new PngColorTypeInformation(4, new[] { 8 }, (p, a) => new TrueColorReader(true)));
}
///
@@ -334,7 +318,7 @@ namespace ImageProcessor.Formats
colorReader.ReadScanline(currentScanline, pixels, this.header);
column = -1;
- Utils.Swap(ref currentScanline, ref lastScanline);
+ this.Swap(ref currentScanline, ref lastScanline);
}
}
}
@@ -544,5 +528,20 @@ namespace ImageProcessor.Formats
return numBytes;
}
+
+ ///
+ /// Swaps two references.
+ ///
+ /// The type of the references to swap.
+ /// The first reference.
+ /// The second reference.
+ private void Swap(ref TRef lhs, ref TRef rhs)
+ where TRef : class
+ {
+ TRef tmp = lhs;
+
+ lhs = rhs;
+ rhs = tmp;
+ }
}
}
diff --git a/src/ImageProcessor/ImageProcessor.csproj b/src/ImageProcessor/ImageProcessor.csproj
index 066022679..4fc9b385e 100644
--- a/src/ImageProcessor/ImageProcessor.csproj
+++ b/src/ImageProcessor/ImageProcessor.csproj
@@ -45,7 +45,6 @@
-
@@ -176,6 +175,7 @@
+