diff --git a/src/ImageProcessorCore/Bootstrapper.cs b/src/ImageProcessorCore/Bootstrapper.cs
index 2076fab19a..a611119921 100644
--- a/src/ImageProcessorCore/Bootstrapper.cs
+++ b/src/ImageProcessorCore/Bootstrapper.cs
@@ -73,13 +73,14 @@ namespace ImageProcessorCore
/// The type of pixel data.
/// The image
/// The
- public IPixelAccessor GetPixelAccessor(IImageBase image)
- where T : IPackedVector, new()
+ public IPixelAccessor GetPixelAccessor(IImageBase image)
+ where T : IPackedVector, new()
+ where TP : struct
{
Type packed = typeof(T);
if (this.pixelAccessors.ContainsKey(packed))
{
- return (IPixelAccessor)this.pixelAccessors[packed].Invoke(image);
+ return (IPixelAccessor)this.pixelAccessors[packed].Invoke(image);
}
throw new NotSupportedException($"PixelAccessor cannot be loaded for {packed}:");
diff --git a/src/ImageProcessorCore/Common/Helpers/Operator.cs b/src/ImageProcessorCore/Common/Helpers/Operator.cs
index fc09a0c7be..8d0d03caae 100644
--- a/src/ImageProcessorCore/Common/Helpers/Operator.cs
+++ b/src/ImageProcessorCore/Common/Helpers/Operator.cs
@@ -260,6 +260,9 @@
}
private static readonly Func add, subtract, multiply, divide;
+
+ private static readonly Func multiplyF, divideF;
+
///
/// Returns a delegate to evaluate binary addition (+) for the given types; this delegate will throw
/// an InvalidOperationException if the type T does not provide this operator, or for
@@ -287,6 +290,10 @@
/// Nullable<TInner> if TInner does not provide this operator.
///
public static Func Divide => divide;
+
+ public static Func MultiplyF => multiplyF;
+
+ public static Func DivideF => divideF;
}
///
@@ -344,6 +351,8 @@
static readonly Func add, subtract, multiply, divide;
+ static readonly Func multiplyF, divideF;
+
///
/// Returns a delegate to evaluate binary addition (+) for the given type; this delegate will throw
/// an InvalidOperationException if the type T does not provide this operator, or for
@@ -372,8 +381,12 @@
///
public static Func Divide => divide;
+ public static Func MultiplyF => multiplyF;
+
+ public static Func DivideF => divideF;
+
static readonly Func equal, notEqual, greaterThan, lessThan, greaterThanOrEqual, lessThanOrEqual;
-
+
///
/// Returns a delegate to evaluate binary equality (==) for the given type; this delegate will throw
/// an InvalidOperationException if the type T does not provide this operator, or for
@@ -422,6 +435,8 @@
subtract = ExpressionUtil.CreateExpression(Expression.Subtract);
divide = ExpressionUtil.CreateExpression(Expression.Divide);
multiply = ExpressionUtil.CreateExpression(Expression.Multiply);
+ multiplyF = ExpressionUtil.CreateExpression(Expression.Multiply);
+ divideF = ExpressionUtil.CreateExpression(Expression.Multiply);
greaterThan = ExpressionUtil.CreateExpression(Expression.GreaterThan);
greaterThanOrEqual = ExpressionUtil.CreateExpression(Expression.GreaterThanOrEqual);
diff --git a/src/ImageProcessorCore/Formats/Bmp/BmpDecoder.cs b/src/ImageProcessorCore/Formats/Bmp/BmpDecoder.cs
index 5565fd690b..916bddce7b 100644
--- a/src/ImageProcessorCore/Formats/Bmp/BmpDecoder.cs
+++ b/src/ImageProcessorCore/Formats/Bmp/BmpDecoder.cs
@@ -74,8 +74,9 @@ namespace ImageProcessorCore.Formats
///
/// The to decode to.
/// The containing image data.
- public void Decode(Image image, Stream stream)
- where T : IPackedVector, new()
+ public void Decode(Image image, Stream stream)
+ where T : IPackedVector, new()
+ where TP : struct
{
new BmpDecoderCore().Decode(image, stream);
}
diff --git a/src/ImageProcessorCore/Formats/Bmp/BmpDecoderCore.cs b/src/ImageProcessorCore/Formats/Bmp/BmpDecoderCore.cs
index 56e2d2e2a5..faa0113697 100644
--- a/src/ImageProcessorCore/Formats/Bmp/BmpDecoderCore.cs
+++ b/src/ImageProcessorCore/Formats/Bmp/BmpDecoderCore.cs
@@ -59,8 +59,9 @@ namespace ImageProcessorCore.Formats
/// - or -
/// is null.
///
- public void Decode(Image image, Stream stream)
- where T : IPackedVector, new()
+ public void Decode(Image image, Stream stream)
+ where T : IPackedVector, new()
+ where TP : struct
{
this.currentStream = stream;
@@ -132,25 +133,19 @@ namespace ImageProcessorCore.Formats
if (this.infoHeader.BitsPerPixel == 32)
{
- this.ReadRgb32(imageData, this.infoHeader.Width, this.infoHeader.Height, inverted);
+ this.ReadRgb32(imageData, this.infoHeader.Width, this.infoHeader.Height, inverted);
}
else if (this.infoHeader.BitsPerPixel == 24)
{
- this.ReadRgb24(imageData, this.infoHeader.Width, this.infoHeader.Height, inverted);
+ this.ReadRgb24(imageData, this.infoHeader.Width, this.infoHeader.Height, inverted);
}
else if (this.infoHeader.BitsPerPixel == 16)
{
- this.ReadRgb16(imageData, this.infoHeader.Width, this.infoHeader.Height, inverted);
+ this.ReadRgb16(imageData, this.infoHeader.Width, this.infoHeader.Height, inverted);
}
else if (this.infoHeader.BitsPerPixel <= 8)
{
- this.ReadRgbPalette(
- imageData,
- palette,
- this.infoHeader.Width,
- this.infoHeader.Height,
- this.infoHeader.BitsPerPixel,
- inverted);
+ this.ReadRgbPalette(imageData, palette, this.infoHeader.Width, this.infoHeader.Height, this.infoHeader.BitsPerPixel, inverted);
}
break;
@@ -199,8 +194,9 @@ namespace ImageProcessorCore.Formats
/// The height of the bitmap.
/// The number of bits per pixel.
/// Whether the bitmap is inverted.
- private void ReadRgbPalette(T[] imageData, byte[] colors, int width, int height, int bits, bool inverted)
- where T : IPackedVector, new()
+ private void ReadRgbPalette(T[] imageData, byte[] colors, int width, int height, int bits, bool inverted)
+ where T : IPackedVector, new()
+ where TP : struct
{
// Pixels per byte (bits per pixel)
int ppb = 8 / bits;
@@ -259,8 +255,9 @@ namespace ImageProcessorCore.Formats
/// The width of the bitmap.
/// The height of the bitmap.
/// Whether the bitmap is inverted.
- private void ReadRgb16(T[] imageData, int width, int height, bool inverted)
- where T : IPackedVector, new()
+ private void ReadRgb16(T[] imageData, int width, int height, bool inverted)
+ where T : IPackedVector, new()
+ where TP : struct
{
// We divide here as we will store the colors in our floating point format.
const int ScaleR = 8; // 256/32
@@ -307,8 +304,9 @@ namespace ImageProcessorCore.Formats
/// The width of the bitmap.
/// The height of the bitmap.
/// Whether the bitmap is inverted.
- private void ReadRgb24(T[] imageData, int width, int height, bool inverted)
- where T : IPackedVector, new()
+ private void ReadRgb24(T[] imageData, int width, int height, bool inverted)
+ where T : IPackedVector, new()
+ where TP : struct
{
int alignment;
byte[] data = this.GetImageArray(width, height, 3, out alignment);
@@ -345,8 +343,9 @@ namespace ImageProcessorCore.Formats
/// The width of the bitmap.
/// The height of the bitmap.
/// Whether the bitmap is inverted.
- private void ReadRgb32(T[] imageData, int width, int height, bool inverted)
- where T : IPackedVector, new()
+ private void ReadRgb32(T[] imageData, int width, int height, bool inverted)
+ where T : IPackedVector, new()
+ where TP : struct
{
int alignment;
byte[] data = this.GetImageArray(width, height, 4, out alignment);
diff --git a/src/ImageProcessorCore/Formats/Bmp/BmpEncoder.cs b/src/ImageProcessorCore/Formats/Bmp/BmpEncoder.cs
index f58f6b85f4..07ada9c05a 100644
--- a/src/ImageProcessorCore/Formats/Bmp/BmpEncoder.cs
+++ b/src/ImageProcessorCore/Formats/Bmp/BmpEncoder.cs
@@ -43,8 +43,9 @@ namespace ImageProcessorCore.Formats
}
///
- public void Encode(ImageBase image, Stream stream)
- where T : IPackedVector, new()
+ public void Encode(ImageBase image, Stream stream)
+ where T : IPackedVector, new()
+ where TP : struct
{
BmpEncoderCore encoder = new BmpEncoderCore();
encoder.Encode(image, stream, this.BitsPerPixel);
diff --git a/src/ImageProcessorCore/Formats/Bmp/BmpEncoderCore.cs b/src/ImageProcessorCore/Formats/Bmp/BmpEncoderCore.cs
index 1df95592a2..cc26ea700c 100644
--- a/src/ImageProcessorCore/Formats/Bmp/BmpEncoderCore.cs
+++ b/src/ImageProcessorCore/Formats/Bmp/BmpEncoderCore.cs
@@ -28,8 +28,9 @@ namespace ImageProcessorCore.Formats
/// The to encode from.
/// The to encode the image data to.
/// The
- public void Encode(ImageBase image, Stream stream, BmpBitsPerPixel bitsPerPixel)
- where T : IPackedVector, new()
+ public void Encode(ImageBase image, Stream stream, BmpBitsPerPixel bitsPerPixel)
+ where T : IPackedVector, new()
+ where TP : struct
{
Guard.NotNull(image, nameof(image));
Guard.NotNull(stream, nameof(stream));
@@ -127,8 +128,9 @@ namespace ImageProcessorCore.Formats
///
/// The containing pixel data.
///
- private void WriteImage(EndianBinaryWriter writer, ImageBase image)
- where T : IPackedVector, new()
+ private void WriteImage(EndianBinaryWriter writer, ImageBase image)
+ where T : IPackedVector, new()
+ where TP : struct
{
// TODO: Add more compression formats.
int amount = (image.Width * (int)this.bmpBitsPerPixel) % 4;
@@ -137,7 +139,7 @@ namespace ImageProcessorCore.Formats
amount = 4 - amount;
}
- using (IPixelAccessor pixels = image.Lock())
+ using (IPixelAccessor pixels = image.Lock())
{
switch (this.bmpBitsPerPixel)
{
@@ -159,8 +161,9 @@ namespace ImageProcessorCore.Formats
/// The containing the stream to write to.
/// The containing pixel data.
/// The amount to pad each row by.
- private void Write32bit(EndianBinaryWriter writer, IPixelAccessor pixels, int amount)
- where T : IPackedVector, new()
+ private void Write32bit(EndianBinaryWriter writer, IPixelAccessor pixels, int amount)
+ where T : IPackedVector, new()
+ where TP : struct
{
for (int y = pixels.Height - 1; y >= 0; y--)
{
@@ -185,8 +188,9 @@ namespace ImageProcessorCore.Formats
/// The containing the stream to write to.
/// The containing pixel data.
/// The amount to pad each row by.
- private void Write24bit(EndianBinaryWriter writer, IPixelAccessor pixels, int amount)
- where T : IPackedVector, new()
+ private void Write24bit(EndianBinaryWriter writer, IPixelAccessor pixels, int amount)
+ where T : IPackedVector, new()
+ where TP : struct
{
for (int y = pixels.Height - 1; y >= 0; y--)
{
diff --git a/src/ImageProcessorCore/Formats/IImageDecoder.cs b/src/ImageProcessorCore/Formats/IImageDecoder.cs
index 3c5676bac4..09dbcdb1e7 100644
--- a/src/ImageProcessorCore/Formats/IImageDecoder.cs
+++ b/src/ImageProcessorCore/Formats/IImageDecoder.cs
@@ -44,7 +44,8 @@ namespace ImageProcessorCore.Formats
/// The type of pixels contained within the image.
/// The to decode to.
/// The containing image data.
- void Decode(Image image, Stream stream)
- where T : IPackedVector, new();
+ void Decode(Image image, Stream stream)
+ where T : IPackedVector, new()
+ where TP : struct;
}
}
diff --git a/src/ImageProcessorCore/Formats/IImageEncoder.cs b/src/ImageProcessorCore/Formats/IImageEncoder.cs
index 6e83c11ae9..7738968631 100644
--- a/src/ImageProcessorCore/Formats/IImageEncoder.cs
+++ b/src/ImageProcessorCore/Formats/IImageEncoder.cs
@@ -48,7 +48,8 @@ namespace ImageProcessorCore.Formats
/// The type of pixels contained within the image.
/// The to encode from.
/// The to encode the image data to.
- void Encode(ImageBase image, Stream stream)
- where T : IPackedVector, new();
+ void Encode(ImageBase image, Stream stream)
+ where T : IPackedVector,
+ new() where TP : struct;
}
}
diff --git a/src/ImageProcessorCore/IImageFrame.cs b/src/ImageProcessorCore/IImageFrame.cs
deleted file mode 100644
index fc92b9306e..0000000000
--- a/src/ImageProcessorCore/IImageFrame.cs
+++ /dev/null
@@ -1,7 +0,0 @@
-namespace ImageProcessorCore
-{
- public interface IImageFrame : IImageBase
- where T : IPackedVector, new()
- {
- }
-}
diff --git a/src/ImageProcessorCore/Image.cs b/src/ImageProcessorCore/Image.cs
index 35eaff2434..3cb8866bbb 100644
--- a/src/ImageProcessorCore/Image.cs
+++ b/src/ImageProcessorCore/Image.cs
@@ -1,292 +1,22 @@
-//
-// Copyright (c) James Jackson-South and contributors.
-// Licensed under the Apache License, Version 2.0.
-//
+using System.IO;
namespace ImageProcessorCore
{
- using System.IO;
- using System.Text;
-
- using System;
- 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 packed vector containing pixel information.
- ///
- public class Image : ImageBase
- where T : IPackedVector, new()
+ public class Image : Image
{
- ///
- /// 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(BmpFormat));
- }
-
- ///
- /// 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.
+ // TODO Constructors.
public Image(int width, int height)
- : base(width, height)
+ : base(width, height)
{
- // TODO: Change to PNG
- this.CurrentImageFormat = Bootstrapper.Instance.ImageFormats.First(f => f.GetType() == typeof(BmpFormat));
}
- ///
- /// Initializes a new instance of the class.
- ///
- ///
- /// The stream containing image information.
- ///
- /// Thrown if the is null.
public Image(Stream stream)
+ : base(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)
- {
- foreach (ImageFrame frame in other.Frames)
- {
- if (frame != null)
- {
- this.Frames.Add(new ImageFrame(frame));
- }
- }
-
- this.RepeatCount = other.RepeatCount;
- this.HorizontalResolution = other.HorizontalResolution;
- this.VerticalResolution = other.VerticalResolution;
- 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 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)
+ public Image(Image other)
+ : base(other)
{
- 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/IImageBase.cs b/src/ImageProcessorCore/Image/IImageBase.cs
similarity index 82%
rename from src/ImageProcessorCore/IImageBase.cs
rename to src/ImageProcessorCore/Image/IImageBase.cs
index 4b78df66c0..256a238f3b 100644
--- a/src/ImageProcessorCore/IImageBase.cs
+++ b/src/ImageProcessorCore/Image/IImageBase.cs
@@ -2,12 +2,16 @@
namespace ImageProcessorCore
{
- public interface IImageBase : IImageBase
- where T : IPackedVector, new()
+ public interface IImageBase : IImageBase
+ where T : IPackedVector, new()
+ where TP : struct
{
T[] Pixels { get; }
+
void ClonePixels(int width, int height, T[] pixels);
- IPixelAccessor Lock();
+
+ IPixelAccessor Lock();
+
void SetPixels(int width, int height, T[] pixels);
}
diff --git a/src/ImageProcessorCore/Image/IImageFrame.cs b/src/ImageProcessorCore/Image/IImageFrame.cs
new file mode 100644
index 0000000000..744716fafe
--- /dev/null
+++ b/src/ImageProcessorCore/Image/IImageFrame.cs
@@ -0,0 +1,8 @@
+namespace ImageProcessorCore
+{
+ public interface IImageFrame : IImageBase
+ where T : IPackedVector, new()
+ where TP : struct
+ {
+ }
+}
diff --git a/src/ImageProcessorCore/IImageProcessor.cs b/src/ImageProcessorCore/Image/IImageProcessor.cs
similarity index 89%
rename from src/ImageProcessorCore/IImageProcessor.cs
rename to src/ImageProcessorCore/Image/IImageProcessor.cs
index 76bc9851c6..6e92c7c8cf 100644
--- a/src/ImageProcessorCore/IImageProcessor.cs
+++ b/src/ImageProcessorCore/Image/IImageProcessor.cs
@@ -45,8 +45,9 @@ namespace ImageProcessorCore.Processors
///
/// doesnt fit the dimension of the image.
///
- void Apply(ImageBase target, ImageBase source, Rectangle sourceRectangle)
- where T : IPackedVector, new();
+ void Apply(ImageBase target, ImageBase source, Rectangle sourceRectangle)
+ where T : IPackedVector,
+ new() where TP : struct;
///
/// Applies the process to the specified portion of the specified at the specified
@@ -68,7 +69,8 @@ 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)
- where T : IPackedVector, new();
+ void Apply(ImageBase target, ImageBase source, int width, int height, Rectangle targetRectangle, Rectangle sourceRectangle)
+ where T : IPackedVector, new()
+ where TP : struct;
}
}
diff --git a/src/ImageProcessorCore/Image/Image.cs b/src/ImageProcessorCore/Image/Image.cs
new file mode 100644
index 0000000000..890feb9f89
--- /dev/null
+++ b/src/ImageProcessorCore/Image/Image.cs
@@ -0,0 +1,293 @@
+//
+// 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.Collections.Generic;
+ using System.Linq;
+
+ using Formats;
+
+ ///
+ /// Encapsulates an image, which consists of the pixel data for a graphics image and its attributes.
+ ///
+ ///
+ /// The packed vector containing pixel information.
+ ///
+ public class Image : ImageBase
+ where T : IPackedVector, new()
+ where TP : struct
+ {
+ ///
+ /// 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(BmpFormat));
+ }
+
+ ///
+ /// 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)
+ {
+ // TODO: Change to PNG
+ this.CurrentImageFormat = Bootstrapper.Instance.ImageFormats.First(f => f.GetType() == typeof(BmpFormat));
+ }
+
+ ///
+ /// 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)
+ {
+ foreach (ImageFrame frame in other.Frames)
+ {
+ if (frame != null)
+ {
+ this.Frames.Add(new ImageFrame(frame));
+ }
+ }
+
+ this.RepeatCount = other.RepeatCount;
+ this.HorizontalResolution = other.HorizontalResolution;
+ this.VerticalResolution = other.VerticalResolution;
+ 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 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/ImageBase.cs b/src/ImageProcessorCore/Image/ImageBase.cs
similarity index 94%
rename from src/ImageProcessorCore/ImageBase.cs
rename to src/ImageProcessorCore/Image/ImageBase.cs
index 357f490010..ec455f271d 100644
--- a/src/ImageProcessorCore/ImageBase.cs
+++ b/src/ImageProcessorCore/Image/ImageBase.cs
@@ -14,18 +14,19 @@ namespace ImageProcessorCore
///
/// The packed vector pixels format.
///
- public abstract class ImageBase : IImageBase
- where T : IPackedVector, new()
+ public abstract class ImageBase : IImageBase
+ where T : IPackedVector, new()
+ where TP : struct
{
///
- /// Initializes a new instance of the class.
+ /// Initializes a new instance of the class.
///
protected ImageBase()
{
}
///
- /// Initializes a new instance of the class.
+ /// Initializes a new instance of the class.
///
/// The width of the image in pixels.
/// The height of the image in pixels.
@@ -43,15 +44,15 @@ namespace ImageProcessorCore
}
///
- /// Initializes a new instance of the class.
+ /// Initializes a new instance of the class.
///
///
- /// The other to create this instance from.
+ /// The other to create this instance from.
///
///
- /// Thrown if the given is null.
+ /// Thrown if the given is null.
///
- protected ImageBase(ImageBase other)
+ protected ImageBase(ImageBase other)
{
Guard.NotNull(other, nameof(other), "Other image cannot be null.");
@@ -196,6 +197,6 @@ namespace ImageProcessorCore
///
///
/// The
- public abstract IPixelAccessor Lock();
+ public abstract IPixelAccessor Lock();
}
}
diff --git a/src/ImageProcessorCore/ImageExtensions.cs b/src/ImageProcessorCore/Image/ImageExtensions.cs
similarity index 84%
rename from src/ImageProcessorCore/ImageExtensions.cs
rename to src/ImageProcessorCore/Image/ImageExtensions.cs
index c30607ce94..c38f951a8d 100644
--- a/src/ImageProcessorCore/ImageExtensions.cs
+++ b/src/ImageProcessorCore/Image/ImageExtensions.cs
@@ -61,8 +61,9 @@ namespace ImageProcessorCore
/// The image this method extends.
/// The processor to apply to the image.
/// The .
- public static Image Process(this Image source, IImageProcessor processor)
- where T : IPackedVector, new()
+ public static Image Process(this Image source, IImageProcessor processor)
+ where T : IPackedVector, new()
+ where TP : struct
{
return Process(source, source.Bounds, processor);
}
@@ -78,8 +79,9 @@ namespace ImageProcessorCore
///
/// The processors to apply to the image.
/// The .
- public static Image Process(this Image source, Rectangle sourceRectangle, IImageProcessor processor)
- where T : IPackedVector, new()
+ public static Image Process(this Image source, Rectangle sourceRectangle, IImageProcessor processor)
+ where T : IPackedVector, new()
+ where TP : struct
{
return PerformAction(source, true, (sourceImage, targetImage) => processor.Apply(targetImage, sourceImage, sourceRectangle));
}
@@ -96,8 +98,9 @@ namespace ImageProcessorCore
/// The target image height.
/// The processor to apply to the image.
/// The .
- public static Image Process(this Image source, int width, int height, IImageSampler sampler)
- where T : IPackedVector, new()
+ public static Image Process(this Image source, int width, int height, IImageSampler sampler)
+ where T : IPackedVector, new()
+ where TP : struct
{
return Process(source, width, height, source.Bounds, default(Rectangle), sampler);
}
@@ -121,8 +124,9 @@ namespace ImageProcessorCore
///
/// The processor to apply to the image.
/// The .
- public static Image Process(this Image source, int width, int height, Rectangle sourceRectangle, Rectangle targetRectangle, IImageSampler sampler)
- where T : IPackedVector, new()
+ public static Image Process(this Image source, int width, int height, Rectangle sourceRectangle, Rectangle targetRectangle, IImageSampler sampler)
+ where T : IPackedVector, new()
+ where TP : struct
{
return PerformAction(source, false, (sourceImage, targetImage) => sampler.Apply(targetImage, sourceImage, width, height, targetRectangle, sourceRectangle));
}
@@ -135,12 +139,13 @@ namespace ImageProcessorCore
/// Whether to clone the image.
/// The to perform against the image.
/// The .
- private static Image PerformAction(Image source, bool clone, Action, ImageBase> action)
- where T : IPackedVector, new()
+ private static Image PerformAction(Image source, bool clone, Action, ImageBase> action)
+ where T : IPackedVector, new()
+ where TP : struct
{
- Image transformedImage = clone
- ? new Image(source)
- : new Image
+ Image transformedImage = clone
+ ? new Image(source)
+ : new Image
{
// Several properties require copying
// TODO: Check why we need to set these?
@@ -154,10 +159,10 @@ namespace ImageProcessorCore
for (int i = 0; i < source.Frames.Count; i++)
{
- ImageFrame sourceFrame = source.Frames[i];
- ImageFrame tranformedFrame = clone
- ? new ImageFrame(sourceFrame)
- : new ImageFrame { FrameDelay = sourceFrame.FrameDelay };
+ ImageFrame sourceFrame = source.Frames[i];
+ ImageFrame tranformedFrame = clone
+ ? new ImageFrame(sourceFrame)
+ : new ImageFrame { FrameDelay = sourceFrame.FrameDelay };
action(sourceFrame, tranformedFrame);
diff --git a/src/ImageProcessorCore/ImageFrame.cs b/src/ImageProcessorCore/Image/ImageFrame.cs
similarity index 75%
rename from src/ImageProcessorCore/ImageFrame.cs
rename to src/ImageProcessorCore/Image/ImageFrame.cs
index 790591b182..0846dc7783 100644
--- a/src/ImageProcessorCore/ImageFrame.cs
+++ b/src/ImageProcessorCore/Image/ImageFrame.cs
@@ -11,8 +11,9 @@ namespace ImageProcessorCore
///
/// The packed vector containing pixel information.
///
- public class ImageFrame : ImageBase
- where T : IPackedVector, new()
+ public class ImageFrame : ImageBase
+ where T : IPackedVector, new()
+ where TP : struct
{
///
/// Initializes a new instance of the class.
@@ -27,15 +28,15 @@ namespace ImageProcessorCore
///
/// The frame to create the frame from.
///
- public ImageFrame(ImageFrame frame)
+ public ImageFrame(ImageFrame frame)
: base(frame)
{
}
///
- public override IPixelAccessor Lock()
+ public override IPixelAccessor Lock()
{
- return Bootstrapper.Instance.GetPixelAccessor(this);
+ return Bootstrapper.Instance.GetPixelAccessor(this);
}
}
}
diff --git a/src/ImageProcessorCore/ImageProperty.cs b/src/ImageProcessorCore/Image/ImageProperty.cs
similarity index 100%
rename from src/ImageProcessorCore/ImageProperty.cs
rename to src/ImageProcessorCore/Image/ImageProperty.cs
diff --git a/src/ImageProcessorCore/ImageProcessor.cs b/src/ImageProcessorCore/ImageProcessor.cs
index 380e5c6340..bfa8eacdfc 100644
--- a/src/ImageProcessorCore/ImageProcessor.cs
+++ b/src/ImageProcessorCore/ImageProcessor.cs
@@ -27,8 +27,9 @@ namespace ImageProcessorCore.Processors
private int totalRows;
///
- public void Apply(ImageBase target, ImageBase source, Rectangle sourceRectangle)
- where T : IPackedVector, new()
+ public void Apply(ImageBase target, ImageBase source, Rectangle sourceRectangle)
+ where T : IPackedVector, new()
+ where TP : struct
{
try
{
@@ -49,8 +50,9 @@ namespace ImageProcessorCore.Processors
}
///
- public void Apply(ImageBase target, ImageBase source, int width, int height, Rectangle targetRectangle = default(Rectangle), Rectangle sourceRectangle = default(Rectangle))
- where T : IPackedVector, new()
+ public void Apply(ImageBase target, ImageBase source, int width, int height, Rectangle targetRectangle = default(Rectangle), Rectangle sourceRectangle = default(Rectangle))
+ where T : IPackedVector, new()
+ where TP : struct
{
try
{
@@ -95,8 +97,9 @@ 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)
- where T : IPackedVector, new()
+ protected virtual void OnApply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle)
+ where T : IPackedVector, new()
+ where TP : struct
{
}
@@ -120,8 +123,9 @@ 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)
- where T : IPackedVector, new();
+ protected abstract void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY)
+ where T : IPackedVector, new()
+ where TP : struct;
///
/// This method is called after the process is applied to prepare the processor.
@@ -136,8 +140,9 @@ 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)
- where T : IPackedVector, new()
+ protected virtual void AfterApply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle)
+ where T : IPackedVector, new()
+ where TP : struct
{
}
diff --git a/src/ImageProcessorCore/PackedVector/Bgra32.cs b/src/ImageProcessorCore/PackedVector/Bgra32.cs
index d1a692e5d5..9c1848aab4 100644
--- a/src/ImageProcessorCore/PackedVector/Bgra32.cs
+++ b/src/ImageProcessorCore/PackedVector/Bgra32.cs
@@ -2,7 +2,6 @@
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
//
-
namespace ImageProcessorCore
{
using System;
@@ -11,8 +10,19 @@ namespace ImageProcessorCore
///
/// Packed vector type containing four 8-bit unsigned normalized values ranging from 0 to 1.
///
- public struct Bgra32 : IPackedVector, IEquatable
+ public unsafe struct Bgra32 : IPackedVector, IEquatable
{
+ const uint B_MASK = 0x000000FF;
+ const uint G_MASK = 0x0000FF00;
+ const uint R_MASK = 0x00FF0000;
+ const uint A_MASK = 0xFF000000;
+ const int B_SHIFT = 0;
+ const int G_SHIFT = 8;
+ const int R_SHIFT = 16;
+ const int A_SHIFT = 24;
+
+ private uint packedValue;
+
///
/// Initializes a new instance of the struct.
///
@@ -23,7 +33,7 @@ namespace ImageProcessorCore
public Bgra32(float b, float g, float r, float a)
{
Vector4 clamped = Vector4.Clamp(new Vector4(b, g, r, a), Vector4.Zero, Vector4.One) * 255f;
- this.PackedValue = Pack(ref clamped);
+ this.packedValue = Pack(ref clamped);
}
///
@@ -35,42 +45,191 @@ namespace ImageProcessorCore
public Bgra32(Vector4 vector)
{
Vector4 clamped = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * 255f;
- this.PackedValue = Pack(ref clamped);
+ this.packedValue = Pack(ref clamped);
+ }
+
+ public byte B
+ {
+ get
+ {
+ return (byte)(this.packedValue & B_MASK);
+ }
+
+ set
+ {
+ this.packedValue = (this.packedValue & ~B_MASK) | value;
+ }
+ }
+
+ public byte G
+ {
+ get
+ {
+ return (byte)((this.packedValue & G_MASK) >> G_SHIFT);
+ }
+
+ set
+ {
+ this.packedValue = (this.packedValue & ~G_MASK) | (((uint)value) << G_SHIFT);
+ }
+ }
+
+ public byte R
+ {
+ get
+ {
+ return (byte)((this.packedValue & R_MASK) >> R_SHIFT);
+ }
+
+ set
+ {
+ this.packedValue = (this.packedValue & ~R_MASK) | (((uint)value) << R_SHIFT);
+ }
+ }
+
+ public byte A
+ {
+ get
+ {
+ return (byte)((this.packedValue & A_MASK) >> A_SHIFT);
+ }
+
+ set
+ {
+ this.packedValue = (this.packedValue & ~A_MASK) | (((uint)value) << A_SHIFT);
+ }
}
///
- public uint PackedValue { get; set; }
+ public uint PackedValue()
+ {
+ return this.packedValue;
+ }
+
+ public void Add(TP value) where TP : IPackedVector
+ {
+ // this.PackVector(this.ToVector4() + value.ToVector4());
+ }
+
+ public void Subtract(TP value) where TP : IPackedVector
+ {
+ // this.PackVector(this.ToVector4() - value.ToVector4());
+ }
- // The maths are wrong here I just wanted to test the performance to see if the
- // issues are caused by the Vector transform or something else.
- public void Add(IPackedVector value)
+ public void Multiply(TP value) where TP : IPackedVector
{
+ // this.PackVector(this.ToVector4() * value.ToVector4());
+ }
+ public void Multiply(float value) where TP : IPackedVector
+ {
+ this.B = (byte)(this.B * value);
+ this.G = (byte)(this.G * value);
+ this.R = (byte)(this.R * value);
+ this.A = (byte)(this.A * value);
}
- public void Subtract(IPackedVector value)
+ public void Divide(TP value) where TP : IPackedVector
{
+ // this.PackVector(this.ToVector4() / value.ToVector4());
+ }
+ public void Divide(float value) where TP : IPackedVector
+ {
+ this.B = (byte)(this.B / value);
+ this.G = (byte)(this.G / value);
+ this.R = (byte)(this.R / value);
+ this.A = (byte)(this.A / value);
}
- public void Multiply(IPackedVector value)
+ ///
+ /// Computes the product of multiplying a Bgra32 by a given factor.
+ ///
+ /// The Bgra32.
+ /// The multiplication factor.
+ ///
+ /// The
+ ///
+ public static Bgra32 operator *(Bgra32 value, float factor)
{
+ byte b = (byte)(value.B * factor);
+ byte g = (byte)(value.G * factor);
+ byte r = (byte)(value.R * factor);
+ byte a = (byte)(value.A * factor);
+ return new Bgra32(b, g, r, a);
}
- public void Multiply(float value)
+ ///
+ /// Computes the product of multiplying a Bgra32 by a given factor.
+ ///
+ /// The multiplication factor.
+ /// The Bgra32.
+ ///
+ /// The
+ ///
+ public static Bgra32 operator *(float factor, Bgra32 value)
{
+ byte b = (byte)(value.B * factor);
+ byte g = (byte)(value.G * factor);
+ byte r = (byte)(value.R * factor);
+ byte a = (byte)(value.A * factor);
+ return new Bgra32(b, g, r, a);
}
- public void Divide(IPackedVector value)
+ ///
+ /// Computes the product of multiplying two Bgra32s.
+ ///
+ /// The Bgra32 on the left hand of the operand.
+ /// The Bgra32 on the right hand of the operand.
+ ///
+ /// The
+ ///
+ public static Bgra32 operator *(Bgra32 left, Bgra32 right)
+ {
+ byte b = (byte)(left.B * right.B);
+ byte g = (byte)(left.G * right.G);
+ byte r = (byte)(left.R * right.R);
+ byte a = (byte)(left.A * right.A);
+
+ return new Bgra32(b, g, r, a);
+ }
+
+ ///
+ /// Computes the sum of adding two Bgra32s.
+ ///
+ /// The Bgra32 on the left hand of the operand.
+ /// The Bgra32 on the right hand of the operand.
+ ///
+ /// The
+ ///
+ public static Bgra32 operator +(Bgra32 left, Bgra32 right)
{
+ byte b = (byte)(left.B + right.B);
+ byte g = (byte)(left.G + right.G);
+ byte r = (byte)(left.R + right.R);
+ byte a = (byte)(left.A + right.A);
+ return new Bgra32(b, g, r, a);
}
- public void Divide(float value)
+ ///
+ /// Computes the difference left by subtracting one Bgra32 from another.
+ ///
+ /// The Bgra32 on the left hand of the operand.
+ /// The Bgra32 on the right hand of the operand.
+ ///
+ /// The
+ ///
+ public static Bgra32 operator -(Bgra32 left, Bgra32 right)
{
+ byte b = (byte)(left.B - right.B);
+ byte g = (byte)(left.G - right.G);
+ byte r = (byte)(left.R - right.R);
+ byte a = (byte)(left.A - right.A);
+ return new Bgra32(b, g, r, a);
}
///
@@ -87,7 +246,7 @@ namespace ImageProcessorCore
///
public static bool operator ==(Bgra32 left, Bgra32 right)
{
- return left.PackedValue == right.PackedValue;
+ return left.packedValue == right.packedValue;
}
///
@@ -100,31 +259,30 @@ namespace ImageProcessorCore
///
public static bool operator !=(Bgra32 left, Bgra32 right)
{
- return left.PackedValue != right.PackedValue;
+ return left.packedValue != right.packedValue;
}
///
public void PackVector(Vector4 vector)
{
Vector4 clamped = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * 255f;
- this.PackedValue = Pack(ref clamped);
+ this.packedValue = Pack(ref clamped);
}
///
public void PackBytes(byte x, byte y, byte z, byte w)
{
- Vector4 vector = new Vector4(x, y, z, w);
- this.PackedValue = Pack(ref vector);
+ this.packedValue = Pack(ref x, ref y, ref z, ref w);
}
///
public Vector4 ToVector4()
{
return new Vector4(
- this.PackedValue & 0xFF,
- (this.PackedValue >> 8) & 0xFF,
- (this.PackedValue >> 16) & 0xFF,
- (this.PackedValue >> 24) & 0xFF) / 255f;
+ this.packedValue & 0xFF,
+ (this.packedValue >> 8) & 0xFF,
+ (this.packedValue >> 16) & 0xFF,
+ (this.packedValue >> 24) & 0xFF) / 255f;
}
///
@@ -132,11 +290,11 @@ namespace ImageProcessorCore
{
return new[]
{
- (byte)(this.PackedValue & 0xFF),
- (byte)((this.PackedValue >> 8) & 0xFF),
- (byte)((this.PackedValue >> 16) & 0xFF),
- (byte)((this.PackedValue >> 24) & 0xFF)
- };
+ (byte)(this.packedValue & 0xFF),
+ (byte)((this.packedValue >> 8) & 0xFF),
+ (byte)((this.packedValue >> 16) & 0xFF),
+ (byte)((this.packedValue >> 24) & 0xFF)
+ };
}
///
@@ -148,7 +306,7 @@ namespace ImageProcessorCore
///
public bool Equals(Bgra32 other)
{
- return this.PackedValue == other.PackedValue;
+ return this.packedValue == other.packedValue;
}
///
@@ -178,9 +336,14 @@ namespace ImageProcessorCore
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);
+ ((uint)Math.Round(vector.Y) << 8) |
+ ((uint)Math.Round(vector.Z) << 16) |
+ ((uint)Math.Round(vector.W) << 24);
+ }
+
+ private static uint Pack(ref byte x, ref byte y, ref byte z, ref byte w)
+ {
+ return x | ((uint)y << 8) | ((uint)z << 16) | ((uint)w << 24);
}
///
@@ -194,7 +357,7 @@ namespace ImageProcessorCore
///
private int GetHashCode(Bgra32 packed)
{
- return packed.PackedValue.GetHashCode();
+ return packed.packedValue.GetHashCode();
}
}
}
diff --git a/src/ImageProcessorCore/PackedVector/IPackedVector.cs b/src/ImageProcessorCore/PackedVector/IPackedVector.cs
index 90d52b27f5..2beeb2c809 100644
--- a/src/ImageProcessorCore/PackedVector/IPackedVector.cs
+++ b/src/ImageProcessorCore/PackedVector/IPackedVector.cs
@@ -18,12 +18,22 @@ namespace ImageProcessorCore
where T : struct
{
///
- /// Gets or sets the packed representation of the value.
+ /// Gets the packed representation of the value.
/// Typically packed in least to greatest significance order.
///
- T PackedValue { get; set; }
+ T PackedValue();
+ void Add(TP value) where TP : IPackedVector;
+ void Subtract(TP value) where TP : IPackedVector;
+
+ void Multiply(TP value) where TP : IPackedVector;
+
+ void Multiply(float value) where TP : IPackedVector;
+
+ void Divide(TP value) where TP : IPackedVector;
+
+ void Divide(float value) where TP : IPackedVector;
}
///
@@ -31,30 +41,6 @@ namespace ImageProcessorCore
///
public interface IPackedVector
{
- //void Add(U value);
-
- //void Subtract(U value);
-
- //void Multiply(U value);
-
- //void Multiply(float value);
-
- //void Divide(U value);
-
- //void Divide(float value);
-
- void Add(IPackedVector value);
-
- void Subtract(IPackedVector value);
-
- void Multiply(IPackedVector value);
-
- void Multiply(float value);
-
- void Divide(IPackedVector value);
-
- void Divide(float value);
-
///
/// Sets the packed representation from a .
///
diff --git a/src/ImageProcessorCore/PixelAccessor/Bgra32PixelAccessor.cs b/src/ImageProcessorCore/PixelAccessor/Bgra32PixelAccessor.cs
index f9fa7005bc..c48090d7b2 100644
--- a/src/ImageProcessorCore/PixelAccessor/Bgra32PixelAccessor.cs
+++ b/src/ImageProcessorCore/PixelAccessor/Bgra32PixelAccessor.cs
@@ -15,8 +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 Bgra32PixelAccessor : IPixelAccessor
-
+ public sealed unsafe class Bgra32PixelAccessor : IPixelAccessor
{
///