Browse Source

Add Bgr565

pull/33/head
James Jackson-South 10 years ago
parent
commit
c184861afc
  1. 2
      src/ImageSharp/Colors/Color.cs
  2. 2
      src/ImageSharp/Colors/PackedPixel/Alpha8.cs
  3. 171
      src/ImageSharp/Colors/PackedPixel/Bgr565.cs
  4. 3
      src/ImageSharp/Colors/PackedPixel/README.md
  5. 69
      tests/ImageSharp.Tests/Colors/PackedVectorTests.cs

2
src/ImageSharp/Colors/Color.cs

@ -219,7 +219,7 @@ namespace ImageSharp
/// <param name="left">The <see cref="Color"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="Color"/> on the right side of the operand.</param>
/// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
public static bool operator !=(Color left, Color right)
{

2
src/ImageSharp/Colors/PackedPixel/Alpha8.cs

@ -50,7 +50,7 @@ namespace ImageSharp
/// <param name="left">The <see cref="Alpha8"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="Alpha8"/> on the right side of the operand.</param>
/// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
public static bool operator !=(Alpha8 left, Alpha8 right)
{

171
src/ImageSharp/Colors/PackedPixel/Bgr565.cs

@ -0,0 +1,171 @@
// <copyright file="Bgr565.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System;
using System.Numerics;
/// <summary>
/// Packed vector type containing unsigned normalized values ranging from 0 to 1.
/// The x and z components use 5 bits, and the y component uses 6 bits.
/// </summary>
public struct Bgr565 : IPackedPixel<ushort>, IEquatable<Bgr565>
{
/// <summary>
/// Initializes a new instance of the <see cref="Bgr565"/> struct.
/// </summary>
/// <param name="x">The x-component</param>
/// <param name="y">The y-component</param>
/// <param name="z">The z-component</param>
public Bgr565(float x, float y, float z)
{
this.PackedValue = Pack(x, y, z);
}
/// <summary>
/// Initializes a new instance of the <see cref="Bgr565"/> struct.
/// </summary>
/// <param name="vector">
/// The vector containing the components for the packed value.
/// </param>
public Bgr565(Vector3 vector)
{
this.PackedValue = Pack(vector.X, vector.Y, vector.Z);
}
/// <inheritdoc />
public ushort PackedValue { get; set; }
/// <summary>
/// Compares two <see cref="Bgr565"/> objects for equality.
/// </summary>
/// <param name="left">The <see cref="Bgr565"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="Bgr565"/> on the right side of the operand.</param>
/// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
public static bool operator ==(Bgr565 left, Bgr565 right)
{
return left.PackedValue == right.PackedValue;
}
/// <summary>
/// Compares two <see cref="Bgr565"/> objects for equality.
/// </summary>
/// <param name="left">The <see cref="Bgr565"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="Bgr565"/> on the right side of the operand.</param>
/// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
public static bool operator !=(Bgr565 left, Bgr565 right)
{
return left.PackedValue != right.PackedValue;
}
/// <summary>
/// Expands the packed representation into a <see cref="Vector3"/>.
/// The vector components are typically expanded in least to greatest significance order.
/// </summary>
/// <returns>The <see cref="Vector3"/>.</returns>
public Vector3 ToVector3()
{
return new Vector3(
((this.PackedValue >> 11) & 0x1F) * (1F / 31F),
((this.PackedValue >> 5) & 0x3F) * (1F / 63F),
(this.PackedValue & 0x1F) * (1F / 31F));
}
/// <inheritdoc />
public void PackFromVector4(Vector4 vector)
{
this.PackedValue = Pack(vector.X, vector.Y, vector.Z);
}
/// <inheritdoc />
public Vector4 ToVector4()
{
return new Vector4(this.ToVector3(), 1F);
}
/// <inheritdoc />
public void PackFromBytes(byte x, byte y, byte z, byte w)
{
this.PackFromVector4(new Vector4(x, y, z, w) / 255F);
}
/// <inheritdoc />
public void ToBytes(byte[] bytes, int startIndex, ComponentOrder componentOrder)
{
Vector4 vector = this.ToVector4() * 255F;
switch (componentOrder)
{
case ComponentOrder.ZYX:
bytes[startIndex] = (byte)vector.Z;
bytes[startIndex + 1] = (byte)vector.Y;
bytes[startIndex + 2] = (byte)vector.X;
break;
case ComponentOrder.ZYXW:
bytes[startIndex] = (byte)vector.Z;
bytes[startIndex + 1] = (byte)vector.Y;
bytes[startIndex + 2] = (byte)vector.X;
bytes[startIndex + 3] = (byte)vector.W;
break;
case ComponentOrder.XYZ:
bytes[startIndex] = (byte)vector.X;
bytes[startIndex + 1] = (byte)vector.Y;
bytes[startIndex + 2] = (byte)vector.Z;
break;
case ComponentOrder.XYZW:
bytes[startIndex] = (byte)vector.X;
bytes[startIndex + 1] = (byte)vector.Y;
bytes[startIndex + 2] = (byte)vector.Z;
bytes[startIndex + 3] = (byte)vector.W;
break;
default:
throw new NotSupportedException();
}
}
/// <inheritdoc />
public override bool Equals(object obj)
{
return (obj is Bgr565) && this.Equals((Bgr565)obj);
}
/// <inheritdoc />
public bool Equals(Bgr565 other)
{
return this.PackedValue == other.PackedValue;
}
/// <inheritdoc />
public override string ToString()
{
return this.ToVector3().ToString();
}
/// <inheritdoc />
public override int GetHashCode()
{
return this.PackedValue.GetHashCode();
}
/// <summary>
/// Packs a <see cref="float"/> components into a <see cref="ushort"/>.
/// </summary>
/// <param name="x">The x-component</param>
/// <param name="y">The y-component</param>
/// <param name="z">The z-component</param>
/// <returns>The <see cref="ushort"/> containing the packed values.</returns>
private static ushort Pack(float x, float y, float z)
{
return (ushort)((((int)Math.Round(x.Clamp(0, 1) * 31F) & 0x1F) << 11) |
(((int)Math.Round(y.Clamp(0, 1) * 63F) & 0x3F) << 5) |
((int)Math.Round(z.Clamp(0, 1) * 31F) & 0x1F));
}
}
}

3
src/ImageSharp/Colors/PackedPixel/README.md

@ -0,0 +1,3 @@
Pixel formats adapted and extended from:
https://github.com/MonoGame/MonoGame

69
tests/ImageSharp.Tests/Colors/PackedVectorTests.cs

@ -5,6 +5,7 @@
namespace ImageSharp.Tests.Colors
{
using System;
using System.Numerics;
using Xunit;
@ -31,6 +32,7 @@ namespace ImageSharp.Tests.Colors
// Test ordering
Vector4 vector = new Alpha8(.5F).ToVector4();
Assert.Equal(vector.X, 0);
Assert.Equal(vector.Y, 0);
Assert.Equal(vector.Z, 0);
@ -53,5 +55,72 @@ namespace ImageSharp.Tests.Colors
new Alpha8(.5F).ToBytes(rgb, 0, ComponentOrder.ZYXW);
Assert.Equal(bgra, new byte[] { 0, 0, 0, 128 });
}
[Fact]
public void Bgr565()
{
// Test the limits.
Assert.Equal(0x0, new Bgr565(Vector3.Zero).PackedValue);
Assert.Equal(0xFFFF, new Bgr565(Vector3.One).PackedValue);
// Test ToVector3.
Assert.True(Equal(Vector3.One, new Bgr565(Vector3.One).ToVector3()));
Assert.True(Equal(Vector3.Zero, new Bgr565(Vector3.Zero).ToVector3()));
Assert.True(Equal(Vector3.UnitX, new Bgr565(Vector3.UnitX).ToVector3()));
Assert.True(Equal(Vector3.UnitY, new Bgr565(Vector3.UnitY).ToVector3()));
Assert.True(Equal(Vector3.UnitZ, new Bgr565(Vector3.UnitZ).ToVector3()));
// Test clamping.
Assert.True(Equal(Vector3.Zero, new Bgr565(Vector3.One * -1234F).ToVector3()));
Assert.True(Equal(Vector3.One, new Bgr565(Vector3.One * 1234F).ToVector3()));
// Make sure the swizzle is correct.
Assert.Equal(0xF800, new Bgr565(Vector3.UnitX).PackedValue);
Assert.Equal(0x07E0, new Bgr565(Vector3.UnitY).PackedValue);
Assert.Equal(0x001F, new Bgr565(Vector3.UnitZ).PackedValue);
float x = 0.1F;
float y = -0.3F;
float z = 0.5F;
Assert.Equal(6160, new Bgr565(x, y, z).PackedValue);
byte[] rgb = new byte[3];
byte[] rgba = new byte[4];
byte[] bgr = new byte[3];
byte[] bgra = new byte[4];
new Bgr565(x, y, z).ToBytes(rgb, 0, ComponentOrder.XYZ);
Assert.Equal(rgb, new byte[] { 24, 0, 131 });
new Bgr565(x, y, z).ToBytes(rgba, 0, ComponentOrder.XYZW);
Assert.Equal(rgba, new byte[] { 24, 0, 131, 255 });
new Bgr565(x, y, z).ToBytes(bgr, 0, ComponentOrder.ZYX);
Assert.Equal(bgr, new byte[] { 131, 0, 24 });
new Bgr565(x, y, z).ToBytes(bgra, 0, ComponentOrder.ZYXW);
Assert.Equal(bgra, new byte[] { 131, 0, 24, 255 });
}
// Comparison helpers with small tolerance to allow for floating point rounding during computations.
public static bool Equal(float a, float b)
{
return Math.Abs(a - b) < 1e-5;
}
public static bool Equal(Vector2 a, Vector2 b)
{
return Equal(a.X, b.X) && Equal(a.Y, b.Y);
}
public static bool Equal(Vector3 a, Vector3 b)
{
return Equal(a.X, b.X) && Equal(a.Y, b.Y) && Equal(a.Z, b.Z);
}
public static bool Equal(Vector4 a, Vector4 b)
{
return Equal(a.X, b.X) && Equal(a.Y, b.Y) && Equal(a.Z, b.Z) && Equal(a.W, b.W);
}
}
}
Loading…
Cancel
Save