diff --git a/src/ImageProcessor/Colors/Color.cs b/src/ImageProcessor/Colors/Color.cs new file mode 100644 index 000000000..891d30ee3 --- /dev/null +++ b/src/ImageProcessor/Colors/Color.cs @@ -0,0 +1,221 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright © James South and contributors. +// Licensed under the Apache License, Version 2.0. +// +// +// Represents an BGRA (blue, green, red, alpha) color. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor +{ + using System; + using System.ComponentModel; + using System.Globalization; + using System.Runtime.InteropServices; + + /// + /// Represents an BGRA (blue, green, red, alpha) color. + /// + [StructLayout(LayoutKind.Explicit)] + public struct Color : IEquatable + { + /// + /// Represents a that has B, G, R, and A values set to zero. + /// + public static readonly Color Empty; + + /// + /// Represents a transparent that has B, G, R, and A values set to 255, 255, 255, 0. + /// + public static readonly Color Transparent = new Color(255, 255, 255, 0); + + /// + /// Represents a black that has B, G, R, and A values set to 0, 0, 0, 0. + /// + public static readonly Color Black = new Color(0, 0, 0, 255); + + /// + /// Represents a white that has B, G, R, and A values set to 255, 255, 255, 255. + /// + public static readonly Color White = new Color(255, 255, 255, 255); + + /// + /// Holds the blue component of the color + /// + [FieldOffset(0)] + public byte B; + + /// + /// Holds the green component of the color + /// + [FieldOffset(1)] + public byte G; + + /// + /// Holds the red component of the color + /// + [FieldOffset(2)] + public byte R; + + /// + /// Holds the alpha component of the color + /// + [FieldOffset(3)] + public byte A; + + /// + /// Permits the to be treated as a 32 bit integer. + /// + [FieldOffset(0)] + public int Bgra; + + /// + /// Initializes a new instance of the struct. + /// + /// + /// The blue component of this . + /// + /// + /// The green component of this . + /// + /// + /// The red component of this . + /// + public Color(byte b, byte g, byte r) + : this() + { + this.B = b; + this.G = g; + this.R = r; + this.A = 255; + } + + /// + /// Initializes a new instance of the struct. + /// + /// + /// The blue component of this . + /// + /// + /// The green component of this . + /// + /// + /// The red component of this . + /// + /// + /// The alpha component of this . + /// + public Color(byte b, byte g, byte r, byte a) + : this() + { + this.B = b; + this.G = g; + this.R = r; + this.A = a; + } + + /// + /// Initializes a new instance of the struct. + /// + /// + /// The combined color components. + /// + public Color(int bgra) + : this() + { + this.Bgra = bgra; + } + + /// + /// Gets a value indicating whether this is empty. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public bool IsEmpty + { + get + { + return this.B == 0 && this.G == 0 && this.R == 0 && this.A == 0; + } + } + + /// + /// Indicates whether this instance and a specified object are equal. + /// + /// + /// true if and this instance are the same type and represent the same value; otherwise, false. + /// + /// Another object to compare to. + public override bool Equals(object obj) + { + if (obj is Color) + { + Color color = (Color)obj; + + return this.Bgra == color.Bgra; + } + + return false; + } + + /// + /// Returns the hash code for this instance. + /// + /// + /// A 32-bit signed integer that is the hash code for this instance. + /// + public override int GetHashCode() + { + return this.GetHashCode(this); + } + + /// + /// Returns the fully qualified type name of this instance. + /// + /// + /// A containing a fully qualified type name. + /// + public override string ToString() + { + return "{B=" + this.B.ToString(CultureInfo.CurrentCulture) + + ",G=" + this.G.ToString(CultureInfo.CurrentCulture) + + ",R=" + this.R.ToString(CultureInfo.CurrentCulture) + + ",A=" + this.A.ToString(CultureInfo.CurrentCulture) + "}"; + } + + /// + /// Indicates whether the current object is equal to another object of the same type. + /// + /// + /// True if the current object is equal to the parameter; otherwise, false. + /// + /// An object to compare with this object. + public bool Equals(Color other) + { + return this.B.Equals(other.B) && this.G.Equals(other.G) + && this.R.Equals(other.R) && this.A.Equals(other.A); + } + + /// + /// Returns the hash code for the given instance. + /// + /// + /// The instance of to return the hash code for. + /// + /// + /// A 32-bit signed integer that is the hash code for this instance. + /// + private int GetHashCode(Color obj) + { + unchecked + { + int hashCode = obj.B.GetHashCode(); + hashCode = (hashCode * 397) ^ obj.G.GetHashCode(); + hashCode = (hashCode * 397) ^ obj.R.GetHashCode(); + hashCode = (hashCode * 397) ^ obj.A.GetHashCode(); + return hashCode; + } + } + } +} diff --git a/src/ImageProcessor/Common/Exceptions/ImageFormatException.cs b/src/ImageProcessor/Common/Exceptions/ImageFormatException.cs new file mode 100644 index 000000000..90e9c3367 --- /dev/null +++ b/src/ImageProcessor/Common/Exceptions/ImageFormatException.cs @@ -0,0 +1,51 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright © James South and contributors. +// Licensed under the Apache License, Version 2.0. +// +// +// The exception that is thrown when the library tries to load +// an image, which has an invalid format. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor +{ + using System; + + /// + /// The exception that is thrown when the library tries to load + /// an image, which has an invalid format. + /// + public class ImageFormatException : Exception + { + /// + /// Initializes a new instance of the class. + /// + public ImageFormatException() + { + } + + /// + /// Initializes a new instance of the class with the name of the + /// parameter that causes this exception. + /// + /// The error message that explains the reason for this exception. + public ImageFormatException(string errorMessage) + : base(errorMessage) + { + } + + /// + /// Initializes a new instance of the class with a specified + /// error message and the exception that is the cause of this exception. + /// + /// The error message that explains the reason for this exception. + /// The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) + /// if no inner exception is specified. + public ImageFormatException(string errorMessage, Exception innerException) + : base(errorMessage, innerException) + { + } + } +} diff --git a/src/ImageProcessor/IImageBase.cs b/src/ImageProcessor/IImageBase.cs new file mode 100644 index 000000000..15a37b68e --- /dev/null +++ b/src/ImageProcessor/IImageBase.cs @@ -0,0 +1,78 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright © James South and contributors. +// Licensed under the Apache License, Version 2.0. +// +// +// Encapsulates all the basic properties and methods required to manipulate images. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor +{ + /// + /// Encapsulates all the basic properties and methods required to manipulate images. + /// + public interface IImageBase + { + /// + /// Gets the image pixels as byte array. + /// + /// + /// The returned array has a length of Width * Height * 4 bytes + /// and stores the blue, the green, the red and the alpha value for + /// each pixel in this order. + /// + byte[] Pixels { get; } + + /// + /// 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; } + + /// + /// Gets the representing the bounds of the image. + /// + Rectangle Bounds { get; } + + /// + /// Gets or sets the color of a pixel at the specified position. + /// + /// + /// The x-coordinate of the pixel. Must be greater + /// than zero and smaller than the width of the pixel. + /// + /// + /// The y-coordinate of the pixel. Must be greater + /// than zero and smaller than the width of the pixel. + /// + /// The at the specified position. + Color this[int x, int y] + { + get; + set; + } + + /// + /// Sets the pixel array of the image. + /// + /// + /// 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, width and height. + /// + void SetPixels(int width, int height, byte[] pixels); + } +} diff --git a/src/ImageProcessor/ImageBase.cs b/src/ImageProcessor/ImageBase.cs new file mode 100644 index 000000000..ae64550bb --- /dev/null +++ b/src/ImageProcessor/ImageBase.cs @@ -0,0 +1,208 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright © James South and contributors. +// Licensed under the Apache License, Version 2.0. +// +// +// The base class of all image. Encapsulates all the properties and methods +// required to manipulate images. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor +{ + using System; + + /// + /// The base class of all image. Encapsulates all the properties and methods + /// required to manipulate images. + /// + public abstract class ImageBase : IImageBase + { + /// + /// Initializes a new instance of the class. + /// + /// + /// The width of the image in pixels. + /// + /// + /// The height of the image in pixels. + /// + /// + /// Thrown if either or are less than or equal to 0. + /// + protected ImageBase(int width, int height) + { + if (width <= 0) + { + throw new ArgumentOutOfRangeException("width", "Width must be greater than or equals than zero."); + } + + if (height <= 0) + { + throw new ArgumentOutOfRangeException("height", "Height must be greater than or equal than zero."); + } + + this.Width = width; + this.Height = height; + + this.Pixels = new byte[width * height * 4]; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The other to create this instance from. + /// + /// + /// Thrown if the given is null. + /// + protected ImageBase(ImageBase other) + { + if (other == null) + { + throw new ArgumentNullException("other", "Other image cannot be null."); + } + + byte[] pixels = other.Pixels; + + this.Width = other.Width; + this.Height = other.Height; + this.Pixels = new byte[pixels.Length]; + Array.Copy(pixels, this.Pixels, pixels.Length); + } + + /// + /// Gets the image pixels as byte array. + /// + /// + /// The returned array has a length of Width * Height * 4 bytes + /// and stores the blue, the green, the red and the alpha value for + /// each pixel in this order. + /// + public byte[] 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 + { + get { return (double)this.Width / this.Height; } + } + + /// + /// Gets the representing the bounds of the image. + /// + public Rectangle Bounds + { + get + { + return new Rectangle(0, 0, this.Width, this.Height); + } + } + + /// + /// Gets or sets the color of a pixel at the specified position. + /// + /// + /// The x-coordinate of the pixel. Must be greater + /// than zero and smaller than the width of the pixel. + /// + /// + /// The y-coordinate of the pixel. Must be greater + /// than zero and smaller than the width of the pixel. + /// + /// The at the specified position. + public Color this[int x, int y] + { + get + { +#if DEBUG + if ((x < 0) || (x >= this.Width)) + { + throw new ArgumentOutOfRangeException("x", "Value cannot be less than zero or greater than the bitmap width."); + } + + if ((y < 0) || (y >= this.Width)) + { + throw new ArgumentOutOfRangeException("y", "Value cannot be less than zero or greater than the bitmap height."); + } +#endif + + int start = ((y * this.Width) + x) * 4; + return new Color(this.Pixels[start], this.Pixels[start + 1], this.Pixels[start + 2], this.Pixels[start + 3]); + } + + set + { +#if DEBUG + if ((x < 0) || (x >= this.Width)) + { + throw new ArgumentOutOfRangeException("x", "Value cannot be less than zero or greater than the bitmap width."); + } + + if ((y < 0) || (y >= this.Width)) + { + throw new ArgumentOutOfRangeException("y", "Value cannot be less than zero or greater than the bitmap height."); + } +#endif + + int start = ((y * this.Width) + x) * 4; + + this.Pixels[start + 0] = value.B; + this.Pixels[start + 1] = value.G; + this.Pixels[start + 2] = value.R; + this.Pixels[start + 3] = value.A; + } + } + + /// + /// Sets the pixel array of the image. + /// + /// + /// 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, width and height. + /// + /// + /// Thrown if either or are less than or equal to 0. + /// + /// + /// Thrown if the length is not equal to Width * Height * 4. + /// + public void SetPixels(int width, int height, byte[] pixels) + { + if (width <= 0) + { + throw new ArgumentOutOfRangeException("width", "Width must be greater than or equals than zero."); + } + + if (height <= 0) + { + throw new ArgumentOutOfRangeException("height", "Height must be greater than or equal than zero."); + } + + if (pixels.Length != width * height * 4) + { + throw new ArgumentException("Pixel array must have the length of Width * Height * 4."); + } + + this.Width = width; + this.Height = height; + this.Pixels = pixels; + } + } +} diff --git a/src/ImageProcessor/ImageProcessor.csproj b/src/ImageProcessor/ImageProcessor.csproj index 3630bb695..02f70a50e 100644 --- a/src/ImageProcessor/ImageProcessor.csproj +++ b/src/ImageProcessor/ImageProcessor.csproj @@ -35,13 +35,16 @@ - + + + + diff --git a/src/ImageProcessor/ImageProcessor.csproj.DotSettings b/src/ImageProcessor/ImageProcessor.csproj.DotSettings index 0eb119984..bb65870ee 100644 --- a/src/ImageProcessor/ImageProcessor.csproj.DotSettings +++ b/src/ImageProcessor/ImageProcessor.csproj.DotSettings @@ -1,4 +1,5 @@  + True True True True