diff --git a/src/ImageProcessorCore/GenericImage.cs b/src/ImageProcessorCore/GenericImage.cs
new file mode 100644
index 0000000000..b0408513ac
--- /dev/null
+++ b/src/ImageProcessorCore/GenericImage.cs
@@ -0,0 +1,261 @@
+
+
+namespace ImageProcessorCore
+{
+ using System.IO;
+ using System.Text;
+
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+
+ using ImageProcessorCore.Formats;
+
+ ///
+ /// Encapsulates an image, which consists of the pixel data for a graphics image and its attributes.
+ ///
+ ///
+ /// The image data is always stored in RGBA format, where the red, green, blue, and
+ /// alpha values are floating point numbers.
+ ///
+ public abstract class GenericImage : ImageBase
+ where TPacked : IPackedVector
+ {
+ ///
+ /// The default horizontal resolution value (dots per inch) in x direction.
+ /// The default value is 96 dots per inch.
+ ///
+ public const double DefaultHorizontalResolution = 96;
+
+ ///
+ /// The default vertical resolution value (dots per inch) in y direction.
+ /// The default value is 96 dots per inch.
+ ///
+ public const double DefaultVerticalResolution = 96;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ protected GenericImage()
+ {
+ this.CurrentImageFormat = Bootstrapper.Instance.ImageFormats.First(f => f.GetType() == typeof(PngFormat));
+ }
+
+ ///
+ /// Initializes a new instance of the class
+ /// with the height and the width of the image.
+ ///
+ /// The width of the image in pixels.
+ /// The height of the image in pixels.
+ protected GenericImage(int width, int height)
+ : base(width, height)
+ {
+ this.CurrentImageFormat = Bootstrapper.Instance.ImageFormats.First(f => f.GetType() == typeof(PngFormat));
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ /// The stream containing image information.
+ ///
+ /// Thrown if the is null.
+ protected GenericImage(Stream stream)
+ {
+ Guard.NotNull(stream, nameof(stream));
+ this.Load(stream);
+ }
+
+ ///
+ /// Gets a list of supported image formats.
+ ///
+ public IReadOnlyCollection Formats { get; } = Bootstrapper.Instance.ImageFormats;
+
+ ///
+ /// Gets or sets the resolution of the image in x- direction. It is defined as
+ /// number of dots per inch and should be an positive value.
+ ///
+ /// The density of the image in x- direction.
+ public double HorizontalResolution { get; set; } = DefaultHorizontalResolution;
+
+ ///
+ /// Gets or sets the resolution of the image in y- direction. It is defined as
+ /// number of dots per inch and should be an positive value.
+ ///
+ /// The density of the image in y- direction.
+ public double VerticalResolution { get; set; } = DefaultVerticalResolution;
+
+ ///
+ /// Gets the width of the image in inches. It is calculated as the width of the image
+ /// in pixels multiplied with the density. When the density is equals or less than zero
+ /// the default value is used.
+ ///
+ /// The width of the image in inches.
+ public double InchWidth
+ {
+ get
+ {
+ double resolution = this.HorizontalResolution;
+
+ if (resolution <= 0)
+ {
+ resolution = DefaultHorizontalResolution;
+ }
+
+ return this.Width / resolution;
+ }
+ }
+
+ ///
+ /// Gets the height of the image in inches. It is calculated as the height of the image
+ /// in pixels multiplied with the density. When the density is equals or less than zero
+ /// the default value is used.
+ ///
+ /// The height of the image in inches.
+ public double InchHeight
+ {
+ get
+ {
+ double resolution = this.VerticalResolution;
+
+ if (resolution <= 0)
+ {
+ resolution = DefaultVerticalResolution;
+ }
+
+ return this.Height / resolution;
+ }
+ }
+
+ ///
+ /// Gets a value indicating whether this image is animated.
+ ///
+ ///
+ /// True if this image is animated; otherwise, false.
+ ///
+ public bool IsAnimated => this.Frames.Count > 0;
+
+ ///
+ /// Gets or sets the number of times any animation is repeated.
+ /// 0 means to repeat indefinitely.
+ ///
+ public ushort RepeatCount { get; set; }
+
+ ///
+ /// Gets the other frames for the animation.
+ ///
+ /// The list of frame images.
+ public IList> Frames { get; } = new List>();
+
+ ///
+ /// Gets the list of properties for storing meta information about this image.
+ ///
+ /// A list of image properties.
+ public IList Properties { get; } = new List();
+
+ ///
+ /// Gets the currently loaded image format.
+ ///
+ public IImageFormat CurrentImageFormat { get; internal set; }
+
+ ///
+ /// Saves the image to the given stream using the currently loaded image format.
+ ///
+ /// The stream to save the image to.
+ /// Thrown if the stream is null.
+ public void Save(Stream stream)
+ {
+ Guard.NotNull(stream, nameof(stream));
+ this.CurrentImageFormat.Encoder.Encode(this, stream);
+ }
+
+ ///
+ /// Saves the image to the given stream using the given image format.
+ ///
+ /// The stream to save the image to.
+ /// The format to save the image as.
+ /// Thrown if the stream is null.
+ public void Save(Stream stream, IImageFormat format)
+ {
+ Guard.NotNull(stream, nameof(stream));
+ format.Encoder.Encode(this, stream);
+ }
+
+ ///
+ /// Saves the image to the given stream using the given image encoder.
+ ///
+ /// The stream to save the image to.
+ /// The encoder to save the image with.
+ /// Thrown if the stream is null.
+ public void Save(Stream stream, IImageEncoder encoder)
+ {
+ Guard.NotNull(stream, nameof(stream));
+ encoder.Encode(this, stream);
+ }
+
+ ///
+ /// Returns a Base64 encoded string from the given image.
+ ///
+ /// data:image/gif;base64,R0lGODlhAQABAIABAEdJRgAAACwAAAAAAQABAAACAkQBAA==
+ /// The
+ public override string ToString()
+ {
+ using (MemoryStream stream = new MemoryStream())
+ {
+ this.Save(stream);
+ stream.Flush();
+ return $"data:{this.CurrentImageFormat.Encoder.MimeType};base64,{Convert.ToBase64String(stream.ToArray())}";
+ }
+ }
+
+ ///
+ /// Loads the image from the given stream.
+ ///
+ /// The stream containing image information.
+ ///
+ /// Thrown if the stream is not readable nor seekable.
+ ///
+ private void Load(Stream stream)
+ {
+ if (!this.Formats.Any()) { return; }
+
+ if (!stream.CanRead)
+ {
+ throw new NotSupportedException("Cannot read from the stream.");
+ }
+
+ if (!stream.CanSeek)
+ {
+ throw new NotSupportedException("The stream does not support seeking.");
+ }
+
+ int maxHeaderSize = this.Formats.Max(x => x.Decoder.HeaderSize);
+ if (maxHeaderSize > 0)
+ {
+ byte[] header = new byte[maxHeaderSize];
+
+ stream.Position = 0;
+ stream.Read(header, 0, maxHeaderSize);
+ stream.Position = 0;
+
+ IImageFormat format = this.Formats.FirstOrDefault(x => x.Decoder.IsSupportedFileFormat(header));
+ if (format != null)
+ {
+ format.Decoder.Decode(this, stream);
+ this.CurrentImageFormat = format;
+ return;
+ }
+ }
+
+ StringBuilder stringBuilder = new StringBuilder();
+ stringBuilder.AppendLine("Image cannot be loaded. Available formats:");
+
+ foreach (IImageFormat format in this.Formats)
+ {
+ stringBuilder.AppendLine("-" + format);
+ }
+
+ throw new NotSupportedException(stringBuilder.ToString());
+ }
+ }
+}
diff --git a/src/ImageProcessorCore/ImageFrame.cs b/src/ImageProcessorCore/ImageFrame.cs
index 42cf08da48..2f1fe518c8 100644
--- a/src/ImageProcessorCore/ImageFrame.cs
+++ b/src/ImageProcessorCore/ImageFrame.cs
@@ -1,13 +1,26 @@
namespace ImageProcessorCore
{
- public class ImageFrame : GenericImageFrame
+ ///
+ /// Represents a single frame in a animation.
+ ///
+ ///
+ /// The image data is always stored in format, where the blue, green, red, and
+ /// alpha values are 8 bit unsigned bytes.
+ ///
+ public class ImageFrame : ImageBase, IImageFrame
{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ /// The frame to create the frame from.
+ ///
public ImageFrame(ImageFrame frame)
: base(frame)
{
}
- ///
+ ///
public override IPixelAccessor Lock()
{
return new PixelAccessor(this);
diff --git a/src/ImageProcessorCore/PixelAccessor.cs b/src/ImageProcessorCore/PixelAccessor.cs
index bf01cb8563..3606491321 100644
--- a/src/ImageProcessorCore/PixelAccessor.cs
+++ b/src/ImageProcessorCore/PixelAccessor.cs
@@ -9,8 +9,12 @@ namespace ImageProcessorCore
using System.Runtime.InteropServices;
///
- /// Provides per-pixel access to an images pixels as 8 bit unsigned components.
+ /// Provides per-pixel access to an images pixels.
///
+ ///
+ /// The image data is always stored in format, where the blue, green, red, and
+ /// alpha values are 8 bit unsigned bytes.
+ ///
public sealed unsafe class PixelAccessor : IPixelAccessor
{
///