Browse Source

Cleanup.

Former-commit-id: 24c3536a9f7e9e6e09b2aba5dc20613deb5480c6
Former-commit-id: 74ae512bde698c21b490426a0df6ecb7029f4f0d
Former-commit-id: 25ae344fe041dfdb12ec44a58f844248adcc25cd
pull/17/head
James Jackson-South 11 years ago
parent
commit
7e7fd78624
  1. 34
      src/ImageProcessor/Common/Helpers/Utils.cs
  2. 43
      src/ImageProcessor/Formats/Gif/BitEncoder.cs
  3. 12
      src/ImageProcessor/Formats/Gif/DisposalMethod.cs
  4. 20
      src/ImageProcessor/Formats/Gif/GifConstants.cs
  5. 19
      src/ImageProcessor/Formats/Gif/GifDecoder.cs
  6. 232
      src/ImageProcessor/Formats/Gif/GifDecoderCore.cs
  7. 22
      src/ImageProcessor/Formats/Gif/GifEncoder.cs
  8. 57
      src/ImageProcessor/Formats/Gif/LzwDecoder.cs
  9. 20
      src/ImageProcessor/Formats/Gif/LzwEncoder.cs
  10. 11
      src/ImageProcessor/Formats/Gif/Quantizer/IQuantizer.cs
  11. 12
      src/ImageProcessor/Formats/Gif/Quantizer/OctreeQuantizer.cs
  12. 11
      src/ImageProcessor/Formats/Gif/Quantizer/QuantizedImage.cs
  13. 11
      src/ImageProcessor/Formats/Gif/Quantizer/Quantizer.cs
  14. 4
      src/ImageProcessor/Formats/Gif/README.md
  15. 12
      src/ImageProcessor/Formats/Gif/Sections/GifGraphicsControlExtension.cs
  16. 14
      src/ImageProcessor/Formats/Gif/Sections/GifImageDescriptor.cs
  17. 45
      src/ImageProcessor/Formats/Png/PngDecoderCore.cs
  18. 2
      src/ImageProcessor/ImageProcessor.csproj

34
src/ImageProcessor/Common/Helpers/Utils.cs

@ -1,34 +0,0 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="Utils.cs" company="James South">
// Copyright © James South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
// <summary>
// General utility methods.
// TODO: I don't like having classes like this as they turn into a dumping ground. Investigate method usage.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace ImageProcessor
{
/// <summary>
/// General utility methods.
/// TODO: I don't like having classes like this as they turn into a dumping ground. Investigate method usage.
/// </summary>
internal static class Utils
{
/// <summary>
/// Swaps two references.
/// </summary>
/// <typeparam name="TRef">The type of the references to swap.</typeparam>
/// <param name="lhs">The first reference.</param>
/// <param name="rhs">The second reference.</param>
public static void Swap<TRef>(ref TRef lhs, ref TRef rhs) where TRef : class
{
TRef tmp = lhs;
lhs = rhs;
rhs = tmp;
}
}
}

43
src/ImageProcessor/Formats/Gif/BitEncoder.cs

@ -1,12 +1,7 @@
// -------------------------------------------------------------------------------------------------------------------- // <copyright file="BitEncoder.cs" company="James South">
// <copyright file="BitEncoder.cs" company="James South"> // Copyright © James South and contributors.
// Copyright © James South and contributors. // Licensed under the Apache License, Version 2.0.
// Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
// <summary>
// Handles the encoding of bits for compression.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace ImageProcessor.Formats namespace ImageProcessor.Formats
{ {
@ -18,29 +13,19 @@ namespace ImageProcessor.Formats
internal class BitEncoder internal class BitEncoder
{ {
/// <summary> /// <summary>
/// The current working bit. /// The inner list for collecting the bits.
/// </summary>
private int currentBit;
/// <summary>
/// The current value.
/// </summary>
private int currentValue;
/// <summary>
/// The inner list for collecting the bits.
/// </summary> /// </summary>
private readonly List<byte> list = new List<byte>(); private readonly List<byte> list = new List<byte>();
/// <summary> /// <summary>
/// The number of bytes in the encoder. /// The current working bit.
/// </summary> /// </summary>
internal int Length => this.list.Count; private int currentBit;
/// <summary> /// <summary>
/// Gets or sets the intitial bit. /// The current value.
/// </summary> /// </summary>
public int IntitialBit { get; set; } private int currentValue;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="BitEncoder"/> class. /// Initializes a new instance of the <see cref="BitEncoder"/> class.
@ -53,6 +38,16 @@ namespace ImageProcessor.Formats
this.IntitialBit = initial; this.IntitialBit = initial;
} }
/// <summary>
/// Gets or sets the intitial bit.
/// </summary>
public int IntitialBit { get; set; }
/// <summary>
/// The number of bytes in the encoder.
/// </summary>
public int Length => this.list.Count;
/// <summary> /// <summary>
/// Adds the current byte to the end of the encoder. /// Adds the current byte to the end of the encoder.
/// </summary> /// </summary>
@ -78,7 +73,7 @@ namespace ImageProcessor.Formats
/// Adds the collection of bytes to the end of the encoder. /// Adds the collection of bytes to the end of the encoder.
/// </summary> /// </summary>
/// <param name="collection"> /// <param name="collection">
/// 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.</param> /// The collection itself cannot be null but can contain elements that are null.</param>
public void AddRange(byte[] collection) public void AddRange(byte[] collection)
{ {

12
src/ImageProcessor/Formats/Gif/DisposalMethod.cs

@ -1,13 +1,7 @@
// -------------------------------------------------------------------------------------------------------------------- // <copyright file="DisposalMethod.cs" company="James South">
// <copyright file="DisposalMethod.cs" company="James South"> // Copyright © James South and contributors.
// Copyright © James South and contributors. // Licensed under the Apache License, Version 2.0.
// Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
// <summary>
// Provides enumeration for instructing the decoder what to do with the last image
// in an animation sequence.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace ImageProcessor.Formats namespace ImageProcessor.Formats
{ {

20
src/ImageProcessor/Formats/Gif/GifConstants.cs

@ -1,12 +1,7 @@
// -------------------------------------------------------------------------------------------------------------------- // <copyright file="GifConstants.cs" company="James South">
// <copyright file="GifConstants.cs" company="James South"> // Copyright © James South and contributors.
// Copyright © James South and contributors. // Licensed under the Apache License, Version 2.0.
// Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
// <summary>
// Constants that define specific points within a gif.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace ImageProcessor.Formats namespace ImageProcessor.Formats
{ {
@ -30,11 +25,6 @@ namespace ImageProcessor.Formats
/// </summary> /// </summary>
public const byte ExtensionIntroducer = 0x21; public const byte ExtensionIntroducer = 0x21;
/// <summary>
/// The end introducer trailer <value>;</value>.
/// </summary>
public const byte EndIntroducer = 0x3B;
/// <summary> /// <summary>
/// The graphic control label. /// The graphic control label.
/// </summary> /// </summary>
@ -85,5 +75,9 @@ namespace ImageProcessor.Formats
/// </summary> /// </summary>
public const byte Terminator = 0; public const byte Terminator = 0;
/// <summary>
/// The end introducer trailer <value>;</value>.
/// </summary>
public const byte EndIntroducer = 0x3B;
} }
} }

19
src/ImageProcessor/Formats/Gif/GifDecoder.cs

@ -1,12 +1,7 @@
// -------------------------------------------------------------------------------------------------------------------- // <copyright file="GifDecoder.cs" company="James South">
// <copyright file="GifDecoder.cs" company="James South"> // Copyright © James South and contributors.
// Copyright © James South and contributors. // Licensed under the Apache License, Version 2.0.
// Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
// <summary>
// Encoder for generating an image out of a gif encoded stream.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace ImageProcessor.Formats namespace ImageProcessor.Formats
{ {
@ -14,7 +9,7 @@ namespace ImageProcessor.Formats
using System.IO; using System.IO;
/// <summary> /// <summary>
/// Encoder for generating an image out of a gif encoded stream. /// Decoder for generating an image out of a gif encoded stream.
/// </summary> /// </summary>
public class GifDecoder : IImageDecoder public class GifDecoder : IImageDecoder
{ {
@ -24,9 +19,6 @@ namespace ImageProcessor.Formats
/// <value>The size of the header.</value> /// <value>The size of the header.</value>
public int HeaderSize => 6; public int HeaderSize => 6;
internal GifDecoderCore CoreDecoder { get; private set; }
/// <summary> /// <summary>
/// Returns a value indicating whether the <see cref="IImageDecoder"/> supports the specified /// Returns a value indicating whether the <see cref="IImageDecoder"/> supports the specified
/// file header. /// file header.
@ -69,8 +61,7 @@ namespace ImageProcessor.Formats
/// <param name="stream">The <see cref="Stream"/> containing image data.</param> /// <param name="stream">The <see cref="Stream"/> containing image data.</param>
public void Decode(Image image, Stream stream) public void Decode(Image image, Stream stream)
{ {
this.CoreDecoder = new GifDecoderCore(); new GifDecoderCore().Decode(image, stream);
this.CoreDecoder.Decode(image, stream);
} }
} }
} }

232
src/ImageProcessor/Formats/Gif/GifDecoderCore.cs

@ -1,39 +1,56 @@
namespace ImageProcessor.Formats // <copyright file="GifDecoderCore.cs" company="James South">
// Copyright © James South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageProcessor.Formats
{ {
using System; using System;
using System.IO; using System.IO;
/// <summary>
/// Performs the gif decoding operation.
/// </summary>
internal class GifDecoderCore internal class GifDecoderCore
{ {
/// <summary> /// <summary>
/// The maximum comment length. /// The image to decode the information to.
/// </summary>
private Image decodedImage;
/// <summary>
/// The currently loaded stream.
/// </summary> /// </summary>
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; private Stream currentStream;
/// <summary>
/// The global color table.
/// </summary>
private byte[] globalColorTable; private byte[] globalColorTable;
private byte[] currentFrame;
internal GifLogicalScreenDescriptor LogicalScreenDescriptor { get; set; } /// <summary>
/// The current frame.
/// </summary>
private byte[] currentFrame;
internal GifGraphicsControlExtension GraphicsControlExtension { get; set; } /// <summary>
/// The logical screen descriptor.
/// </summary>
private GifLogicalScreenDescriptor logicalScreenDescriptor;
internal byte Quality { get; set; } /// <summary>
/// The graphics control extension.
/// </summary>
private GifGraphicsControlExtension graphicsControlExtension;
/// <summary>
/// Decodes the stream to the image.
/// </summary>
/// <param name="image">The image to decode to.</param>
/// <param name="stream">The stream containing image data. </param>
public void Decode(Image image, Stream stream) public void Decode(Image image, Stream stream)
{ {
this.image = image; this.decodedImage = image;
this.currentStream = stream; this.currentStream = stream;
@ -41,42 +58,42 @@
this.currentStream.Seek(6, SeekOrigin.Current); this.currentStream.Seek(6, SeekOrigin.Current);
this.ReadLogicalScreenDescriptor(); 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 // Read the global color table from the stream
stream.Read(this.globalColorTable, 0, this.globalColorTable.Length); stream.Read(this.globalColorTable, 0, this.globalColorTable.Length);
} }
// Loop though the respective gif parts and read the data.
int nextFlag = stream.ReadByte(); int nextFlag = stream.ReadByte();
while (nextFlag != Terminator) while (nextFlag != GifConstants.Terminator)
{ {
if (nextFlag == ImageLabel) if (nextFlag == GifConstants.ImageLabel)
{ {
this.ReadFrame(); this.ReadFrame();
} }
else if (nextFlag == ExtensionIntroducer) else if (nextFlag == GifConstants.ExtensionIntroducer)
{ {
int label = stream.ReadByte(); int label = stream.ReadByte();
switch (label) switch (label)
{ {
case GraphicControlLabel: case GifConstants.GraphicControlLabel:
this.ReadGraphicalControlExtension(); this.ReadGraphicalControlExtension();
break; break;
case CommentLabel: case GifConstants.CommentLabel:
this.ReadComments(); this.ReadComments();
break; break;
case ApplicationExtensionLabel: case GifConstants.ApplicationExtensionLabel:
// TODO: Read Application extension this.Skip(12); // No need to read.
this.Skip(12);
break; break;
case PlainTextLabel: case GifConstants.PlainTextLabel:
this.Skip(13); this.Skip(13); // Not supported by any known decoder.
break; break;
} }
} }
else if (nextFlag == EndIntroducer) else if (nextFlag == GifConstants.EndIntroducer)
{ {
break; break;
} }
@ -85,6 +102,9 @@
} }
} }
/// <summary>
/// Reads the graphic control extension.
/// </summary>
private void ReadGraphicalControlExtension() private void ReadGraphicalControlExtension()
{ {
byte[] buffer = new byte[6]; byte[] buffer = new byte[6];
@ -93,7 +113,7 @@
byte packed = buffer[1]; byte packed = buffer[1];
this.GraphicsControlExtension = new GifGraphicsControlExtension this.graphicsControlExtension = new GifGraphicsControlExtension
{ {
DelayTime = BitConverter.ToInt16(buffer, 2), DelayTime = BitConverter.ToInt16(buffer, 2),
TransparencyIndex = buffer[4], TransparencyIndex = buffer[4],
@ -102,12 +122,10 @@
}; };
} }
private void ReadApplicationBlockExtension() /// <summary>
{ /// Reads the image descriptor
// TODO: Implement /// </summary>
throw new NotImplementedException(); /// <returns><see cref="GifImageDescriptor"/></returns>
}
private GifImageDescriptor ReadImageDescriptor() private GifImageDescriptor ReadImageDescriptor()
{ {
byte[] buffer = new byte[9]; byte[] buffer = new byte[9];
@ -130,6 +148,9 @@
return imageDescriptor; return imageDescriptor;
} }
/// <summary>
/// Reads the logical screen descriptor.
/// </summary>
private void ReadLogicalScreenDescriptor() private void ReadLogicalScreenDescriptor()
{ {
byte[] buffer = new byte[7]; byte[] buffer = new byte[7];
@ -138,7 +159,7 @@
byte packed = buffer[4]; byte packed = buffer[4];
this.LogicalScreenDescriptor = new GifLogicalScreenDescriptor this.logicalScreenDescriptor = new GifLogicalScreenDescriptor
{ {
Width = BitConverter.ToInt16(buffer, 0), Width = BitConverter.ToInt16(buffer, 0),
Height = BitConverter.ToInt16(buffer, 2), Height = BitConverter.ToInt16(buffer, 2),
@ -148,19 +169,23 @@
GlobalColorTableSize = 2 << (packed & 0x07) GlobalColorTableSize = 2 << (packed & 0x07)
}; };
if (this.LogicalScreenDescriptor.GlobalColorTableSize > 255 * 4) if (this.logicalScreenDescriptor.GlobalColorTableSize > 255 * 4)
{ {
throw new ImageFormatException( 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( 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}'");
} }
} }
/// <summary>
/// Skips the designated number of bytes in the stream.
/// </summary>
/// <param name="length">The number of bytes to skip.</param>
private void Skip(int length) private void Skip(int length)
{ {
this.currentStream.Seek(length, SeekOrigin.Current); this.currentStream.Seek(length, SeekOrigin.Current);
@ -173,25 +198,31 @@
} }
} }
/// <summary>
/// Reads the gif comments.
/// </summary>
private void ReadComments() private void ReadComments()
{ {
int flag; int flag;
while ((flag = this.currentStream.ReadByte()) != 0) 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]; byte[] buffer = new byte[flag];
this.currentStream.Read(buffer, 0, 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)));
} }
} }
/// <summary>
/// Reads an individual gif frame.
/// </summary>
private void ReadFrame() private void ReadFrame()
{ {
GifImageDescriptor imageDescriptor = this.ReadImageDescriptor(); GifImageDescriptor imageDescriptor = this.ReadImageDescriptor();
@ -210,6 +241,11 @@
this.Skip(0); this.Skip(0);
} }
/// <summary>
/// Reads the frame indices marking the color to use for each pixel.
/// </summary>
/// <param name="imageDescriptor">The <see cref="GifImageDescriptor"/>.</param>
/// <returns>The <see cref="T:byte[]"/></returns>
private byte[] ReadFrameIndices(GifImageDescriptor imageDescriptor) private byte[] ReadFrameIndices(GifImageDescriptor imageDescriptor)
{ {
int dataSize = this.currentStream.ReadByte(); int dataSize = this.currentStream.ReadByte();
@ -220,6 +256,11 @@
return indices; return indices;
} }
/// <summary>
/// Reads the local color table from the current frame.
/// </summary>
/// <param name="imageDescriptor">The <see cref="GifImageDescriptor"/>.</param>
/// <returns>The <see cref="T:byte[]"/></returns>
private byte[] ReadFrameLocalColorTable(GifImageDescriptor imageDescriptor) private byte[] ReadFrameLocalColorTable(GifImageDescriptor imageDescriptor)
{ {
byte[] localColorTable = null; byte[] localColorTable = null;
@ -234,10 +275,16 @@
return localColorTable; return localColorTable;
} }
/// <summary>
/// Reads the frames colors, mapping indices to colors.
/// </summary>
/// <param name="indices">The indexed pixels.</param>
/// <param name="colorTable">The color table containing the available colors.</param>
/// <param name="descriptor">The <see cref="GifImageDescriptor"/></param>
private void ReadFrameColors(byte[] indices, byte[] colorTable, GifImageDescriptor descriptor) private void ReadFrameColors(byte[] indices, byte[] colorTable, GifImageDescriptor descriptor)
{ {
int imageWidth = this.LogicalScreenDescriptor.Width; int imageWidth = this.logicalScreenDescriptor.Width;
int imageHeight = this.LogicalScreenDescriptor.Height; int imageHeight = this.logicalScreenDescriptor.Height;
if (this.currentFrame == null) if (this.currentFrame == null)
{ {
@ -246,51 +293,50 @@
byte[] lastFrame = null; byte[] lastFrame = null;
if (this.GraphicsControlExtension != null && if (this.graphicsControlExtension != null &&
this.GraphicsControlExtension.DisposalMethod == DisposalMethod.RestoreToPrevious) this.graphicsControlExtension.DisposalMethod == DisposalMethod.RestoreToPrevious)
{ {
lastFrame = new byte[imageWidth * imageHeight * 4]; lastFrame = new byte[imageWidth * imageHeight * 4];
Array.Copy(this.currentFrame, lastFrame, lastFrame.Length); Array.Copy(this.currentFrame, lastFrame, lastFrame.Length);
} }
int offset = 0, i = 0, index = -1; int offset, i = 0;
int interlacePass = 0; // The interlace pass
int iPass = 0; // the interlace pass int interlaceIncrement = 8; // The interlacing line increment
int iInc = 8; // the interlacing line increment int interlaceY = 0; // The current interlaced line
int iY = 0; // the current interlaced line
int writeY = 0; // the target y offset to write to
for (int y = descriptor.Top; y < descriptor.Top + descriptor.Height; y++) for (int y = descriptor.Top; y < descriptor.Top + descriptor.Height; y++)
{ {
// Check if this image is interlaced. // Check if this image is interlaced.
int writeY; // the target y offset to write to
if (descriptor.InterlaceFlag) if (descriptor.InterlaceFlag)
{ {
// If so then we read lines at predetermined offsets. // 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. // 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. // With each pass the number of offset lines changes and the starting line changes.
if (iY >= descriptor.Height) if (interlaceY >= descriptor.Height)
{ {
iPass++; interlacePass++;
switch (iPass) switch (interlacePass)
{ {
case 1: case 1:
iY = 4; interlaceY = 4;
break; break;
case 2: case 2:
iY = 2; interlaceY = 2;
iInc = 4; interlaceIncrement = 4;
break; break;
case 3: case 3:
iY = 1; interlaceY = 1;
iInc = 2; interlaceIncrement = 2;
break; break;
} }
} }
writeY = iY + descriptor.Top; writeY = interlaceY + descriptor.Top;
iY += iInc; interlaceY += interlaceIncrement;
} }
else else
{ {
@ -299,18 +345,18 @@
for (int x = descriptor.Left; x < descriptor.Left + descriptor.Width; x++) for (int x = descriptor.Left; x < descriptor.Left + descriptor.Width; x++)
{ {
offset = (writeY * imageWidth) + x; offset = ((writeY * imageWidth) + x) * 4;
int index = indices[i];
index = indices[i];
if (this.GraphicsControlExtension == null || if (this.graphicsControlExtension == null ||
this.GraphicsControlExtension.TransparencyFlag == false || this.graphicsControlExtension.TransparencyFlag == false ||
this.GraphicsControlExtension.TransparencyIndex != index) this.graphicsControlExtension.TransparencyIndex != index)
{ {
this.currentFrame[offset * 4 + 0] = colorTable[index * 3 + 2]; int indexOffset = index * 3;
this.currentFrame[offset * 4 + 1] = colorTable[index * 3 + 1]; this.currentFrame[offset + 0] = colorTable[indexOffset + 2];
this.currentFrame[offset * 4 + 2] = colorTable[index * 3 + 0]; this.currentFrame[offset + 1] = colorTable[indexOffset + 1];
this.currentFrame[offset * 4 + 3] = (byte)255; this.currentFrame[offset + 2] = colorTable[indexOffset + 0];
this.currentFrame[offset + 3] = 255;
} }
i++; i++;
@ -323,15 +369,15 @@
ImageBase currentImage; ImageBase currentImage;
if (this.image.Pixels == null) if (this.decodedImage.Pixels == null)
{ {
currentImage = this.image; currentImage = this.decodedImage;
currentImage.SetPixels(imageWidth, imageHeight, pixels); currentImage.SetPixels(imageWidth, imageHeight, pixels);
currentImage.Quality = colorTable.Length / 3; 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 else
@ -342,32 +388,32 @@
currentImage.SetPixels(imageWidth, imageHeight, pixels); currentImage.SetPixels(imageWidth, imageHeight, pixels);
currentImage.Quality = colorTable.Length / 3; 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 y = descriptor.Top; y < descriptor.Top + descriptor.Height; y++)
{ {
for (int x = descriptor.Left; x < descriptor.Left + descriptor.Width; x++) 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 + 0] = 0;
this.currentFrame[offset * 4 + 1] = 0; this.currentFrame[offset + 1] = 0;
this.currentFrame[offset * 4 + 2] = 0; this.currentFrame[offset + 2] = 0;
this.currentFrame[offset * 4 + 3] = 0; this.currentFrame[offset + 3] = 0;
} }
} }
} }
else if (this.GraphicsControlExtension.DisposalMethod == DisposalMethod.RestoreToPrevious) else if (this.graphicsControlExtension.DisposalMethod == DisposalMethod.RestoreToPrevious)
{ {
this.currentFrame = lastFrame; this.currentFrame = lastFrame;
} }

22
src/ImageProcessor/Formats/Gif/GifEncoder.cs

@ -10,7 +10,7 @@ namespace ImageProcessor.Formats
using System.Linq; using System.Linq;
/// <summary> /// <summary>
/// The Gif encoder /// Image encoder for writing image data to a stream in gif format.
/// </summary> /// </summary>
public class GifEncoder : IImageEncoder public class GifEncoder : IImageEncoder
{ {
@ -63,12 +63,12 @@ namespace ImageProcessor.Formats
quality = quality > 0 ? quality.Clamp(1, 256) : 256; quality = quality > 0 ? quality.Clamp(1, 256) : 256;
// Get the number of bits. // 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. // Write the LSD and check to see if we need a global color table.
// Always true just now. // Always true just now.
bool globalColor = this.WriteGlobalLogicalScreenDescriptor(image, stream, bitdepth); bool globalColor = this.WriteGlobalLogicalScreenDescriptor(image, stream, bitDepth);
QuantizedImage quantized = this.WriteColorTable(imageBase, stream, quality, bitdepth); QuantizedImage quantized = this.WriteColorTable(imageBase, stream, quality, bitDepth);
this.WriteGraphicalControlExtension(imageBase, stream); this.WriteGraphicalControlExtension(imageBase, stream);
this.WriteImageDescriptor(quantized, quality, stream); this.WriteImageDescriptor(quantized, quality, stream);
@ -238,13 +238,13 @@ namespace ImageProcessor.Formats
this.WriteShort(stream, image.Height); this.WriteShort(stream, image.Height);
// Calculate the quality. // Calculate the quality.
int bitdepth = this.GetBitsNeededForColorDepth(quality); int bitDepth = this.GetBitsNeededForColorDepth(quality);
// No LCT use GCT. // No LCT use GCT.
this.WriteByte(stream, 0); this.WriteByte(stream, 0);
// Write the image data.. // Write the image data.
this.WriteImageData(image, stream, bitdepth); this.WriteImageData(image, stream, bitDepth);
} }
/// <summary> /// <summary>
@ -264,19 +264,19 @@ namespace ImageProcessor.Formats
// Calculate the quality. // Calculate the quality.
int quality = this.Quality > 0 ? this.Quality : image.Quality; int quality = this.Quality > 0 ? this.Quality : image.Quality;
quality = quality > 0 ? quality.Clamp(1, 256) : 256; 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) int packed = 0x80 | // 1: Local color table flag = 1 (LCT used)
0x00 | // 2: Interlace flag 0 0x00 | // 2: Interlace flag 0
0x00 | // 3: Sort flag 0 0x00 | // 3: Sort flag 0
0 | // 4-5: Reserved 0 | // 4-5: Reserved
bitdepth - 1; bitDepth - 1;
this.WriteByte(stream, packed); this.WriteByte(stream, packed);
// Now immediately follow with the color table. // Now immediately follow with the color table.
QuantizedImage quantized = this.WriteColorTable(image, stream, quality, bitdepth); QuantizedImage quantized = this.WriteColorTable(image, stream, quality, bitDepth);
this.WriteImageData(quantized, stream, bitdepth); this.WriteImageData(quantized, stream, bitDepth);
} }
/// <summary> /// <summary>

57
src/ImageProcessor/Formats/Gif/LzwDecoder.cs

@ -1,12 +1,7 @@
// -------------------------------------------------------------------------------------------------------------------- // <copyright file="LzwDecoder.cs" company="James South">
// <copyright file="LzwDecoder.cs" company="James South"> // Copyright © James South and contributors.
// Copyright © James South and contributors. // Licensed under the Apache License, Version 2.0.
// Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
// <summary>
// Decompresses data using the LZW algorithms.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace ImageProcessor.Formats namespace ImageProcessor.Formats
{ {
@ -19,9 +14,9 @@ namespace ImageProcessor.Formats
internal sealed class LzwDecoder internal sealed class LzwDecoder
{ {
/// <summary> /// <summary>
/// The stack size. /// One more than the maximum value 12 bit integer.
/// </summary> /// </summary>
private const int StackSize = 4096; private const int MaxStackSize = 4096;
/// <summary> /// <summary>
/// The null code. /// The null code.
@ -37,18 +32,19 @@ namespace ImageProcessor.Formats
/// Initializes a new instance of the <see cref="LzwDecoder"/> class /// Initializes a new instance of the <see cref="LzwDecoder"/> class
/// and sets the stream, where the compressed data should be read from. /// and sets the stream, where the compressed data should be read from.
/// </summary> /// </summary>
/// <param name="stream">The stream. where to read from.</param> /// <param name="stream">The stream to read from.</param>
/// <exception cref="ArgumentNullException"><paramref name="stream"/> is null /// <exception cref="ArgumentNullException"><paramref name="stream"/> is null.</exception>
/// (Nothing in Visual Basic).</exception>
public LzwDecoder(Stream stream) public LzwDecoder(Stream stream)
{ {
Guard.NotNull(stream, "stream"); Guard.NotNull(stream, nameof(stream));
this.stream = stream; this.stream = stream;
} }
/// <summary> /// <summary>
/// Decodes and decompresses all pixel indices from the stream. /// Decodes and decompresses all pixel indices from the stream.
/// <remarks>
/// </remarks>
/// </summary> /// </summary>
/// <param name="width">The width of the pixel index array.</param> /// <param name="width">The width of the pixel index array.</param>
/// <param name="height">The height of the pixel index array.</param> /// <param name="height">The height of the pixel index array.</param>
@ -72,7 +68,7 @@ namespace ImageProcessor.Formats
// Calculate the available code. // Calculate the available code.
int availableCode = clearCode + 2; 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: 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. // TODO: Unfortunately I can't figure out the character encoding to translate from the original Chinese.
int code; // ÓÃÓÚ´æ´¢µ±Ç°µÄ±àÂëÖµ int code; // ÓÃÓÚ´æ´¢µ±Ç°µÄ±àÂëÖµ
@ -80,10 +76,9 @@ namespace ImageProcessor.Formats
int codeMask = (1 << codeSize) - 1; // ±íʾ±àÂëµÄ×î´óÖµ£¬Èç¹ûcodeSize=5,Ôòcode_mask=31 int codeMask = (1 << codeSize) - 1; // ±íʾ±àÂëµÄ×î´óÖµ£¬Èç¹ûcodeSize=5,Ôòcode_mask=31
int bits = 0; // ÔÚ±àÂëÁ÷ÖÐÊý¾ÝµÄ±£´æÐÎʽΪbyte£¬¶øÊµ¼Ê±àÂë¹ý³ÌÖÐÊÇÕÒʵ¼Ê±àÂëλÀ´´æ´¢µÄ£¬±ÈÈçµ±codeSize=5µÄʱºò£¬ÄÇôʵ¼ÊÉÏ5bitµÄÊý¾Ý¾ÍÓ¦¸Ã¿ÉÒÔ±íʾһ¸ö±àÂ룬ÕâÑùÈ¡³öÀ´µÄ1¸ö×ֽھ͸»ÓàÁË3¸öbit£¬Õâ3¸öbitÓÃÓں͵ڶþ¸ö×ֽڵĺóÁ½¸öbit½øÐÐ×éºÏ£¬ÔÙ´ÎÐγɱàÂëÖµ£¬Èç´ËÀàÍÆ int bits = 0; // ÔÚ±àÂëÁ÷ÖÐÊý¾ÝµÄ±£´æÐÎʽΪbyte£¬¶øÊµ¼Ê±àÂë¹ý³ÌÖÐÊÇÕÒʵ¼Ê±àÂëλÀ´´æ´¢µÄ£¬±ÈÈçµ±codeSize=5µÄʱºò£¬ÄÇôʵ¼ÊÉÏ5bitµÄÊý¾Ý¾ÍÓ¦¸Ã¿ÉÒÔ±íʾһ¸ö±àÂ룬ÕâÑùÈ¡³öÀ´µÄ1¸ö×ֽھ͸»ÓàÁË3¸öbit£¬Õâ3¸öbitÓÃÓں͵ڶþ¸ö×ֽڵĺóÁ½¸öbit½øÐÐ×éºÏ£¬ÔÙ´ÎÐγɱàÂëÖµ£¬Èç´ËÀàÍÆ
int[] prefix = new int[MaxStackSize]; // ÓÃÓÚ±£´æÇ°×ºµÄ¼¯ºÏ
int[] prefix = new int[StackSize]; // ÓÃÓÚ±£´æÇ°×ºµÄ¼¯ºÏ int[] suffix = new int[MaxStackSize]; // ÓÃÓÚ±£´æºó׺
int[] suffix = new int[StackSize]; // ÓÃÓÚ±£´æºó׺ int[] pixelStatck = new int[MaxStackSize + 1]; // ÓÃÓÚÁÙʱ±£´æÊý¾ÝÁ÷
int[] pixelStatck = new int[StackSize + 1]; // ÓÃÓÚÁÙʱ±£´æÊý¾ÝÁ÷
int top = 0; int top = 0;
int count = 0; // ÔÚÏÂÃæµÄÑ­»·ÖУ¬Ã¿´Î»á»ñȡһ¶¨Á¿µÄ±àÂëµÄ×Ö½ÚÊý×飬¶ø´¦ÀíÕâЩÊý×éµÄʱºòÐèÒª1¸ö¸ö×Ö½ÚÀ´´¦Àí£¬count¾ÍÊDZíʾ»¹Òª´¦ÀíµÄ×Ö½ÚÊýÄ¿ int count = 0; // ÔÚÏÂÃæµÄÑ­»·ÖУ¬Ã¿´Î»á»ñȡһ¶¨Á¿µÄ±àÂëµÄ×Ö½ÚÊý×飬¶ø´¦ÀíÕâЩÊý×éµÄʱºòÐèÒª1¸ö¸ö×Ö½ÚÀ´´¦Àí£¬count¾ÍÊDZíʾ»¹Òª´¦ÀíµÄ×Ö½ÚÊýÄ¿
@ -92,7 +87,6 @@ namespace ImageProcessor.Formats
int data = 0; // ±íʾµ±Ç°´¦ÀíµÄÊý¾ÝµÄÖµ int data = 0; // ±íʾµ±Ç°´¦ÀíµÄÊý¾ÝµÄÖµ
int first = 0; // Ò»¸ö×Ö·û´®ÖصĵÚÒ»¸ö×Ö½Ú int first = 0; // Ò»¸ö×Ö·û´®ÖصĵÚÒ»¸ö×Ö½Ú
int inCode; // ÔÚlzwÖУ¬Èç¹ûÈÏʶÁËÒ»¸ö±àÂëËù´ú±íµÄÊý¾Ýentry£¬Ôò½«±àÂë×÷ΪÏÂÒ»´ÎµÄprefix£¬´Ë´¦inCode´ú±í´«µÝ¸øÏÂÒ»´Î×÷Ϊǰ׺µÄ±àÂëÖµ
// ÏÈÉú³ÉÔªÊý¾ÝµÄǰ׺¼¯ºÏºÍºó׺¼¯ºÏ£¬ÔªÊý¾ÝµÄǰ׺¾ùΪ0£¬¶øºó׺ÓëÔªÊý¾ÝÏàµÈ£¬Í¬Ê±±àÂëÒ²ÓëÔªÊý¾ÝÏàµÈ // ÏÈÉú³ÉÔªÊý¾ÝµÄǰ׺¼¯ºÏºÍºó׺¼¯ºÏ£¬ÔªÊý¾ÝµÄǰ׺¾ùΪ0£¬¶øºó׺ÓëÔªÊý¾ÝÏàµÈ£¬Í¬Ê±±àÂëÒ²ÓëÔªÊý¾ÝÏàµÈ
for (code = 0; code < clearCode; code++) for (code = 0; code < clearCode; code++)
@ -129,8 +123,12 @@ namespace ImageProcessor.Formats
} }
// »ñÈ¡±¾´ÎÒª´¦ÀíµÄÊý¾ÝµÄÖµ // »ñÈ¡±¾´ÎÒª´¦ÀíµÄÊý¾ÝµÄÖµ
data += buffer[bi] << bits; // ´Ë´¦ÎªºÎÒªÒÆÎ»ÄØ£¬±ÈÈçµÚÒ»´Î´¦ÀíÁË1¸ö×Ö½ÚΪ176£¬µÚÒ»´ÎÖ»Òª´¦Àí5bit¾Í¹»ÁË£¬Ê£ÏÂ3bitÁô¸øÏ¸ö×Ö½Ú½øÐÐ×éºÏ¡£Ò²¾ÍÊǵڶþ¸ö×ֽڵĺóÁ½Î»+µÚÒ»¸ö×Ö½ÚµÄǰÈýλ×é³ÉµÚ¶þ´ÎÊä³öÖµ if (buffer != null)
bits += 8; // ±¾´ÎÓÖ´¦ÀíÁËÒ»¸ö×Ö½Ú£¬ËùÒÔÐèÒª+8 {
data += buffer[bi] << bits; // ´Ë´¦ÎªºÎÒªÒÆÎ»ÄØ£¬±ÈÈçµÚÒ»´Î´¦ÀíÁË1¸ö×Ö½ÚΪ176£¬µÚÒ»´ÎÖ»Òª´¦Àí5bit¾Í¹»ÁË£¬Ê£ÏÂ3bitÁô¸øÏ¸ö×Ö½Ú½øÐÐ×éºÏ¡£Ò²¾ÍÊǵڶþ¸ö×ֽڵĺóÁ½Î»+µÚÒ»¸ö×Ö½ÚµÄǰÈýλ×é³ÉµÚ¶þ´ÎÊä³öÖµ
}
bits += 8; // ±¾´ÎÓÖ´¦ÀíÁËÒ»¸ö×Ö½Ú£¬ËùÒÔÐèÒª+8
bi++; // ½«´¦ÀíÏÂÒ»¸ö×Ö½Ú bi++; // ½«´¦ÀíÏÂÒ»¸ö×Ö½Ú
count--; // ÒѾ­´¦Àí¹ýµÄ×Ö½ÚÊý+1 count--; // ÒѾ­´¦Àí¹ýµÄ×Ö½ÚÊý+1
continue; continue;
@ -145,7 +143,7 @@ namespace ImageProcessor.Formats
// ÏÂÃæ¸ù¾Ý»ñÈ¡µÄcodeÖµÀ´½øÐд¦Àí // ÏÂÃæ¸ù¾Ý»ñÈ¡µÄcodeÖµÀ´½øÐд¦Àí
if (code > availableCode || code == endCode) if (code > availableCode || code == endCode)
{ {
// µ±±àÂëÖµ´óÓÚ×î´ó±àÂëÖµ»òÕßΪ½áÊø±ê¼ÇµÄʱºò£¬Í£Ö¹´¦Àí // µ±±àÂëÖµ´óÓÚ×î´ó±àÂëÖµ»òÕßΪ½áÊø±ê¼ÇµÄʱºò£¬Í£Ö¹´¦Àí
break; break;
} }
@ -179,7 +177,7 @@ namespace ImageProcessor.Formats
continue; continue;
} }
inCode = code; int inCode = code; // ÔÚlzwÖУ¬Èç¹ûÈÏʶÁËÒ»¸ö±àÂëËù´ú±íµÄÊý¾Ýentry£¬Ôò½«±àÂë×÷ΪÏÂÒ»´ÎµÄprefix£¬´Ë´¦inCode´ú±í´«µÝ¸øÏÂÒ»´Î×÷Ϊǰ׺µÄ±àÂëÖµ
if (code == availableCode) if (code == availableCode)
{ {
// Èç¹ûµ±Ç°±àÂëºÍ±¾´ÎÓ¦¸ÃÉú³ÉµÄ±àÂëÏàͬ // Èç¹ûµ±Ç°±àÂëºÍ±¾´ÎÓ¦¸ÃÉú³ÉµÄ±àÂëÏàͬ
@ -201,8 +199,9 @@ namespace ImageProcessor.Formats
// »ñÈ¡ÏÂÒ»¸öÊý¾Ý // »ñÈ¡ÏÂÒ»¸öÊý¾Ý
pixelStatck[top++] = suffix[code]; pixelStatck[top++] = suffix[code];
// Fix for Gifs that have "deferred clear code" as per here : https://bugzilla.mozilla.org/show_bug.cgi?id=55918 // Fix for Gifs that have "deferred clear code" as per here :
if (availableCode < StackSize) // https://bugzilla.mozilla.org/show_bug.cgi?id=55918
if (availableCode < MaxStackSize)
{ {
// ÉèÖõ±Ç°Ó¦¸Ã±àÂëλÖõÄǰ׺ // ÉèÖõ±Ç°Ó¦¸Ã±àÂëλÖõÄǰ׺
prefix[availableCode] = oldCode; prefix[availableCode] = oldCode;
@ -212,7 +211,7 @@ namespace ImageProcessor.Formats
// Ï´ÎÓ¦¸ÃµÃµ½µÄ±àÂëÖµ // Ï´ÎÓ¦¸ÃµÃµ½µÄ±àÂëÖµ
availableCode++; availableCode++;
if (availableCode == codeMask + 1 && availableCode < StackSize) if (availableCode == codeMask + 1 && availableCode < MaxStackSize)
{ {
// Ôö¼Ó±àÂëλÊý // Ôö¼Ó±àÂëλÊý
codeSize++; codeSize++;
@ -229,12 +228,10 @@ namespace ImageProcessor.Formats
// »ØËݵ½ÉÏÒ»¸ö´¦ÀíλÖà // »ØËݵ½ÉÏÒ»¸ö´¦ÀíλÖÃ
top--; top--;
// »ñȡԪÊý¾Ý // »ñȡԪÊý¾Ý
pixels[xyz++] = (byte)pixelStatck[top]; pixels[xyz++] = (byte)pixelStatck[top];
} }
#endregion
return pixels; return pixels;
} }

20
src/ImageProcessor/Formats/Gif/LzwEncoder.cs

@ -1,16 +1,11 @@
// -------------------------------------------------------------------------------------------------------------------- // <copyright file="LzwEncoder.cs" company="James South">
// <copyright file="LzwEncoder.cs" company="James South"> // Copyright © James South and contributors.
// Copyright © James South and contributors. // Licensed under the Apache License, Version 2.0.
// Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
// <summary>
// Encodes an image pixels used on a method based on LZW compression.
// <see href="http://matthewflickinger.com/lab/whatsinagif/lzw_image_data.asp"/>
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace ImageProcessor.Formats namespace ImageProcessor.Formats
{ {
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
@ -52,8 +47,15 @@ namespace ImageProcessor.Formats
this.initDataSize = this.colorDepth; this.initDataSize = this.colorDepth;
} }
/// <summary>
/// Encodes the compressed indexed pixel data to the given stream.
/// </summary>
/// <param name="stream">The stream to add the data to.</param>
/// <exception cref="ArgumentNullException"><paramref name="stream"/> is null.</exception>
public void Encode(Stream stream) public void Encode(Stream stream)
{ {
Guard.NotNull(stream, nameof(stream));
// Whether it is a first step. // Whether it is a first step.
bool first = true; bool first = true;

11
src/ImageProcessor/Formats/Gif/Quantizer/IQuantizer.cs

@ -1,12 +1,7 @@
// -------------------------------------------------------------------------------------------------------------------- // <copyright file="IQuantizer.cs" company="James South">
// <copyright file="IQuantizer.cs" company="James South"> // Copyright © James South and contributors.
// Copyright © James South and contributors. // Licensed under the Apache License, Version 2.0.
// Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
// <summary>
// Provides methods for allowing quantization of images pixels.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace ImageProcessor.Formats namespace ImageProcessor.Formats
{ {

12
src/ImageProcessor/Formats/Gif/Quantizer/OctreeQuantizer.cs

@ -1,13 +1,7 @@
// -------------------------------------------------------------------------------------------------------------------- // <copyright file="OctreeQuantizer.cs" company="James South">
// <copyright file="OctreeQuantizer.cs" company="James South"> // Copyright © James South and contributors.
// Copyright © James South and contributors. // Licensed under the Apache License, Version 2.0.
// Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
// <summary>
// Encapsulates methods to calculate the color palette of an image using an Octree pattern.
// <see href="http://msdn.microsoft.com/en-us/library/aa479306.aspx" />
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace ImageProcessor.Formats namespace ImageProcessor.Formats
{ {

11
src/ImageProcessor/Formats/Gif/Quantizer/QuantizedImage.cs

@ -1,12 +1,7 @@
// -------------------------------------------------------------------------------------------------------------------- // <copyright file="QuantizedImage.cs" company="James South">
// <copyright file="QuantizedImage.cs" company="James South"> // Copyright © James South and contributors.
// Copyright © James South and contributors. // Licensed under the Apache License, Version 2.0.
// Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
// <summary>
// Provides methods for allowing quantization of images pixels.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace ImageProcessor.Formats namespace ImageProcessor.Formats
{ {

11
src/ImageProcessor/Formats/Gif/Quantizer/Quantizer.cs

@ -1,12 +1,7 @@
// -------------------------------------------------------------------------------------------------------------------- // <copyright file="Quantizer.cs" company="James South">
// <copyright file="Quantizer.cs" company="James South"> // Copyright © James South and contributors.
// Copyright © James South and contributors. // Licensed under the Apache License, Version 2.0.
// Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
// <summary>
// Encapsulates methods to calculate the color palette of an image.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace ImageProcessor.Formats namespace ImageProcessor.Formats
{ {

4
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/

12
src/ImageProcessor/Formats/Gif/Sections/GifGraphicsControlExtension.cs

@ -1,13 +1,7 @@
// -------------------------------------------------------------------------------------------------------------------- // <copyright file="GifGraphicsControlExtension.cs" company="James South">
// <copyright file="GifGraphicsControlExtension.cs" company="James South"> // Copyright © James South and contributors.
// Copyright © James South and contributors. // Licensed under the Apache License, Version 2.0.
// Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
// <summary>
// The Graphic Control Extension contains parameters used when
// processing a graphic rendering block.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace ImageProcessor.Formats namespace ImageProcessor.Formats
{ {

14
src/ImageProcessor/Formats/Gif/Sections/GifImageDescriptor.cs

@ -1,15 +1,7 @@
// -------------------------------------------------------------------------------------------------------------------- // <copyright file="GifImageDescriptor.cs" company="James South">
// <copyright file="GifImageDescriptor.cs" company="James South"> // Copyright © James South and contributors.
// Copyright © James South and contributors. // Licensed under the Apache License, Version 2.0.
// Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
// <summary>
// 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.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace ImageProcessor.Formats namespace ImageProcessor.Formats
{ {

45
src/ImageProcessor/Formats/Png/PngDecoderCore.cs

@ -57,38 +57,22 @@ namespace ImageProcessor.Formats
{ {
ColorTypes.Add( ColorTypes.Add(
0, 0,
new PngColorTypeInformation( new PngColorTypeInformation(1, new[] { 1, 2, 4, 8 }, (p, a) => new GrayscaleReader(false)));
1,
new[] { 1, 2, 4, 8 },
(p, a) => new GrayscaleReader(false)));
ColorTypes.Add( ColorTypes.Add(
2, 2,
new PngColorTypeInformation( new PngColorTypeInformation(3, new[] { 8 }, (p, a) => new TrueColorReader(false)));
3,
new[] { 8 },
(p, a) => new TrueColorReader(false)));
ColorTypes.Add( ColorTypes.Add(
3, 3,
new PngColorTypeInformation( new PngColorTypeInformation(1, new[] { 1, 2, 4, 8 }, (p, a) => new PaletteIndexReader(p, a)));
1,
new[] { 1, 2, 4, 8 },
(p, a) => new PaletteIndexReader(p, a)));
ColorTypes.Add( ColorTypes.Add(
4, 4,
new PngColorTypeInformation( new PngColorTypeInformation(2, new[] { 8 }, (p, a) => new GrayscaleReader(true)));
2,
new[] { 8 },
(p, a) => new GrayscaleReader(true)));
ColorTypes.Add( ColorTypes.Add(6,
6, new PngColorTypeInformation(4, new[] { 8 }, (p, a) => new TrueColorReader(true)));
new PngColorTypeInformation(
4,
new[] { 8 },
(p, a) => new TrueColorReader(true)));
} }
/// <summary> /// <summary>
@ -334,7 +318,7 @@ namespace ImageProcessor.Formats
colorReader.ReadScanline(currentScanline, pixels, this.header); colorReader.ReadScanline(currentScanline, pixels, this.header);
column = -1; column = -1;
Utils.Swap(ref currentScanline, ref lastScanline); this.Swap(ref currentScanline, ref lastScanline);
} }
} }
} }
@ -544,5 +528,20 @@ namespace ImageProcessor.Formats
return numBytes; return numBytes;
} }
/// <summary>
/// Swaps two references.
/// </summary>
/// <typeparam name="TRef">The type of the references to swap.</typeparam>
/// <param name="lhs">The first reference.</param>
/// <param name="rhs">The second reference.</param>
private void Swap<TRef>(ref TRef lhs, ref TRef rhs)
where TRef : class
{
TRef tmp = lhs;
lhs = rhs;
rhs = tmp;
}
} }
} }

2
src/ImageProcessor/ImageProcessor.csproj

@ -45,7 +45,6 @@
<Compile Include="Colors\YCbCr.cs" /> <Compile Include="Colors\YCbCr.cs" />
<Compile Include="Common\Extensions\ByteExtensions.cs" /> <Compile Include="Common\Extensions\ByteExtensions.cs" />
<Compile Include="Common\Extensions\ComparableExtensions.cs" /> <Compile Include="Common\Extensions\ComparableExtensions.cs" />
<Compile Include="Common\Helpers\Utils.cs" />
<Compile Include="Formats\Bmp\BmpCompression.cs" /> <Compile Include="Formats\Bmp\BmpCompression.cs" />
<Compile Include="Formats\Bmp\BmpFileHeader.cs" /> <Compile Include="Formats\Bmp\BmpFileHeader.cs" />
<Compile Include="Formats\Bmp\BmpInfoHeader.cs" /> <Compile Include="Formats\Bmp\BmpInfoHeader.cs" />
@ -176,6 +175,7 @@
</Reference> </Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="Formats\Gif\README.md" />
<None Include="Formats\Jpg\README.md" /> <None Include="Formats\Jpg\README.md" />
<None Include="packages.config" /> <None Include="packages.config" />
<AdditionalFiles Include="stylecop.json" /> <AdditionalFiles Include="stylecop.json" />

Loading…
Cancel
Save