diff --git a/src/ImageSharp.Formats.Gif/GifDecoderCore.cs b/src/ImageSharp.Formats.Gif/GifDecoderCore.cs
index 9c367c15a6..e6f7b6136f 100644
--- a/src/ImageSharp.Formats.Gif/GifDecoderCore.cs
+++ b/src/ImageSharp.Formats.Gif/GifDecoderCore.cs
@@ -321,12 +321,14 @@ namespace ImageSharp.Formats
if (this.previousFrame == null)
{
- image = this.decodedImage;
-
this.decodedImage.MetaData.Quality = colorTableLength / 3;
// This initializes the image to become fully transparent because the alpha channel is zero.
- image.InitPixels(imageWidth, imageHeight);
+ this.decodedImage.InitPixels(imageWidth, imageHeight);
+
+ this.SetFrameDelay(this.decodedImage.MetaData);
+
+ image = this.decodedImage;
}
else
{
@@ -338,6 +340,8 @@ namespace ImageSharp.Formats
currentFrame = this.previousFrame.Clone();
+ this.SetFrameDelay(currentFrame.MetaData);
+
image = currentFrame;
this.RestoreToBackground(image);
@@ -345,11 +349,6 @@ namespace ImageSharp.Formats
this.decodedImage.Frames.Add(currentFrame);
}
- if (this.graphicsControlExtension != null && this.graphicsControlExtension.DelayTime > 0)
- {
- image.FrameDelay = this.graphicsControlExtension.DelayTime;
- }
-
int i = 0;
int interlacePass = 0; // The interlace pass
int interlaceIncrement = 8; // The interlacing line increment
@@ -465,5 +464,17 @@ namespace ImageSharp.Formats
this.restoreArea = null;
}
+
+ ///
+ /// Sets the frame delay in the metadata.
+ ///
+ /// The meta data.
+ private void SetFrameDelay(IMetaData metaData)
+ {
+ if (this.graphicsControlExtension != null && this.graphicsControlExtension.DelayTime > 0)
+ {
+ metaData.FrameDelay = this.graphicsControlExtension.DelayTime;
+ }
+ }
}
}
\ No newline at end of file
diff --git a/src/ImageSharp.Formats.Gif/GifEncoderCore.cs b/src/ImageSharp.Formats.Gif/GifEncoderCore.cs
index c5923c1a54..80c9ee36bc 100644
--- a/src/ImageSharp.Formats.Gif/GifEncoderCore.cs
+++ b/src/ImageSharp.Formats.Gif/GifEncoderCore.cs
@@ -229,14 +229,41 @@ namespace ImageSharp.Formats
}
}
+ ///
+ /// Writes the graphics control extension to the stream.
+ ///
+ /// The pixel format.
+ /// The to encode.
+ /// The stream to write to.
+ /// The index of the color in the color palette to make transparent.
+ private void WriteGraphicalControlExtension(Image image, EndianBinaryWriter writer, int transparencyIndex)
+ where TColor : struct, IPackedPixel, IEquatable
+ {
+ this.WriteGraphicalControlExtension(image, image.MetaData, writer, transparencyIndex);
+ }
+
+ ///
+ /// Writes the graphics control extension to the stream.
+ ///
+ /// The pixel format.
+ /// The to encode.
+ /// The stream to write to.
+ /// The index of the color in the color palette to make transparent.
+ private void WriteGraphicalControlExtension(ImageFrame imageFrame, EndianBinaryWriter writer, int transparencyIndex)
+ where TColor : struct, IPackedPixel, IEquatable
+ {
+ this.WriteGraphicalControlExtension(imageFrame, imageFrame.MetaData, writer, transparencyIndex);
+ }
+
///
/// Writes the graphics control extension to the stream.
///
/// The pixel format.
/// The to encode.
+ /// The metadata of the image or frame.
/// The stream to write to.
/// The index of the color in the color palette to make transparent.
- private void WriteGraphicalControlExtension(ImageBase image, EndianBinaryWriter writer, int transparencyIndex)
+ private void WriteGraphicalControlExtension(ImageBase image, IMetaData metaData, EndianBinaryWriter writer, int transparencyIndex)
where TColor : struct, IPackedPixel, IEquatable
{
// TODO: Check transparency logic.
@@ -250,7 +277,7 @@ namespace ImageSharp.Formats
DisposalMethod = disposalMethod,
TransparencyFlag = hasTransparent,
TransparencyIndex = transparencyIndex,
- DelayTime = image.FrameDelay
+ DelayTime = metaData.FrameDelay
};
// Write the intro.
diff --git a/src/ImageSharp/Image/IImageBase.cs b/src/ImageSharp/Image/IImageBase.cs
index effbd60063..707fea235d 100644
--- a/src/ImageSharp/Image/IImageBase.cs
+++ b/src/ImageSharp/Image/IImageBase.cs
@@ -15,14 +15,6 @@ namespace ImageSharp
///
Rectangle Bounds { get; }
- ///
- /// Gets or sets the frame delay for animated images.
- /// If not 0, this field specifies the number of hundredths (1/100) of a second to
- /// wait before continuing with the processing of the Data Stream.
- /// The clock starts ticking immediately after the graphic is rendered.
- ///
- int FrameDelay { get; set; }
-
///
/// Gets or sets the maximum allowable width in pixels.
///
diff --git a/src/ImageSharp/Image/IImageFrame.cs b/src/ImageSharp/Image/IImageFrame.cs
new file mode 100644
index 0000000000..bf3261d93c
--- /dev/null
+++ b/src/ImageSharp/Image/IImageFrame.cs
@@ -0,0 +1,18 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp
+{
+ ///
+ /// Encapsulates the basic properties and methods required to manipulate images.
+ ///
+ internal interface IImageFrame : IImageBase
+ {
+ ///
+ /// Gets the meta data of the image.
+ ///
+ ImageFrameMetaData MetaData { get; }
+ }
+}
\ No newline at end of file
diff --git a/src/ImageSharp/Image/ImageBase{TColor}.cs b/src/ImageSharp/Image/ImageBase{TColor}.cs
index 6fcd7a3b7f..fd82f77308 100644
--- a/src/ImageSharp/Image/ImageBase{TColor}.cs
+++ b/src/ImageSharp/Image/ImageBase{TColor}.cs
@@ -110,9 +110,6 @@ namespace ImageSharp
///
public Rectangle Bounds => new Rectangle(0, 0, this.Width, this.Height);
- ///
- public int FrameDelay { get; set; }
-
///
/// Gets the configuration providing initialization code which allows extending the library.
///
@@ -187,7 +184,6 @@ namespace ImageSharp
{
Debug.Assert(other != null);
- this.FrameDelay = other.FrameDelay;
this.Configuration = other.Configuration;
}
diff --git a/src/ImageSharp/Image/ImageFrame{TColor}.cs b/src/ImageSharp/Image/ImageFrame{TColor}.cs
index b06b10bc49..02e5b71618 100644
--- a/src/ImageSharp/Image/ImageFrame{TColor}.cs
+++ b/src/ImageSharp/Image/ImageFrame{TColor}.cs
@@ -13,7 +13,7 @@ namespace ImageSharp
/// Represents a single frame in a animation.
///
/// The pixel format.
- public class ImageFrame : ImageBase
+ public class ImageFrame : ImageBase, IImageFrame
where TColor : struct, IPackedPixel, IEquatable
{
///
@@ -38,6 +38,11 @@ namespace ImageSharp
{
}
+ ///
+ /// Gets the meta data of the frame.
+ ///
+ public ImageFrameMetaData MetaData { get; private set; } = new ImageFrameMetaData();
+
///
public override string ToString()
{
@@ -87,5 +92,18 @@ namespace ImageSharp
{
return new ImageFrame(this);
}
+
+ ///
+ /// Copies the properties from the other .
+ ///
+ ///
+ /// The other to copy the properties from.
+ ///
+ private void CopyProperties(IImageFrame other)
+ {
+ base.CopyProperties(other);
+
+ this.MetaData = new ImageFrameMetaData(other.MetaData);
+ }
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/Metadata/IMetaData.cs b/src/ImageSharp/Metadata/IMetaData.cs
new file mode 100644
index 0000000000..38fd313493
--- /dev/null
+++ b/src/ImageSharp/Metadata/IMetaData.cs
@@ -0,0 +1,21 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp
+{
+ ///
+ /// Encapsulates the metadata of an image frame.
+ ///
+ internal interface IMetaData
+ {
+ ///
+ /// Gets or sets the frame delay for animated images.
+ /// If not 0, this field specifies the number of hundredths (1/100) of a second to
+ /// wait before continuing with the processing of the Data Stream.
+ /// The clock starts ticking immediately after the graphic is rendered.
+ ///
+ int FrameDelay { get; set; }
+ }
+}
diff --git a/src/ImageSharp/Metadata/ImageFrameMetaData.cs b/src/ImageSharp/Metadata/ImageFrameMetaData.cs
new file mode 100644
index 0000000000..c2277686f1
--- /dev/null
+++ b/src/ImageSharp/Metadata/ImageFrameMetaData.cs
@@ -0,0 +1,44 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp
+{
+ using System.Diagnostics;
+
+ ///
+ /// Encapsulates the metadata of an image frame.
+ ///
+ public sealed class ImageFrameMetaData : IMetaData
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ internal ImageFrameMetaData()
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class
+ /// by making a copy from other metadata.
+ ///
+ ///
+ /// The other to create this instance from.
+ ///
+ internal ImageFrameMetaData(ImageFrameMetaData other)
+ {
+ Debug.Assert(other != null);
+
+ this.FrameDelay = other.FrameDelay;
+ }
+
+ ///
+ /// Gets or sets the frame delay for animated images.
+ /// If not 0, this field specifies the number of hundredths (1/100) of a second to
+ /// wait before continuing with the processing of the Data Stream.
+ /// The clock starts ticking immediately after the graphic is rendered.
+ ///
+ public int FrameDelay { get; set; }
+ }
+}
diff --git a/src/ImageSharp/Metadata/ImageMetaData.cs b/src/ImageSharp/Metadata/ImageMetaData.cs
index 30bd2c348e..a38899840e 100644
--- a/src/ImageSharp/Metadata/ImageMetaData.cs
+++ b/src/ImageSharp/Metadata/ImageMetaData.cs
@@ -11,7 +11,7 @@ namespace ImageSharp
///
/// Encapsulates the metadata of an image.
///
- public sealed class ImageMetaData
+ public sealed class ImageMetaData : IMetaData
{
///
/// The default horizontal resolution value (dots per inch) in x direction.
@@ -51,6 +51,8 @@ namespace ImageSharp
this.HorizontalResolution = other.HorizontalResolution;
this.VerticalResolution = other.VerticalResolution;
this.Quality = other.Quality;
+ this.FrameDelay = other.FrameDelay;
+ this.RepeatCount = other.RepeatCount;
foreach (ImageProperty property in other.Properties)
{
@@ -110,6 +112,14 @@ namespace ImageSharp
///
public ExifProfile ExifProfile { get; set; }
+ ///
+ /// Gets or sets the frame delay for animated images.
+ /// If not 0, this field specifies the number of hundredths (1/100) of a second to
+ /// wait before continuing with the processing of the Data Stream.
+ /// The clock starts ticking immediately after the graphic is rendered.
+ ///
+ public int FrameDelay { get; set; }
+
///
/// Gets the list of properties for storing meta information about this image.
///
diff --git a/tests/ImageSharp.Tests/Metadata/ImageFrameMetaDataTests.cs b/tests/ImageSharp.Tests/Metadata/ImageFrameMetaDataTests.cs
new file mode 100644
index 0000000000..24dd2eac56
--- /dev/null
+++ b/tests/ImageSharp.Tests/Metadata/ImageFrameMetaDataTests.cs
@@ -0,0 +1,26 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp.Tests
+{
+ using Xunit;
+
+ ///
+ /// Tests the class.
+ ///
+ public class ImageFrameMetaDataTests
+ {
+ [Fact]
+ public void ConstructorImageFrameMetaData()
+ {
+ ImageFrameMetaData metaData = new ImageFrameMetaData();
+ metaData.FrameDelay = 42;
+
+ ImageFrameMetaData clone = new ImageFrameMetaData(metaData);
+
+ Assert.Equal(42, clone.FrameDelay);
+ }
+ }
+}
diff --git a/tests/ImageSharp.Tests/Metadata/ImageMetaDataTests.cs b/tests/ImageSharp.Tests/Metadata/ImageMetaDataTests.cs
new file mode 100644
index 0000000000..9034b88c09
--- /dev/null
+++ b/tests/ImageSharp.Tests/Metadata/ImageMetaDataTests.cs
@@ -0,0 +1,42 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp.Tests
+{
+ using Xunit;
+
+ ///
+ /// Tests the class.
+ ///
+ public class ImageMetaDataTests
+ {
+ [Fact]
+ public void ConstructorImageMetaData()
+ {
+ ImageMetaData metaData = new ImageMetaData();
+
+ ExifProfile exifProfile = new ExifProfile();
+ ImageProperty imageProperty = new ImageProperty("name", "value");
+
+ metaData.ExifProfile = exifProfile;
+ metaData.FrameDelay = 42;
+ metaData.HorizontalResolution = 4;
+ metaData.VerticalResolution = 2;
+ metaData.Properties.Add(imageProperty);
+ metaData.Quality = 24;
+ metaData.RepeatCount = 1;
+
+ ImageMetaData clone = new ImageMetaData(metaData);
+
+ Assert.Equal(exifProfile.ToByteArray(), clone.ExifProfile.ToByteArray());
+ Assert.Equal(42, clone.FrameDelay);
+ Assert.Equal(4, clone.HorizontalResolution);
+ Assert.Equal(2, clone.VerticalResolution);
+ Assert.Equal(imageProperty, clone.Properties[0]);
+ Assert.Equal(24, clone.Quality);
+ Assert.Equal(1, clone.RepeatCount);
+ }
+ }
+}