diff --git a/src/ImageProcessorCore/Image.cs b/src/ImageProcessorCore/Image.cs index 3cb8866bb..22c171f17 100644 --- a/src/ImageProcessorCore/Image.cs +++ b/src/ImageProcessorCore/Image.cs @@ -1,19 +1,47 @@ -using System.IO; +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// namespace ImageProcessorCore { + using System; + using System.IO; + + /// + /// Represents an image. Each pixel is a made up four 8-bit components blue, green, red, and alpha. + /// public class Image : Image { - // TODO Constructors. + /// + /// 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) { } + /// + /// Initializes a new instance of the class. + /// + /// + /// The stream containing image information. + /// + /// Thrown if the is null. public Image(Stream stream) : base(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) : base(other) { diff --git a/src/ImageProcessorCore/Image/IImageBase.cs b/src/ImageProcessorCore/Image/IImageBase.cs index db78d127b..cdee55cd6 100644 --- a/src/ImageProcessorCore/Image/IImageBase.cs +++ b/src/ImageProcessorCore/Image/IImageBase.cs @@ -1,29 +1,88 @@ -using System.Collections.Generic; +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// namespace ImageProcessorCore { + using System; + + /// + /// Encapsulates the basic properties and methods required to manipulate images in varying formats. + /// + /// The pixel format. + /// The packed format. long, float. public interface IImageBase : IImageBase where T : IPackedVector, new() where TP : struct { + /// + /// Gets the pixels as an array of the given packed pixel format. + /// T[] Pixels { get; } + /// + /// Sets the pixel array of the image to the given value. + /// + /// The new width of the image. Must be greater than zero. + /// The new height of the image. Must be greater than zero. + /// The array with pixels. Must be a multiple of the width and height. + /// + /// Thrown if either or are less than or equal to 0. + /// + /// + /// Thrown if the length is not equal to Width * Height. + /// + void SetPixels(int width, int height, T[] pixels); + + /// + /// Sets the pixel array of the image to the given value, creating a copy of + /// the original pixels. + /// + /// The new width of the image. Must be greater than zero. + /// The new height of the image. Must be greater than zero. + /// The array with pixels. Must be a multiple of four times the width and height. + /// + /// Thrown if either or are less than or equal to 0. + /// + /// + /// Thrown if the length is not equal to Width * Height. + /// void ClonePixels(int width, int height, T[] pixels); + /// + /// Locks the image providing access to the pixels. + /// + /// It is imperative that the accessor is correctly disposed off after use. + /// + /// + /// The IPixelAccessor Lock(); - - void SetPixels(int width, int height, T[] pixels); } + /// + /// Encapsulates the basic properties and methods required to manipulate images. + /// public interface IImageBase { + /// + /// Gets the representing the bounds of the image. + /// Rectangle Bounds { get; } - int FrameDelay { get; set; } - int Height { get; } - double PixelRatio { get; } + /// + /// Gets or sets the quality of the image. This affects the output quality of lossy image formats. + /// int Quality { 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. + /// + int FrameDelay { get; set; } + /// /// Gets or sets the maximum allowable width in pixels. /// @@ -34,6 +93,19 @@ namespace ImageProcessorCore /// int MaxHeight { get; set; } + /// + /// Gets the width in pixels. + /// int Width { get; } + + /// + /// Gets the height in pixels. + /// + int Height { get; } + + /// + /// Gets the pixel ratio made up of the width and height. + /// + double PixelRatio { get; } } } \ No newline at end of file diff --git a/src/ImageProcessorCore/Image/IImageFrame.cs b/src/ImageProcessorCore/Image/IImageFrame.cs index dadc5dd1c..4907019e0 100644 --- a/src/ImageProcessorCore/Image/IImageFrame.cs +++ b/src/ImageProcessorCore/Image/IImageFrame.cs @@ -1,6 +1,16 @@ -namespace ImageProcessorCore +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageProcessorCore { - public interface IImageFrame : IImageBase + /// + /// Represents a single frame in a animation. + /// + /// The pixel format. + /// The packed format. long, float. + public interface IImageFrame : IImageBase where T : IPackedVector, new() where TP : struct { diff --git a/src/ImageProcessorCore/Image/IImageProcessor.cs b/src/ImageProcessorCore/Image/IImageProcessor.cs index 617dc76cd..b817be724 100644 --- a/src/ImageProcessorCore/Image/IImageProcessor.cs +++ b/src/ImageProcessorCore/Image/IImageProcessor.cs @@ -27,9 +27,10 @@ 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. + /// The pixel format. + /// The packed format. long, float. /// Target image to apply the process to. /// The source image. Cannot be null. /// @@ -50,10 +51,11 @@ namespace ImageProcessorCore.Processors new() where TP : struct; /// - /// 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. + /// The pixel format. + /// The packed format. long, float. /// Target image to apply the process to. /// The source image. Cannot be null. /// The target width. diff --git a/src/ImageProcessorCore/Image/Image.cs b/src/ImageProcessorCore/Image/Image.cs index 67d0b53e4..8156b17e6 100644 --- a/src/ImageProcessorCore/Image/Image.cs +++ b/src/ImageProcessorCore/Image/Image.cs @@ -17,9 +17,8 @@ namespace ImageProcessorCore /// /// Encapsulates an image, which consists of the pixel data for a graphics image and its attributes. /// - /// - /// The packed vector containing pixel information. - /// + /// The pixel format. + /// The packed format. long, float. public class Image : ImageBase where T : IPackedVector, new() where TP : struct @@ -37,7 +36,7 @@ namespace ImageProcessorCore public const double DefaultVerticalResolution = 96; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// public Image() { @@ -45,7 +44,7 @@ namespace ImageProcessorCore } /// - /// Initializes a new instance of the class + /// Initializes a new instance of the class /// with the height and the width of the image. /// /// The width of the image in pixels. @@ -58,7 +57,7 @@ namespace ImageProcessorCore } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// /// The stream containing image information. @@ -71,7 +70,7 @@ namespace ImageProcessorCore } /// - /// Initializes a new instance of the class + /// Initializes a new instance of the class /// by making a copy from another image. /// /// The other image, where the clone should be made from. diff --git a/src/ImageProcessorCore/Image/ImageBase.cs b/src/ImageProcessorCore/Image/ImageBase.cs index 691f7450d..6cd0ca615 100644 --- a/src/ImageProcessorCore/Image/ImageBase.cs +++ b/src/ImageProcessorCore/Image/ImageBase.cs @@ -8,12 +8,11 @@ namespace ImageProcessorCore using System; /// - /// The base class of all images. Encapsulates the basic properties and methods required to manipulate images - /// in different pixel formats. + /// The base class of all images. Encapsulates the basic properties and methods required to manipulate + /// images in different pixel formats. /// - /// - /// The packed vector pixels format. - /// + /// The pixel format. + /// The packed format. long, float. public abstract class ImageBase : IImageBase where T : IPackedVector, new() where TP : struct @@ -66,68 +65,34 @@ namespace ImageProcessorCore Array.Copy(other.Pixels, this.Pixels, other.Pixels.Length); } - /// - /// Gets or sets the maximum allowable width in pixels. - /// + /// public int MaxWidth { get; set; } = int.MaxValue; - /// - /// Gets or sets the maximum allowable height in pixels. - /// + /// public int MaxHeight { get; set; } = int.MaxValue; - /// - /// Gets the pixels as an array of the given packed pixel format. - /// + /// public T[] Pixels { get; private set; } - /// - /// Gets the width in pixels. - /// + /// public int Width { get; private set; } - /// - /// Gets the height in pixels. - /// + /// public int Height { get; private set; } - /// - /// Gets the pixel ratio made up of the width and height. - /// + /// public double PixelRatio => (double)this.Width / this.Height; - /// - /// Gets the representing the bounds of the image. - /// + /// public Rectangle Bounds => new Rectangle(0, 0, this.Width, this.Height); - /// - /// Gets or sets th quality of the image. This affects the output quality of lossy image formats. - /// + /// public int Quality { 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; } - /// - /// Sets the pixel array of the image to the given value. - /// - /// The new width of the image. Must be greater than zero. - /// The new height of the image. Must be greater than zero. - /// - /// The array with colors. Must be a multiple of the width and height. - /// - /// - /// Thrown if either or are less than or equal to 0. - /// - /// - /// Thrown if the length is not equal to Width * Height. - /// + /// public void SetPixels(int width, int height, T[] pixels) { if (width <= 0) @@ -150,21 +115,7 @@ namespace ImageProcessorCore this.Pixels = pixels; } - /// - /// Sets the pixel array of the image to the given value, creating a copy of - /// the original pixels. - /// - /// The new width of the image. Must be greater than zero. - /// The new height of the image. Must be greater than zero. - /// - /// The array with colors. Must be a multiple of four times the width and height. - /// - /// - /// Thrown if either or are less than or equal to 0. - /// - /// - /// Thrown if the length is not equal to Width * Height. - /// + /// public void ClonePixels(int width, int height, T[] pixels) { if (width <= 0) @@ -190,13 +141,7 @@ namespace ImageProcessorCore Array.Copy(pixels, this.Pixels, pixels.Length); } - /// - /// Locks the image providing access to the pixels. - /// - /// It is imperative that the accessor is correctly disposed off after use. - /// - /// - /// The + /// public abstract IPixelAccessor Lock(); } } diff --git a/src/ImageProcessorCore/Image/ImageExtensions.cs b/src/ImageProcessorCore/Image/ImageExtensions.cs index b65bdc760..087edd655 100644 --- a/src/ImageProcessorCore/Image/ImageExtensions.cs +++ b/src/ImageProcessorCore/Image/ImageExtensions.cs @@ -12,7 +12,7 @@ namespace ImageProcessorCore using Processors; /// - /// Extension methods for the type. + /// Extension methods for the type. /// public static partial class ImageExtensions { @@ -57,10 +57,11 @@ namespace ImageProcessorCore /// Applies the collection of processors to the image. /// This method does not resize the target image. /// - /// The type of pixels contained within the image. + /// The pixel format. + /// The packed format. long, float. /// The image this method extends. /// The processor to apply to the image. - /// The . + /// The . public static Image Process(this Image source, IImageProcessor processor) where T : IPackedVector, new() where TP : struct @@ -72,13 +73,14 @@ namespace ImageProcessorCore /// Applies the collection of processors to the image. /// This method does not resize the target image. /// - /// The type of pixels contained within the image. + /// The pixel format. + /// The packed format. long, float. /// The image this method extends. /// /// The structure that specifies the portion of the image object to draw. /// /// The processors to apply to the image. - /// The . + /// The . public static Image Process(this Image source, Rectangle sourceRectangle, IImageProcessor processor) where T : IPackedVector, new() where TP : struct @@ -92,12 +94,13 @@ namespace ImageProcessorCore /// This method is not chainable. /// /// - /// The type of pixels contained within the image. + /// The pixel format. + /// The packed format. long, float. /// The source image. Cannot be null. /// The target image width. /// The target image height. /// The processor to apply to the image. - /// The . + /// The . public static Image Process(this Image source, int width, int height, IImageSampler sampler) where T : IPackedVector, new() where TP : struct @@ -111,7 +114,8 @@ namespace ImageProcessorCore /// This method does will resize the target image if the source and target rectangles are different. /// /// - /// The type of pixels contained within the image. + /// The pixel format. + /// The packed format. long, float. /// The source image. Cannot be null. /// The target image width. /// The target image height. @@ -123,7 +127,7 @@ namespace ImageProcessorCore /// The image is scaled to fit the rectangle. /// /// The processor to apply to the image. - /// The . + /// The . public static Image Process(this Image source, int width, int height, Rectangle sourceRectangle, Rectangle targetRectangle, IImageSampler sampler) where T : IPackedVector, new() where TP : struct @@ -134,11 +138,12 @@ namespace ImageProcessorCore /// /// Performs the given action on the source image. /// - /// The type of pixels contained within the image. + /// The pixel format. + /// The packed format. long, float. /// The image to perform the action against. /// Whether to clone the image. /// The to perform against the image. - /// The . + /// The . private static Image PerformAction(Image source, bool clone, Action, ImageBase> action) where T : IPackedVector, new() where TP : struct diff --git a/src/ImageProcessorCore/Image/ImageFrame.cs b/src/ImageProcessorCore/Image/ImageFrame.cs index 84ea69fa0..0cf3ef1e0 100644 --- a/src/ImageProcessorCore/Image/ImageFrame.cs +++ b/src/ImageProcessorCore/Image/ImageFrame.cs @@ -8,22 +8,21 @@ namespace ImageProcessorCore /// /// Represents a single frame in a animation. /// - /// - /// The packed vector containing pixel information. - /// + /// The pixel format. + /// The packed format. long, float. public class ImageFrame : ImageBase where T : IPackedVector, new() where TP : struct { /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// public ImageFrame() { } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// /// The frame to create the frame from. diff --git a/src/ImageProcessorCore/Image/ImageProperty.cs b/src/ImageProcessorCore/Image/ImageProperty.cs index 1d8f5bb8e..ef432ada2 100644 --- a/src/ImageProcessorCore/Image/ImageProperty.cs +++ b/src/ImageProcessorCore/Image/ImageProperty.cs @@ -1,14 +1,7 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. // -// -// Stores meta information about a image, like the name of the author, -// the copyright information, the date, where the image was created -// or some other information. -// -// -------------------------------------------------------------------------------------------------------------------- namespace ImageProcessorCore { @@ -24,12 +17,8 @@ namespace ImageProcessorCore /// /// Initializes a new instance of the struct. /// - /// - /// The name of the property. - /// - /// - /// The value of the property. - /// + /// The name of the property. + /// The value of the property. public ImageProperty(string name, string value) { this.Name = name; diff --git a/src/ImageProcessorCore/PackedVector/Bgra32.cs b/src/ImageProcessorCore/PackedVector/Bgra32.cs index 7020d43b7..7c0f24142 100644 --- a/src/ImageProcessorCore/PackedVector/Bgra32.cs +++ b/src/ImageProcessorCore/PackedVector/Bgra32.cs @@ -7,16 +7,43 @@ namespace ImageProcessorCore { using System; using System.Numerics; + using System.Runtime.InteropServices; /// /// Packed vector type containing four 8-bit unsigned normalized values ranging from 0 to 1. /// + [StructLayout(LayoutKind.Explicit)] public struct Bgra32 : IPackedVector, IEquatable { + /// + /// Gets or sets the blue component. + /// + [FieldOffset(0)] + public byte B; + + /// + /// Gets or sets the green component. + /// + [FieldOffset(1)] + public byte G; + + /// + /// Gets or sets the red component. + /// + [FieldOffset(2)] + public byte R; + + /// + /// Gets or sets the alpha component. + /// + [FieldOffset(3)] + public byte A; + /// /// The packed value. /// - private uint packedValue; + [FieldOffset(0)] + private readonly uint packedValue; /// /// Initializes a new instance of the struct. @@ -29,7 +56,10 @@ namespace ImageProcessorCore : this() { Vector4 clamped = Vector4.Clamp(new Vector4(b, g, r, a), Vector4.Zero, Vector4.One) * 255f; - this.packedValue = Pack(ref clamped); + this.B = (byte)Math.Round(clamped.X); + this.G = (byte)Math.Round(clamped.Y); + this.R = (byte)Math.Round(clamped.Z); + this.A = (byte)Math.Round(clamped.W); } /// @@ -46,7 +76,6 @@ namespace ImageProcessorCore this.G = g; this.R = r; this.A = a; - this.packedValue = this.Pack(); } /// @@ -59,29 +88,12 @@ namespace ImageProcessorCore : this() { Vector4 clamped = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * 255f; - this.packedValue = Pack(ref clamped); + this.B = (byte)Math.Round(clamped.X); + this.G = (byte)Math.Round(clamped.Y); + this.R = (byte)Math.Round(clamped.Z); + this.A = (byte)Math.Round(clamped.W); } - /// - /// Gets or sets the blue component. - /// - public byte B { get; set; } - - /// - /// Gets or sets the green component. - /// - public byte G { get; set; } - - /// - /// Gets or sets the red component. - /// - public byte R { get; set; } - - /// - /// Gets or sets the alpha component. - /// - public byte A { get; set; } - /// /// Compares two objects for equality. /// @@ -113,12 +125,6 @@ namespace ImageProcessorCore } /// - public uint PackedValue() - { - this.packedValue = this.Pack(); - return this.packedValue; - } - public void Add(Bgra32 value) { this.B = (byte)(this.B + value.B); @@ -127,6 +133,7 @@ namespace ImageProcessorCore this.A = (byte)(this.A + value.A); } + /// public void Subtract(Bgra32 value) { this.B = (byte)(this.B - value.B); @@ -135,6 +142,7 @@ namespace ImageProcessorCore this.A = (byte)(this.A - value.A); } + /// public void Multiply(Bgra32 value) { this.B = (byte)(this.B * value.B); @@ -143,6 +151,7 @@ namespace ImageProcessorCore this.A = (byte)(this.A * value.A); } + /// public void Multiply(float value) { this.B = (byte)(this.B * value); @@ -151,6 +160,7 @@ namespace ImageProcessorCore this.A = (byte)(this.A * value); } + /// public void Divide(Bgra32 value) { this.B = (byte)(this.B / value.B); @@ -159,6 +169,7 @@ namespace ImageProcessorCore this.A = (byte)(this.A / value.A); } + /// public void Divide(float value) { this.B = (byte)(this.B / value); @@ -167,11 +178,20 @@ namespace ImageProcessorCore this.A = (byte)(this.A / value); } + /// + public uint PackedValue() + { + return this.packedValue; + } + /// public void PackVector(Vector4 vector) { Vector4 clamped = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * 255f; - this.packedValue = Pack(ref clamped); + this.B = (byte)Math.Round(clamped.X); + this.G = (byte)Math.Round(clamped.Y); + this.R = (byte)Math.Round(clamped.Z); + this.A = (byte)Math.Round(clamped.W); } /// @@ -181,17 +201,12 @@ namespace ImageProcessorCore this.G = y; this.R = z; this.A = w; - this.packedValue = this.Pack(); } /// public Vector4 ToVector4() { - return new Vector4( - this.packedValue & 0xFF, - (this.packedValue >> 8) & 0xFF, - (this.packedValue >> 16) & 0xFF, - (this.packedValue >> 24) & 0xFF) / 255f; + return new Vector4(this.B, this.G, this.R, this.A) / 255f; } /// @@ -199,10 +214,10 @@ namespace ImageProcessorCore { return new[] { - (byte)(this.packedValue & 0xFF), - (byte)((this.packedValue >> 8) & 0xFF), - (byte)((this.packedValue >> 16) & 0xFF), - (byte)((this.packedValue >> 24) & 0xFF) + this.B, + this.G, + this.R, + this.A }; } @@ -233,34 +248,6 @@ namespace ImageProcessorCore return this.GetHashCode(this); } - /// - /// Sets the packed representation from the given component values. - /// - /// - /// The vector containing the components for the packed vector. - /// - /// - /// The . - /// - private static uint Pack(ref Vector4 vector) - { - return (uint)Math.Round(vector.X) | - ((uint)Math.Round(vector.Y) << 8) | - ((uint)Math.Round(vector.Z) << 16) | - ((uint)Math.Round(vector.W) << 24); - } - - /// - /// Sets the packed representation from the given component values. - /// - /// - /// The . - /// - private uint Pack() - { - return this.B | ((uint)this.G << 8) | ((uint)this.R << 16) | ((uint)this.A << 24); - } - /// /// Returns the hash code for this instance. /// diff --git a/src/ImageProcessorCore/PackedVector/IPackedVector.cs b/src/ImageProcessorCore/PackedVector/IPackedVector.cs index 5f8a369a4..329cc1703 100644 --- a/src/ImageProcessorCore/PackedVector/IPackedVector.cs +++ b/src/ImageProcessorCore/PackedVector/IPackedVector.cs @@ -11,9 +11,8 @@ namespace ImageProcessorCore /// An interface that converts packed vector types to and from values, /// allowing multiple encodings to be manipulated in a generic way. /// - /// - /// The type of object representing the packed value. - /// + /// The pixel format. + /// The packed format. long, float. public interface IPackedVector : IPackedVector where TP : struct { @@ -21,18 +20,45 @@ namespace ImageProcessorCore /// Gets the packed representation of the value. /// Typically packed in least to greatest significance order. /// + /// + /// The . + /// TP PackedValue(); + /// + /// Adds the given to the current instance. + /// + /// The packed vector to add. void Add(T value); + /// + /// Subtracts the given from the current instance. + /// + /// The packed vector to subtract. void Subtract(T value); + /// + /// Multiplies the given current instance by given the . + /// + /// The packed vector to multiply by. void Multiply(T value); + /// + /// Multiplies the given current instance by given the value. + /// + /// The value to multiply by. void Multiply(float value); + /// + /// Divides the given current instance by given the . + /// + /// The packed vector to divide by. void Divide(T value); + /// + /// Divides the given current instance by given the value. + /// + /// The value to divide by. void Divide(float value); } diff --git a/tests/ImageProcessorCore.Tests/Processors/Samplers/SamplerTests.cs b/tests/ImageProcessorCore.Tests/Processors/Samplers/SamplerTests.cs index 878a9f1ce..ba12cdf10 100644 --- a/tests/ImageProcessorCore.Tests/Processors/Samplers/SamplerTests.cs +++ b/tests/ImageProcessorCore.Tests/Processors/Samplers/SamplerTests.cs @@ -24,7 +24,7 @@ namespace ImageProcessorCore.Tests //{ "Lanczos3", new Lanczos3Resampler() }, //{ "Lanczos5", new Lanczos5Resampler() }, //{ "Lanczos8", new Lanczos8Resampler() }, - //{ "MitchellNetravali", new MitchellNetravaliResampler() }, + { "MitchellNetravali", new MitchellNetravaliResampler() }, //{ "Hermite", new HermiteResampler() }, //{ "Spline", new SplineResampler() }, //{ "Robidoux", new RobidouxResampler() },