Browse Source

True Generic Image?

Former-commit-id: 5b08411e203ba38ad40a1892f599cf67af7c513f
Former-commit-id: 64f7bf7a94fc878e8fb8b4a19f049b55bca5dea6
Former-commit-id: d183d15ce5ebefc2f8b9dc86ac8a9d7bb5c27714
pull/1/head
James Jackson-South 10 years ago
parent
commit
7aa7c40d38
  1. 66
      src/ImageProcessorCore/Bootstrapper.cs
  2. 261
      src/ImageProcessorCore/GenericImage.cs
  3. 40
      src/ImageProcessorCore/GenericImageFrame.cs
  4. 10
      src/ImageProcessorCore/IImageBase.cs
  5. 10
      src/ImageProcessorCore/IImageProcessor.cs
  6. 273
      src/ImageProcessorCore/Image.cs
  7. 23
      src/ImageProcessorCore/ImageFrame.cs
  8. 20
      src/ImageProcessorCore/ImageProcessor.cs
  9. 12
      src/ImageProcessorCore/PixelAccessor/Bgra32PixelAccessor.cs
  10. 0
      src/ImageProcessorCore/PixelAccessor/IPixelAccessor.cs

66
src/ImageProcessorCore/Bootstrapper.cs

@ -8,6 +8,8 @@ namespace ImageProcessorCore
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
using ImageProcessorCore.Formats;
/// <summary>
@ -26,18 +28,25 @@ namespace ImageProcessorCore
/// </summary>
private readonly List<IImageFormat> imageFormats;
private readonly Dictionary<Type, Type> pixelAccessors;
/// <summary>
/// Prevents a default instance of the <see cref="Bootstrapper"/> class from being created.
/// </summary>
private Bootstrapper()
{
this.imageFormats = new List<IImageFormat>(new List<IImageFormat>
this.imageFormats = new List<IImageFormat>
{
new BmpFormat(),
new JpegFormat(),
new PngFormat(),
new GifFormat()
});
};
this.pixelAccessors = new Dictionary<Type, Type>
{
{ typeof(Bgra32), typeof(Bgra32PixelAccessor) }
};
}
/// <summary>
@ -58,5 +67,58 @@ namespace ImageProcessorCore
{
this.imageFormats.Add(format);
}
/// <summary>
/// Gets an instance of the correct <see cref="IPixelAccessor"/> for the packed vector.
/// </summary>
/// <typeparam name="TPackedVector">The type of pixel data.</typeparam>
/// <param name="image">The image</param>
/// <returns>The <see cref="IPixelAccessor"/></returns>
public IPixelAccessor GetPixelAccessor<TPackedVector>(Image<TPackedVector> image)
where TPackedVector : IPackedVector
{
Type packed = typeof(TPackedVector);
if (!this.pixelAccessors.ContainsKey(packed))
{
// TODO: Double check this. It should work...
return (IPixelAccessor)Activator.CreateInstance(this.pixelAccessors[packed], image);
}
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.AppendLine("PixelAccessor cannot be loaded. Available accessors:");
foreach (Type value in this.pixelAccessors.Values)
{
stringBuilder.AppendLine("-" + value.Name);
}
throw new NotSupportedException(stringBuilder.ToString());
}
/// <summary>
/// Gets an instance of the correct <see cref="IPixelAccessor"/> for the packed vector.
/// </summary>
/// <typeparam name="TPackedVector">The type of pixel data.</typeparam>
/// <param name="image">The image</param>
/// <returns>The <see cref="IPixelAccessor"/></returns>
public IPixelAccessor GetPixelAccessor<TPackedVector>(ImageFrame<TPackedVector> image)
where TPackedVector : IPackedVector
{
Type packed = typeof(TPackedVector);
if (!this.pixelAccessors.ContainsKey(packed))
{
return (IPixelAccessor)Activator.CreateInstance(this.pixelAccessors[packed], image);
}
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.AppendLine("PixelAccessor cannot be loaded. Available accessors:");
foreach (Type value in this.pixelAccessors.Values)
{
stringBuilder.AppendLine("-" + value.Name);
}
throw new NotSupportedException(stringBuilder.ToString());
}
}
}

261
src/ImageProcessorCore/GenericImage.cs

@ -1,261 +0,0 @@

namespace ImageProcessorCore
{
using System.IO;
using System.Text;
using System;
using System.Collections.Generic;
using System.Linq;
using ImageProcessorCore.Formats;
/// <summary>
/// Encapsulates an image, which consists of the pixel data for a graphics image and its attributes.
/// </summary>
/// <remarks>
/// The image data is always stored in RGBA format, where the red, green, blue, and
/// alpha values are floating point numbers.
/// </remarks>
public abstract class GenericImage<TPacked> : ImageBase<TPacked>
where TPacked : IPackedVector
{
/// <summary>
/// The default horizontal resolution value (dots per inch) in x direction.
/// <remarks>The default value is 96 dots per inch.</remarks>
/// </summary>
public const double DefaultHorizontalResolution = 96;
/// <summary>
/// The default vertical resolution value (dots per inch) in y direction.
/// <remarks>The default value is 96 dots per inch.</remarks>
/// </summary>
public const double DefaultVerticalResolution = 96;
/// <summary>
/// Initializes a new instance of the <see cref="Image"/> class.
/// </summary>
protected GenericImage()
{
this.CurrentImageFormat = Bootstrapper.Instance.ImageFormats.First(f => f.GetType() == typeof(PngFormat));
}
/// <summary>
/// Initializes a new instance of the <see cref="Image"/> class
/// with the height and the width of the image.
/// </summary>
/// <param name="width">The width of the image in pixels.</param>
/// <param name="height">The height of the image in pixels.</param>
protected GenericImage(int width, int height)
: base(width, height)
{
this.CurrentImageFormat = Bootstrapper.Instance.ImageFormats.First(f => f.GetType() == typeof(PngFormat));
}
/// <summary>
/// Initializes a new instance of the <see cref="Image"/> class.
/// </summary>
/// <param name="stream">
/// The stream containing image information.
/// </param>
/// <exception cref="ArgumentNullException">Thrown if the <paramref name="stream"/> is null.</exception>
protected GenericImage(Stream stream)
{
Guard.NotNull(stream, nameof(stream));
this.Load(stream);
}
/// <summary>
/// Gets a list of supported image formats.
/// </summary>
public IReadOnlyCollection<IImageFormat> Formats { get; } = Bootstrapper.Instance.ImageFormats;
/// <summary>
/// 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.
/// </summary>
/// <value>The density of the image in x- direction.</value>
public double HorizontalResolution { get; set; } = DefaultHorizontalResolution;
/// <summary>
/// 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.
/// </summary>
/// <value>The density of the image in y- direction.</value>
public double VerticalResolution { get; set; } = DefaultVerticalResolution;
/// <summary>
/// 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.
/// </summary>
/// <value>The width of the image in inches.</value>
public double InchWidth
{
get
{
double resolution = this.HorizontalResolution;
if (resolution <= 0)
{
resolution = DefaultHorizontalResolution;
}
return this.Width / resolution;
}
}
/// <summary>
/// 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.
/// </summary>
/// <value>The height of the image in inches.</value>
public double InchHeight
{
get
{
double resolution = this.VerticalResolution;
if (resolution <= 0)
{
resolution = DefaultVerticalResolution;
}
return this.Height / resolution;
}
}
/// <summary>
/// Gets a value indicating whether this image is animated.
/// </summary>
/// <value>
/// <c>True</c> if this image is animated; otherwise, <c>false</c>.
/// </value>
public bool IsAnimated => this.Frames.Count > 0;
/// <summary>
/// Gets or sets the number of times any animation is repeated.
/// <remarks>0 means to repeat indefinitely.</remarks>
/// </summary>
public ushort RepeatCount { get; set; }
/// <summary>
/// Gets the other frames for the animation.
/// </summary>
/// <value>The list of frame images.</value>
public IList<IImageFrame<TPacked>> Frames { get; } = new List<IImageFrame<TPacked>>();
/// <summary>
/// Gets the list of properties for storing meta information about this image.
/// </summary>
/// <value>A list of image properties.</value>
public IList<ImageProperty> Properties { get; } = new List<ImageProperty>();
/// <summary>
/// Gets the currently loaded image format.
/// </summary>
public IImageFormat CurrentImageFormat { get; internal set; }
/// <summary>
/// Saves the image to the given stream using the currently loaded image format.
/// </summary>
/// <param name="stream">The stream to save the image to.</param>
/// <exception cref="ArgumentNullException">Thrown if the stream is null.</exception>
public void Save(Stream stream)
{
Guard.NotNull(stream, nameof(stream));
this.CurrentImageFormat.Encoder.Encode(this, stream);
}
/// <summary>
/// Saves the image to the given stream using the given image format.
/// </summary>
/// <param name="stream">The stream to save the image to.</param>
/// <param name="format">The format to save the image as.</param>
/// <exception cref="ArgumentNullException">Thrown if the stream is null.</exception>
public void Save(Stream stream, IImageFormat format)
{
Guard.NotNull(stream, nameof(stream));
format.Encoder.Encode(this, stream);
}
/// <summary>
/// Saves the image to the given stream using the given image encoder.
/// </summary>
/// <param name="stream">The stream to save the image to.</param>
/// <param name="encoder">The encoder to save the image with.</param>
/// <exception cref="ArgumentNullException">Thrown if the stream is null.</exception>
public void Save(Stream stream, IImageEncoder encoder)
{
Guard.NotNull(stream, nameof(stream));
encoder.Encode(this, stream);
}
/// <summary>
/// Returns a Base64 encoded string from the given image.
/// </summary>
/// <example>data:image/gif;base64,R0lGODlhAQABAIABAEdJRgAAACwAAAAAAQABAAACAkQBAA==</example>
/// <returns>The <see cref="string"/></returns>
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())}";
}
}
/// <summary>
/// Loads the image from the given stream.
/// </summary>
/// <param name="stream">The stream containing image information.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
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());
}
}
}

40
src/ImageProcessorCore/GenericImageFrame.cs

@ -1,40 +0,0 @@
// <copyright file="GenericImageFrame.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageProcessorCore
{
using System;
/// <summary>
/// Represents a single frame in a animation.
/// </summary>
/// <typeparam name="TPacked">
/// The packed vector pixels format.
/// </typeparam>
public abstract class GenericImageFrame<TPacked> : ImageBase<TPacked>, IImageFrame<TPacked>
where TPacked : IPackedVector
{
/// <summary>
/// Initializes a new instance of the <see cref="GenericImageFrame{TPacked}"/> class.
/// </summary>
protected GenericImageFrame()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="GenericImageFrame{TPacked}"/> class.
/// </summary>
/// <param name="other">
/// The other <see cref="GenericImageFrame{TPacked}"/> to create this instance from.
/// </param>
/// <exception cref="ArgumentNullException">
/// Thrown if the given <see cref="GenericImageFrame{TPacked}"/> is null.
/// </exception>
protected GenericImageFrame(GenericImageFrame<TPacked> other)
: base(other)
{
}
}
}

10
src/ImageProcessorCore/IImageBase.cs

@ -1,18 +1,18 @@
namespace ImageProcessorCore
{
public interface IImageBase<TPacked>
where TPacked : IPackedVector
public interface IImageBase<TPackedVector>
where TPackedVector : IPackedVector
{
Rectangle Bounds { get; }
int FrameDelay { get; set; }
int Height { get; }
double PixelRatio { get; }
TPacked[] Pixels { get; }
TPackedVector[] Pixels { get; }
int Quality { get; set; }
int Width { get; }
void ClonePixels(int width, int height, TPacked[] pixels);
void ClonePixels(int width, int height, TPackedVector[] pixels);
IPixelAccessor Lock();
void SetPixels(int width, int height, TPacked[] pixels);
void SetPixels(int width, int height, TPackedVector[] pixels);
}
}

10
src/ImageProcessorCore/IImageProcessor.cs

@ -27,8 +27,9 @@ namespace ImageProcessorCore.Processors
event ProgressEventHandler OnProgress;
/// <summary>
/// Applies the process to the specified portion of the specified <see cref="ImageBase"/>.
/// Applies the process to the specified portion of the specified <see cref="ImageBase{TPackedVector}"/>.
/// </summary>
/// <typeparam name="TPackedVector">The type of pixels contained within the image.</typeparam>
/// <param name="target">Target image to apply the process to.</param>
/// <param name="source">The source image. Cannot be null.</param>
/// <param name="sourceRectangle">
@ -44,12 +45,13 @@ namespace ImageProcessorCore.Processors
/// <exception cref="System.ArgumentException">
/// <paramref name="sourceRectangle"/> doesnt fit the dimension of the image.
/// </exception>
void Apply(ImageBase target, ImageBase source, Rectangle sourceRectangle);
void Apply<TPackedVector>(ImageBase<TPackedVector> target, ImageBase<TPackedVector> source, Rectangle sourceRectangle) where TPackedVector : IPackedVector;
/// <summary>
/// Applies the process to the specified portion of the specified <see cref="ImageBase"/> at the specified
/// Applies the process to the specified portion of the specified <see cref="ImageBase{TPackedVector}"/> at the specified
/// location and with the specified size.
/// </summary>
/// <typeparam name="TPackedVector">The type of pixels contained within the image.</typeparam>
/// <param name="target">Target image to apply the process to.</param>
/// <param name="source">The source image. Cannot be null.</param>
/// <param name="width">The target width.</param>
@ -65,6 +67,6 @@ namespace ImageProcessorCore.Processors
/// The method keeps the source image unchanged and returns the
/// the result of image process as new image.
/// </remarks>
void Apply(ImageBase target, ImageBase source, int width, int height, Rectangle targetRectangle, Rectangle sourceRectangle);
void Apply<TPackedVector>(ImageBase<TPackedVector> target, ImageBase<TPackedVector> source, int width, int height, Rectangle targetRectangle, Rectangle sourceRectangle) where TPackedVector : IPackedVector;
}
}

273
src/ImageProcessorCore/Image.cs

@ -1,33 +1,86 @@
namespace ImageProcessorCore
// <copyright file="Image.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageProcessorCore
{
using System.IO;
using System.Text;
using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.Linq;
using Formats;
/// <summary>
/// Encapsulates an image, which consists of the pixel data for a graphics image and its attributes.
/// </summary>
/// <remarks>
/// The image data is always stored in <see cref="Bgra32"/> format, where the blue, green, red, and
/// alpha values are 8 bit unsigned bytes.
/// </remarks>
[DebuggerDisplay("Image: {Width}x{Height}")]
public class Image : GenericImage<Bgra32>
/// <typeparam name="TPackedVector">
/// The packed vector containing pixel information.
/// </typeparam>
public class Image<TPackedVector> : ImageBase<TPackedVector>
where TPackedVector : IPackedVector
{
/// <summary>
/// Initializes a new instance of the <see cref="Image"/> class
/// The default horizontal resolution value (dots per inch) in x direction.
/// <remarks>The default value is 96 dots per inch.</remarks>
/// </summary>
public const double DefaultHorizontalResolution = 96;
/// <summary>
/// The default vertical resolution value (dots per inch) in y direction.
/// <remarks>The default value is 96 dots per inch.</remarks>
/// </summary>
public const double DefaultVerticalResolution = 96;
/// <summary>
/// Initializes a new instance of the <see cref="Image{TPackedVector}"/> class.
/// </summary>
public Image()
{
this.CurrentImageFormat = Bootstrapper.Instance.ImageFormats.First(f => f.GetType() == typeof(PngFormat));
}
/// <summary>
/// Initializes a new instance of the <see cref="Image{TPackedVector}"/> class
/// with the height and the width of the image.
/// </summary>
/// <param name="width">The width of the image in pixels.</param>
/// <param name="height">The height of the image in pixels.</param>
public Image(int width, int height)
: base(width, height)
{
this.CurrentImageFormat = Bootstrapper.Instance.ImageFormats.First(f => f.GetType() == typeof(PngFormat));
}
/// <summary>
/// Initializes a new instance of the <see cref="Image{TPackedVector}"/> class.
/// </summary>
/// <param name="stream">
/// The stream containing image information.
/// </param>
/// <exception cref="ArgumentNullException">Thrown if the <paramref name="stream"/> is null.</exception>
public Image(Stream stream)
{
Guard.NotNull(stream, nameof(stream));
this.Load(stream);
}
/// <summary>
/// Initializes a new instance of the <see cref="Image{TPackedVector}"/> class
/// by making a copy from another image.
/// </summary>
/// <param name="other">The other image, where the clone should be made from.</param>
/// <exception cref="ArgumentNullException"><paramref name="other"/> is null.</exception>
public Image(Image other)
public Image(Image<TPackedVector> other)
{
// TODO: Check this. Not sure why I was getting a cast warning.
foreach (ImageFrame frame in other.Frames.Cast<ImageFrame>())
foreach (ImageFrame<TPackedVector> frame in other.Frames)
{
if (frame != null)
{
this.Frames.Add(new ImageFrame(frame));
this.Frames.Add(new ImageFrame<TPackedVector>(frame));
}
}
@ -37,10 +90,202 @@
this.CurrentImageFormat = other.CurrentImageFormat;
}
/// <summary>
/// Gets a list of supported image formats.
/// </summary>
public IReadOnlyCollection<IImageFormat> Formats { get; } = Bootstrapper.Instance.ImageFormats;
/// <summary>
/// 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.
/// </summary>
/// <value>The density of the image in x- direction.</value>
public double HorizontalResolution { get; set; } = DefaultHorizontalResolution;
/// <summary>
/// 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.
/// </summary>
/// <value>The density of the image in y- direction.</value>
public double VerticalResolution { get; set; } = DefaultVerticalResolution;
/// <summary>
/// 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.
/// </summary>
/// <value>The width of the image in inches.</value>
public double InchWidth
{
get
{
double resolution = this.HorizontalResolution;
if (resolution <= 0)
{
resolution = DefaultHorizontalResolution;
}
return this.Width / resolution;
}
}
/// <summary>
/// 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.
/// </summary>
/// <value>The height of the image in inches.</value>
public double InchHeight
{
get
{
double resolution = this.VerticalResolution;
if (resolution <= 0)
{
resolution = DefaultVerticalResolution;
}
return this.Height / resolution;
}
}
/// <summary>
/// Gets a value indicating whether this image is animated.
/// </summary>
/// <value>
/// <c>True</c> if this image is animated; otherwise, <c>false</c>.
/// </value>
public bool IsAnimated => this.Frames.Count > 0;
/// <summary>
/// Gets or sets the number of times any animation is repeated.
/// <remarks>0 means to repeat indefinitely.</remarks>
/// </summary>
public ushort RepeatCount { get; set; }
/// <summary>
/// Gets the other frames for the animation.
/// </summary>
/// <value>The list of frame images.</value>
public IList<ImageFrame<TPackedVector>> Frames { get; } = new List<ImageFrame<TPackedVector>>();
/// <summary>
/// Gets the list of properties for storing meta information about this image.
/// </summary>
/// <value>A list of image properties.</value>
public IList<ImageProperty> Properties { get; } = new List<ImageProperty>();
/// <summary>
/// Gets the currently loaded image format.
/// </summary>
public IImageFormat CurrentImageFormat { get; internal set; }
/// <inheritdoc/>
public override IPixelAccessor Lock()
{
return new PixelAccessor(this);
return Bootstrapper.Instance.GetPixelAccessor(this);
}
/// <summary>
/// Saves the image to the given stream using the currently loaded image format.
/// </summary>
/// <param name="stream">The stream to save the image to.</param>
/// <exception cref="ArgumentNullException">Thrown if the stream is null.</exception>
public void Save(Stream stream)
{
Guard.NotNull(stream, nameof(stream));
this.CurrentImageFormat.Encoder.Encode(this, stream);
}
/// <summary>
/// Saves the image to the given stream using the given image format.
/// </summary>
/// <param name="stream">The stream to save the image to.</param>
/// <param name="format">The format to save the image as.</param>
/// <exception cref="ArgumentNullException">Thrown if the stream is null.</exception>
public void Save(Stream stream, IImageFormat format)
{
Guard.NotNull(stream, nameof(stream));
format.Encoder.Encode(this, stream);
}
/// <summary>
/// Saves the image to the given stream using the given image encoder.
/// </summary>
/// <param name="stream">The stream to save the image to.</param>
/// <param name="encoder">The encoder to save the image with.</param>
/// <exception cref="ArgumentNullException">Thrown if the stream is null.</exception>
public void Save(Stream stream, IImageEncoder encoder)
{
Guard.NotNull(stream, nameof(stream));
encoder.Encode(this, stream);
}
/// <summary>
/// Returns a Base64 encoded string from the given image.
/// </summary>
/// <example>data:image/gif;base64,R0lGODlhAQABAIABAEdJRgAAACwAAAAAAQABAAACAkQBAA==</example>
/// <returns>The <see cref="string"/></returns>
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())}";
}
}
/// <summary>
/// Loads the image from the given stream.
/// </summary>
/// <param name="stream">The stream containing image information.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
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());
}
}
}

23
src/ImageProcessorCore/ImageFrame.cs

@ -1,21 +1,26 @@
namespace ImageProcessorCore
// <copyright file="ImageFrame.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageProcessorCore
{
/// <summary>
/// Represents a single frame in a animation.
/// </summary>
/// <remarks>
/// The image data is always stored in <see cref="Bgra32"/> format, where the blue, green, red, and
/// alpha values are 8 bit unsigned bytes.
/// </remarks>
public class ImageFrame : ImageBase<Bgra32>, IImageFrame<Bgra32>
/// <typeparam name="TPackedVector">
/// The packed vector containing pixel information.
/// </typeparam>
public class ImageFrame<TPackedVector> : ImageBase<TPackedVector>
where TPackedVector : IPackedVector
{
/// <summary>
/// Initializes a new instance of the <see cref="ImageFrame"/> class.
/// Initializes a new instance of the <see cref="ImageFrame{TPackedVector}"/> class.
/// </summary>
/// <param name="frame">
/// The frame to create the frame from.
/// </param>
public ImageFrame(ImageFrame frame)
public ImageFrame(ImageFrame<TPackedVector> frame)
: base(frame)
{
}
@ -23,7 +28,7 @@
/// <inheritdoc />
public override IPixelAccessor Lock()
{
return new PixelAccessor(this);
return Bootstrapper.Instance.GetPixelAccessor(this);
}
}
}

20
src/ImageProcessorCore/ImageProcessor.cs

@ -27,7 +27,8 @@ namespace ImageProcessorCore.Processors
private int totalRows;
/// <inheritdoc/>
public void Apply(ImageBase target, ImageBase source, Rectangle sourceRectangle)
public void Apply<TPackedVector>(ImageBase<TPackedVector> target, ImageBase<TPackedVector> source, Rectangle sourceRectangle)
where TPackedVector : IPackedVector
{
try
{
@ -48,11 +49,12 @@ namespace ImageProcessorCore.Processors
}
/// <inheritdoc/>
public void Apply(ImageBase target, ImageBase source, int width, int height, Rectangle targetRectangle = default(Rectangle), Rectangle sourceRectangle = default(Rectangle))
public void Apply<TPackedVector>(ImageBase<TPackedVector> target, ImageBase<TPackedVector> source, int width, int height, Rectangle targetRectangle = default(Rectangle), Rectangle sourceRectangle = default(Rectangle))
where TPackedVector : IPackedVector
{
try
{
float[] pixels = new float[width * height * 4];
TPackedVector[] pixels = new TPackedVector[width * height];
target.SetPixels(width, height, pixels);
// Ensure we always have bounds.
@ -93,14 +95,16 @@ namespace ImageProcessorCore.Processors
/// <param name="sourceRectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to draw.
/// </param>
protected virtual void OnApply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle)
protected virtual void OnApply<TPackedVector>(ImageBase<TPackedVector> target, ImageBase<TPackedVector> source, Rectangle targetRectangle, Rectangle sourceRectangle)
where TPackedVector : IPackedVector
{
}
/// <summary>
/// Applies the process to the specified portion of the specified <see cref="ImageBase"/> at the specified location
/// Applies the process to the specified portion of the specified <see cref="ImageBase{TPackedVector}"/> at the specified location
/// and with the specified size.
/// </summary>
/// <typeparam name="TPackedVector">The type of pixels contained within the image.</typeparam>
/// <param name="target">Target image to apply the process to.</param>
/// <param name="source">The source image. Cannot be null.</param>
/// <param name="targetRectangle">
@ -116,11 +120,12 @@ namespace ImageProcessorCore.Processors
/// The method keeps the source image unchanged and returns the
/// the result of image process as new image.
/// </remarks>
protected abstract void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY);
protected abstract void Apply<TPackedVector>(ImageBase<TPackedVector> target, ImageBase<TPackedVector> source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) where TPackedVector : IPackedVector;
/// <summary>
/// This method is called after the process is applied to prepare the processor.
/// </summary>
/// <typeparam name="TPackedVector">The type of pixels contained within the image.</typeparam>
/// <param name="target">Target image to apply the process to.</param>
/// <param name="source">The source image. Cannot be null.</param>
/// <param name="targetRectangle">
@ -130,7 +135,8 @@ namespace ImageProcessorCore.Processors
/// <param name="sourceRectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to draw.
/// </param>
protected virtual void AfterApply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle)
protected virtual void AfterApply<TPackedVector>(ImageBase<TPackedVector> target, ImageBase<TPackedVector> source, Rectangle targetRectangle, Rectangle sourceRectangle)
where TPackedVector : IPackedVector
{
}

12
src/ImageProcessorCore/PixelAccessor.cs → src/ImageProcessorCore/PixelAccessor/Bgra32PixelAccessor.cs

@ -1,4 +1,4 @@
// <copyright file="PixelAccessor.cs" company="James Jackson-South">
// <copyright file="Bgra32PixelAccessor.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
@ -15,7 +15,7 @@ namespace ImageProcessorCore
/// The image data is always stored in <see cref="Bgra32"/> format, where the blue, green, red, and
/// alpha values are 8 bit unsigned bytes.
/// </remarks>
public sealed unsafe class PixelAccessor : IPixelAccessor
public sealed unsafe class Bgra32PixelAccessor : IPixelAccessor
{
/// <summary>
/// The position of the first pixel in the bitmap.
@ -41,12 +41,12 @@ namespace ImageProcessorCore
private bool isDisposed;
/// <summary>
/// Initializes a new instance of the <see cref="PixelAccessor"/> class.
/// Initializes a new instance of the <see cref="Bgra32PixelAccessor"/> class.
/// </summary>
/// <param name="image">
/// The image to provide pixel access for.
/// </param>
public PixelAccessor(ImageBase<Bgra32> image)
public Bgra32PixelAccessor(IImageBase<IPackedVector> image)
{
Guard.NotNull(image, nameof(image));
Guard.MustBeGreaterThan(image.Width, 0, "image width");
@ -60,9 +60,9 @@ namespace ImageProcessorCore
}
/// <summary>
/// Finalizes an instance of the <see cref="PixelAccessor"/> class.
/// Finalizes an instance of the <see cref="Bgra32PixelAccessor"/> class.
/// </summary>
~PixelAccessor()
~Bgra32PixelAccessor()
{
this.Dispose();
}

0
src/ImageProcessorCore/IPixelAccessor.cs → src/ImageProcessorCore/PixelAccessor/IPixelAccessor.cs

Loading…
Cancel
Save