From 7aa7c40d3893ae960ee126e004b08bf71ac706ac Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 7 Jul 2016 16:48:39 +1000 Subject: [PATCH] True Generic Image? Former-commit-id: 5b08411e203ba38ad40a1892f599cf67af7c513f Former-commit-id: 64f7bf7a94fc878e8fb8b4a19f049b55bca5dea6 Former-commit-id: d183d15ce5ebefc2f8b9dc86ac8a9d7bb5c27714 --- src/ImageProcessorCore/Bootstrapper.cs | 66 ++++- src/ImageProcessorCore/GenericImage.cs | 261 ----------------- src/ImageProcessorCore/GenericImageFrame.cs | 40 --- src/ImageProcessorCore/IImageBase.cs | 10 +- src/ImageProcessorCore/IImageProcessor.cs | 10 +- src/ImageProcessorCore/Image.cs | 273 +++++++++++++++++- src/ImageProcessorCore/ImageFrame.cs | 23 +- src/ImageProcessorCore/ImageProcessor.cs | 20 +- .../Bgra32PixelAccessor.cs} | 12 +- .../{ => PixelAccessor}/IPixelAccessor.cs | 0 10 files changed, 367 insertions(+), 348 deletions(-) delete mode 100644 src/ImageProcessorCore/GenericImage.cs delete mode 100644 src/ImageProcessorCore/GenericImageFrame.cs rename src/ImageProcessorCore/{PixelAccessor.cs => PixelAccessor/Bgra32PixelAccessor.cs} (92%) rename src/ImageProcessorCore/{ => PixelAccessor}/IPixelAccessor.cs (100%) diff --git a/src/ImageProcessorCore/Bootstrapper.cs b/src/ImageProcessorCore/Bootstrapper.cs index a9c7dc831..5f2978534 100644 --- a/src/ImageProcessorCore/Bootstrapper.cs +++ b/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; /// @@ -26,18 +28,25 @@ namespace ImageProcessorCore /// private readonly List imageFormats; + private readonly Dictionary pixelAccessors; + /// /// Prevents a default instance of the class from being created. /// private Bootstrapper() { - this.imageFormats = new List(new List + this.imageFormats = new List { new BmpFormat(), new JpegFormat(), new PngFormat(), new GifFormat() - }); + }; + + this.pixelAccessors = new Dictionary + { + { typeof(Bgra32), typeof(Bgra32PixelAccessor) } + }; } /// @@ -58,5 +67,58 @@ namespace ImageProcessorCore { this.imageFormats.Add(format); } + + /// + /// Gets an instance of the correct for the packed vector. + /// + /// The type of pixel data. + /// The image + /// The + public IPixelAccessor GetPixelAccessor(Image 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()); + } + + /// + /// Gets an instance of the correct for the packed vector. + /// + /// The type of pixel data. + /// The image + /// The + public IPixelAccessor GetPixelAccessor(ImageFrame 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()); + } } } diff --git a/src/ImageProcessorCore/GenericImage.cs b/src/ImageProcessorCore/GenericImage.cs deleted file mode 100644 index b0408513a..000000000 --- a/src/ImageProcessorCore/GenericImage.cs +++ /dev/null @@ -1,261 +0,0 @@ - - -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/GenericImageFrame.cs b/src/ImageProcessorCore/GenericImageFrame.cs deleted file mode 100644 index b0dbe341c..000000000 --- a/src/ImageProcessorCore/GenericImageFrame.cs +++ /dev/null @@ -1,40 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageProcessorCore -{ - using System; - - /// - /// Represents a single frame in a animation. - /// - /// - /// The packed vector pixels format. - /// - public abstract class GenericImageFrame : ImageBase, IImageFrame - where TPacked : IPackedVector - { - /// - /// Initializes a new instance of the class. - /// - protected GenericImageFrame() - { - } - - /// - /// Initializes a new instance of the class. - /// - /// - /// The other to create this instance from. - /// - /// - /// Thrown if the given is null. - /// - protected GenericImageFrame(GenericImageFrame other) - : base(other) - { - } - } -} diff --git a/src/ImageProcessorCore/IImageBase.cs b/src/ImageProcessorCore/IImageBase.cs index 85ffa0086..b01ee7c9c 100644 --- a/src/ImageProcessorCore/IImageBase.cs +++ b/src/ImageProcessorCore/IImageBase.cs @@ -1,18 +1,18 @@ namespace ImageProcessorCore { - public interface IImageBase - where TPacked : IPackedVector + public interface IImageBase + 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); } } \ No newline at end of file diff --git a/src/ImageProcessorCore/IImageProcessor.cs b/src/ImageProcessorCore/IImageProcessor.cs index e71762b10..ad6e4ac76 100644 --- a/src/ImageProcessorCore/IImageProcessor.cs +++ b/src/ImageProcessorCore/IImageProcessor.cs @@ -27,8 +27,9 @@ namespace ImageProcessorCore.Processors event ProgressEventHandler OnProgress; /// - /// Applies the process to the specified portion of the specified . + /// Applies the process to the specified portion of the specified . /// + /// The type of pixels contained within the image. /// Target image to apply the process to. /// The source image. Cannot be null. /// @@ -44,12 +45,13 @@ namespace ImageProcessorCore.Processors /// /// doesnt fit the dimension of the image. /// - void Apply(ImageBase target, ImageBase source, Rectangle sourceRectangle); + void Apply(ImageBase target, ImageBase source, Rectangle sourceRectangle) where TPackedVector : IPackedVector; /// - /// Applies the process to the specified portion of the specified at the specified + /// Applies the process to the specified portion of the specified at the specified /// location and with the specified size. /// + /// The type of pixels contained within the image. /// Target image to apply the process to. /// The source image. Cannot be null. /// The target width. @@ -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. /// - void Apply(ImageBase target, ImageBase source, int width, int height, Rectangle targetRectangle, Rectangle sourceRectangle); + void Apply(ImageBase target, ImageBase source, int width, int height, Rectangle targetRectangle, Rectangle sourceRectangle) where TPackedVector : IPackedVector; } } diff --git a/src/ImageProcessorCore/Image.cs b/src/ImageProcessorCore/Image.cs index 88d4d1b6c..c8dc861d6 100644 --- a/src/ImageProcessorCore/Image.cs +++ b/src/ImageProcessorCore/Image.cs @@ -1,33 +1,86 @@ -namespace ImageProcessorCore +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageProcessorCore { + using System.IO; + using System.Text; + using System; - using System.Diagnostics; + using System.Collections.Generic; using System.Linq; + using Formats; + /// /// Encapsulates an image, which consists of the pixel data for a graphics image and its attributes. /// - /// - /// The image data is always stored in format, where the blue, green, red, and - /// alpha values are 8 bit unsigned bytes. - /// - [DebuggerDisplay("Image: {Width}x{Height}")] - public class Image : GenericImage + /// + /// The packed vector containing pixel information. + /// + public class Image : ImageBase + where TPackedVector : IPackedVector { /// - /// Initializes a new instance of the class + /// 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. + /// + public Image() + { + 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. + public Image(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. + public Image(Stream stream) + { + Guard.NotNull(stream, nameof(stream)); + this.Load(stream); + } + + /// + /// Initializes a new instance of the class /// by making a copy from another image. /// /// The other image, where the clone should be made from. /// is null. - public Image(Image other) + public Image(Image other) { - // TODO: Check this. Not sure why I was getting a cast warning. - foreach (ImageFrame frame in other.Frames.Cast()) + foreach (ImageFrame frame in other.Frames) { if (frame != null) { - this.Frames.Add(new ImageFrame(frame)); + this.Frames.Add(new ImageFrame(frame)); } } @@ -37,10 +90,202 @@ this.CurrentImageFormat = other.CurrentImageFormat; } + /// + /// 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; } + /// public override IPixelAccessor Lock() { - return new PixelAccessor(this); + return Bootstrapper.Instance.GetPixelAccessor(this); + } + + /// + /// 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 2f1fe518c..479d9dd9b 100644 --- a/src/ImageProcessorCore/ImageFrame.cs +++ b/src/ImageProcessorCore/ImageFrame.cs @@ -1,21 +1,26 @@ -namespace ImageProcessorCore +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageProcessorCore { /// /// 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 + /// + /// The packed vector containing pixel information. + /// + public class ImageFrame : ImageBase + where TPackedVector : IPackedVector { /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// /// The frame to create the frame from. /// - public ImageFrame(ImageFrame frame) + public ImageFrame(ImageFrame frame) : base(frame) { } @@ -23,7 +28,7 @@ /// public override IPixelAccessor Lock() { - return new PixelAccessor(this); + return Bootstrapper.Instance.GetPixelAccessor(this); } } } diff --git a/src/ImageProcessorCore/ImageProcessor.cs b/src/ImageProcessorCore/ImageProcessor.cs index ea76ebbf8..e7057a3f9 100644 --- a/src/ImageProcessorCore/ImageProcessor.cs +++ b/src/ImageProcessorCore/ImageProcessor.cs @@ -27,7 +27,8 @@ namespace ImageProcessorCore.Processors private int totalRows; /// - public void Apply(ImageBase target, ImageBase source, Rectangle sourceRectangle) + public void Apply(ImageBase target, ImageBase source, Rectangle sourceRectangle) + where TPackedVector : IPackedVector { try { @@ -48,11 +49,12 @@ namespace ImageProcessorCore.Processors } /// - public void Apply(ImageBase target, ImageBase source, int width, int height, Rectangle targetRectangle = default(Rectangle), Rectangle sourceRectangle = default(Rectangle)) + public void Apply(ImageBase target, ImageBase 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 /// /// The structure that specifies the portion of the image object to draw. /// - protected virtual void OnApply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle) + protected virtual void OnApply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle) + where TPackedVector : IPackedVector { } /// - /// Applies the process to the specified portion of the specified at the specified location + /// Applies the process to the specified portion of the specified at the specified location /// and with the specified size. /// + /// The type of pixels contained within the image. /// Target image to apply the process to. /// The source image. Cannot be null. /// @@ -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. /// - protected abstract void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY); + protected abstract void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) where TPackedVector : IPackedVector; /// /// This method is called after the process is applied to prepare the processor. /// + /// The type of pixels contained within the image. /// Target image to apply the process to. /// The source image. Cannot be null. /// @@ -130,7 +135,8 @@ namespace ImageProcessorCore.Processors /// /// The structure that specifies the portion of the image object to draw. /// - protected virtual void AfterApply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle) + protected virtual void AfterApply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle) + where TPackedVector : IPackedVector { } diff --git a/src/ImageProcessorCore/PixelAccessor.cs b/src/ImageProcessorCore/PixelAccessor/Bgra32PixelAccessor.cs similarity index 92% rename from src/ImageProcessorCore/PixelAccessor.cs rename to src/ImageProcessorCore/PixelAccessor/Bgra32PixelAccessor.cs index 360649132..cecc148b9 100644 --- a/src/ImageProcessorCore/PixelAccessor.cs +++ b/src/ImageProcessorCore/PixelAccessor/Bgra32PixelAccessor.cs @@ -1,4 +1,4 @@ -// +// // Copyright (c) James Jackson-South and contributors. // Licensed under the Apache License, Version 2.0. // @@ -15,7 +15,7 @@ namespace ImageProcessorCore /// 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 + public sealed unsafe class Bgra32PixelAccessor : IPixelAccessor { /// /// The position of the first pixel in the bitmap. @@ -41,12 +41,12 @@ namespace ImageProcessorCore private bool isDisposed; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// /// The image to provide pixel access for. /// - public PixelAccessor(ImageBase image) + public Bgra32PixelAccessor(IImageBase image) { Guard.NotNull(image, nameof(image)); Guard.MustBeGreaterThan(image.Width, 0, "image width"); @@ -60,9 +60,9 @@ namespace ImageProcessorCore } /// - /// Finalizes an instance of the class. + /// Finalizes an instance of the class. /// - ~PixelAccessor() + ~Bgra32PixelAccessor() { this.Dispose(); } diff --git a/src/ImageProcessorCore/IPixelAccessor.cs b/src/ImageProcessorCore/PixelAccessor/IPixelAccessor.cs similarity index 100% rename from src/ImageProcessorCore/IPixelAccessor.cs rename to src/ImageProcessorCore/PixelAccessor/IPixelAccessor.cs