Browse Source

Wire up Bgra32 to match others

Former-commit-id: 6df70bbcb522e8463342caf7c4bc19236ccd1977
Former-commit-id: dbf66da49cbb9c7de53421015fcb221a8f05a22b
Former-commit-id: cf4e7e4e2046a257d27661c57f2bb23a1a940123
af/merge-core
James Jackson-South 10 years ago
parent
commit
eba8920d18
  1. 48
      src/ImageProcessor/Colors/Color.cs
  2. 189
      src/ImageProcessor/Colors/Formats/Bgra32.cs
  3. 6
      src/ImageProcessor/Formats/Gif/Quantizer/OctreeQuantizer.cs
  4. 65
      tests/ImageProcessor.Tests/Colors/ColorTests.cs

48
src/ImageProcessor/Colors/Color.cs

@ -42,9 +42,6 @@ namespace ImageProcessor
public Color(float r, float g, float b)
: this(r, g, b, 1)
{
this.backingVector.X = r;
this.backingVector.Y = g;
this.backingVector.Z = b;
}
/// <summary>
@ -63,6 +60,51 @@ namespace ImageProcessor
this.backingVector.W = a;
}
/// <summary>
/// Initializes a new instance of the <see cref="Color"/> struct.
/// </summary>
/// <param name="hex">
/// The hexadecimal representation of the combined color components arranged
/// in rgb, rrggbb, or aarrggbb format to match web syntax.
/// </param>
public Color(string hex)
: this()
{
// Hexadecimal representations are layed out AARRGGBB to we need to do some reordering.
hex = hex.StartsWith("#") ? hex.Substring(1) : hex;
if (hex.Length != 8 && hex.Length != 6 && hex.Length != 3)
{
throw new ArgumentException("Hexadecimal string is not in the correct format.", nameof(hex));
}
if (hex.Length == 8)
{
this.R = Convert.ToByte(hex.Substring(2, 2), 16) / 255f;
this.G = Convert.ToByte(hex.Substring(4, 2), 16) / 255f;
this.B = Convert.ToByte(hex.Substring(6, 2), 16) / 255f;
this.A = Convert.ToByte(hex.Substring(0, 2), 16) / 255f;
}
else if (hex.Length == 6)
{
this.R = Convert.ToByte(hex.Substring(0, 2), 16) / 255f;
this.G = Convert.ToByte(hex.Substring(2, 2), 16) / 255f;
this.B = Convert.ToByte(hex.Substring(4, 2), 16) / 255f;
this.A = 1;
}
else
{
string r = char.ToString(hex[0]);
string g = char.ToString(hex[1]);
string b = char.ToString(hex[2]);
this.B = Convert.ToByte(b + b, 16) / 255f;
this.G = Convert.ToByte(g + g, 16) / 255f;
this.R = Convert.ToByte(r + r, 16) / 255f;
this.A = 1;
}
}
/// <summary>
/// Initializes a new instance of the <see cref="Color"/> struct.
/// </summary>

189
src/ImageProcessor/Colors/Formats/Bgra32.cs

@ -1,4 +1,4 @@
// <copyright file="Bgra.cs" company="James South">
// <copyright file="Bgra32.cs" company="James South">
// Copyright (c) James South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
@ -7,12 +7,11 @@ namespace ImageProcessor
{
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Numerics;
/// <summary>
/// Represents an BGRA (blue, green, red, alpha) color.
/// </summary>
[StructLayout(LayoutKind.Explicit)]
public struct Bgra32 : IEquatable<Bgra32>
{
/// <summary>
@ -21,157 +20,67 @@ namespace ImageProcessor
public static readonly Bgra32 Empty = default(Bgra32);
/// <summary>
/// Represents a transparent <see cref="Bgra32"/> that has B, G, R, and A values set to 255, 255, 255, 0.
/// The backing vector for SIMD support.
/// </summary>
public static readonly Bgra32 Transparent = new Bgra32(255, 255, 255, 0);
/// <summary>
/// Represents a black <see cref="Bgra32"/> that has B, G, R, and A values set to 0, 0, 0, 255.
/// </summary>
public static readonly Bgra32 Black = new Bgra32(0, 0, 0, 255);
/// <summary>
/// Represents a white <see cref="Bgra32"/> that has B, G, R, and A values set to 255, 255, 255, 255.
/// </summary>
public static readonly Bgra32 White = new Bgra32(255, 255, 255, 255);
/// <summary>
/// Holds the blue component of the color
/// </summary>
[FieldOffset(0)]
public readonly byte B;
/// <summary>
/// Holds the green component of the color
/// </summary>
[FieldOffset(1)]
public readonly byte G;
/// <summary>
/// Holds the red component of the color
/// </summary>
[FieldOffset(2)]
public readonly byte R;
/// <summary>
/// Holds the alpha component of the color
/// </summary>
[FieldOffset(3)]
public readonly byte A;
/// <summary>
/// Permits the <see cref="Bgra32"/> to be treated as a 32 bit integer.
/// </summary>
[FieldOffset(0)]
public readonly int BGRA;
private Vector4 backingVector;
/// <summary>
/// Initializes a new instance of the <see cref="Bgra32"/> struct.
/// </summary>
/// <param name="b">
/// The blue component of this <see cref="Bgra32"/>.
/// </param>
/// <param name="g">
/// The green component of this <see cref="Bgra32"/>.
/// </param>
/// <param name="r">
/// The red component of this <see cref="Bgra32"/>.
/// </param>
/// <param name="b">The blue component of this <see cref="Bgra32"/>.</param>
/// <param name="g">The green component of this <see cref="Bgra32"/>.</param>
/// <param name="r">The red component of this <see cref="Bgra32"/>.</param>
public Bgra32(byte b, byte g, byte r)
: this()
: this(b, g, r, 255)
{
this.B = b;
this.G = g;
this.R = r;
this.A = 255;
}
/// <summary>
/// Initializes a new instance of the <see cref="Bgra32"/> struct.
/// </summary>
/// <param name="b">
/// The blue component of this <see cref="Bgra32"/>.
/// </param>
/// <param name="g">
/// The green component of this <see cref="Bgra32"/>.
/// </param>
/// <param name="r">
/// The red component of this <see cref="Bgra32"/>.
/// </param>
/// <param name="a">
/// The alpha component of this <see cref="Bgra32"/>.
/// </param>
/// <param name="b">The blue component of this <see cref="Bgra32"/>.</param>
/// <param name="g">The green component of this <see cref="Bgra32"/>.</param>
/// <param name="r">The red component of this <see cref="Bgra32"/>.</param>
/// <param name="a">The alpha component of this <see cref="Bgra32"/>.</param>
public Bgra32(byte b, byte g, byte r, byte a)
: this()
{
this.B = b;
this.G = g;
this.R = r;
this.A = a;
this.backingVector.X = b.Clamp(0, 255);
this.backingVector.Y = g.Clamp(0, 255);
this.backingVector.Z = r.Clamp(0, 255);
this.backingVector.W = a.Clamp(0, 255);
}
/// <summary>
/// Initializes a new instance of the <see cref="Bgra32"/> struct.
/// Gets the blue component of the color
/// </summary>
/// <param name="bgra">
/// The combined color components.
/// </param>
public Bgra32(int bgra)
: this()
{
this.BGRA = bgra;
}
public byte B => (byte)this.backingVector.X;
/// <summary>
/// Initializes a new instance of the <see cref="Bgra32"/> struct.
/// Gets the green component of the color
/// </summary>
/// <param name="hex">
/// The hexadecimal representation of the combined color components arranged
/// in rgb, rrggbb, or aarrggbb format to match web syntax.
/// </param>
public Bgra32(string hex)
: this()
{
// Hexadecimal representations are layed out AARRGGBB to we need to do some reordering.
hex = hex.StartsWith("#") ? hex.Substring(1) : hex;
public byte G => (byte)this.backingVector.Y;
if (hex.Length != 8 && hex.Length != 6 && hex.Length != 3)
{
throw new ArgumentException("Hexadecimal string is not in the correct format.", nameof(hex));
}
/// <summary>
/// Gets the red component of the color
/// </summary>
public byte R => (byte)this.backingVector.Z;
if (hex.Length == 8)
{
this.B = Convert.ToByte(hex.Substring(6, 2), 16);
this.G = Convert.ToByte(hex.Substring(4, 2), 16);
this.R = Convert.ToByte(hex.Substring(2, 2), 16);
this.A = Convert.ToByte(hex.Substring(0, 2), 16);
}
else if (hex.Length == 6)
{
this.B = Convert.ToByte(hex.Substring(4, 2), 16);
this.G = Convert.ToByte(hex.Substring(2, 2), 16);
this.R = Convert.ToByte(hex.Substring(0, 2), 16);
this.A = 255;
}
else
{
string b = char.ToString(hex[2]);
string g = char.ToString(hex[1]);
string r = char.ToString(hex[0]);
/// <summary>
/// Gets the alpha component of the color
/// </summary>
public byte A => (byte)this.backingVector.W;
this.B = Convert.ToByte(b + b, 16);
this.G = Convert.ToByte(g + g, 16);
this.R = Convert.ToByte(r + r, 16);
this.A = 255;
}
}
/// <summary>
/// Gets the <see cref="Bgra32"/> integer representation of the color.
/// </summary>
public int Bgra => (this.R << 16) | (this.G << 8) | (this.B << 0) | (this.A << 24);
/// <summary>
/// Gets a value indicating whether this <see cref="Bgra32"/> is empty.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public bool IsEmpty => this.B == 0 && this.G == 0 && this.R == 0 && this.A == 0;
public bool IsEmpty => this.backingVector.Equals(default(Vector4));
/// <summary>
/// Allows the implicit conversion of an instance of <see cref="Color"/> to a
@ -190,9 +99,7 @@ namespace ImageProcessor
}
/// <summary>
/// Compares two <see cref="Bgra32"/> objects. The result specifies whether the values
/// of the <see cref="Bgra32.B"/>, <see cref="Bgra32.G"/>, <see cref="Bgra32.R"/>, and <see cref="Bgra32.A"/>
/// properties of the two <see cref="Bgra32"/> objects are equal.
/// Compares two <see cref="Bgra32"/> objects for equality.
/// </summary>
/// <param name="left">
/// The <see cref="Bgra32"/> on the left side of the operand.
@ -209,9 +116,7 @@ namespace ImageProcessor
}
/// <summary>
/// Compares two <see cref="Bgra32"/> objects. The result specifies whether the values
/// of the <see cref="Bgra32.B"/>, <see cref="Bgra32.G"/>, <see cref="Bgra32.R"/>, and <see cref="Bgra32.A"/>
/// properties of the two <see cref="Bgra32"/> objects are unequal.
/// Compares two <see cref="Bgra32"/> objects for inequality.
/// </summary>
/// <param name="left">
/// The <see cref="Bgra32"/> on the left side of the operand.
@ -240,7 +145,7 @@ namespace ImageProcessor
{
Bgra32 color = (Bgra32)obj;
return this.BGRA == color.BGRA;
return this.backingVector == color.backingVector;
}
return false;
@ -254,14 +159,7 @@ namespace ImageProcessor
/// </returns>
public override int GetHashCode()
{
unchecked
{
int hashCode = this.B.GetHashCode();
hashCode = (hashCode * 397) ^ this.G.GetHashCode();
hashCode = (hashCode * 397) ^ this.R.GetHashCode();
hashCode = (hashCode * 397) ^ this.A.GetHashCode();
return hashCode;
}
return GetHashCode(this);
}
/// <summary>
@ -289,7 +187,18 @@ namespace ImageProcessor
/// <param name="other">An object to compare with this object.</param>
public bool Equals(Bgra32 other)
{
return this.BGRA == other.BGRA;
return this.backingVector.Equals(other.backingVector);
}
/// <summary>
/// Returns the hash code for this instance.
/// </summary>
/// <param name="color">
/// The instance of <see cref="Cmyk"/> to return the hash code for.
/// </param>
/// <returns>
/// A 32-bit signed integer that is the hash code for this instance.
/// </returns>
private static int GetHashCode(Bgra32 color) => color.backingVector.GetHashCode();
}
}

6
src/ImageProcessor/Formats/Gif/Quantizer/OctreeQuantizer.cs

@ -195,13 +195,13 @@ namespace ImageProcessor.Formats
public void AddColor(Bgra32 pixel)
{
// Check if this request is for the same color as the last
if (this.previousColor == pixel.BGRA)
if (this.previousColor == pixel.Bgra)
{
// If so, check if I have a previous node setup. This will only occur if the first color in the image
// happens to be black, with an alpha component of zero.
if (this.previousNode == null)
{
this.previousColor = pixel.BGRA;
this.previousColor = pixel.Bgra;
this.root.AddColor(pixel, this.maxColorBits, 0, this);
}
else
@ -212,7 +212,7 @@ namespace ImageProcessor.Formats
}
else
{
this.previousColor = pixel.BGRA;
this.previousColor = pixel.Bgra;
this.root.AddColor(pixel, this.maxColorBits, 0, this);
}
}

65
tests/ImageProcessor.Tests/Colors/ColorTests.cs

@ -13,7 +13,7 @@ namespace ImageProcessor.Tests
using Xunit;
/// <summary>
/// Tests the <see cref="Bgra32"/> struct.
/// Tests the <see cref="Color"/> struct.
/// </summary>
public class ColorTests
{
@ -23,18 +23,16 @@ namespace ImageProcessor.Tests
[Fact]
public void AreEqual()
{
Bgra32 color1 = new Bgra32(0, 0, 0, 255);
Bgra32 color2 = new Bgra32(0, 0, 0, 255);
Bgra32 color3 = new Bgra32("#000");
Bgra32 color4 = new Bgra32("#000000");
Bgra32 color5 = new Bgra32("#FF000000");
Bgra32 color6 = new Bgra32(-16777216);
Color color1 = new Color(0, 0, 0);
Color color2 = new Color(0, 0, 0, 1);
Color color3 = new Color("#000");
Color color4 = new Color("#000000");
Color color5 = new Color("#FF000000");
Assert.Equal(color1, color2);
Assert.Equal(color1, color3);
Assert.Equal(color1, color4);
Assert.Equal(color1, color5);
Assert.Equal(color1, color6);
}
/// <summary>
@ -43,18 +41,16 @@ namespace ImageProcessor.Tests
[Fact]
public void AreNotEqual()
{
Bgra32 color1 = new Bgra32(255, 0, 0, 255);
Bgra32 color2 = new Bgra32(0, 0, 0, 255);
Bgra32 color3 = new Bgra32("#000");
Bgra32 color4 = new Bgra32("#000000");
Bgra32 color5 = new Bgra32("#FF000000");
Bgra32 color6 = new Bgra32(-16777216);
Color color1 = new Color(255, 0, 0, 255);
Color color2 = new Color(0, 0, 0, 255);
Color color3 = new Color("#000");
Color color4 = new Color("#000000");
Color color5 = new Color("#FF000000");
Assert.NotEqual(color1, color2);
Assert.NotEqual(color1, color3);
Assert.NotEqual(color1, color4);
Assert.NotEqual(color1, color5);
Assert.NotEqual(color1, color6);
}
/// <summary>
@ -63,29 +59,23 @@ namespace ImageProcessor.Tests
[Fact]
public void ConstructorAssignsProperties()
{
Bgra32 color1 = new Bgra32(255, 10, 34, 220);
Assert.Equal(255, color1.B);
Assert.Equal(10, color1.G);
Assert.Equal(34, color1.R);
Assert.Equal(220, color1.A);
Color color1 = new Color(1, .1f, .133f, .864f);
Assert.Equal(1, color1.R, 1);
Assert.Equal(.1f, color1.G, 1);
Assert.Equal(.133f, color1.B, 3);
Assert.Equal(.864f, color1.A, 3);
Bgra32 color2 = new Bgra32(255, 10, 34);
Assert.Equal(255, color2.B);
Assert.Equal(10, color2.G);
Assert.Equal(34, color2.R);
Assert.Equal(255, color2.A);
Color color2 = new Color(1, .1f, .133f);
Assert.Equal(1, color2.R, 1);
Assert.Equal(.1f, color2.G, 1);
Assert.Equal(.133f, color2.B, 3);
Assert.Equal(1, color2.A, 1);
Bgra32 color3 = new Bgra32(-1);
Assert.Equal(255, color3.B);
Assert.Equal(255, color3.G);
Assert.Equal(255, color3.R);
Assert.Equal(255, color3.A);
Bgra32 color4 = new Bgra32("#FF0000");
Assert.Equal(0, color4.B);
Assert.Equal(0, color4.G);
Assert.Equal(255, color4.R);
Assert.Equal(255, color4.A);
Color color3 = new Color("#FF0000");
Assert.Equal(1, color3.R, 1);
Assert.Equal(0, color3.G, 1);
Assert.Equal(0, color3.B, 3);
Assert.Equal(1, color3.A, 1);
}
/// <summary>
@ -95,7 +85,8 @@ namespace ImageProcessor.Tests
public void ConvertHex()
{
const string First = "FF000000";
string second = new Bgra32(0, 0, 0, 255).BGRA.ToString("X");
Bgra32 bgra = new Color(0, 0, 0, 1);
string second = bgra.Bgra.ToString("X");
Assert.Equal(First, second);
}
}

Loading…
Cancel
Save