|
|
|
@ -1,15 +1,15 @@ |
|
|
|
// Copyright (c) Six Labors and contributors.
|
|
|
|
// Licensed under the Apache License, Version 2.0.
|
|
|
|
|
|
|
|
using System; |
|
|
|
using System.Numerics; |
|
|
|
using System.Runtime.CompilerServices; |
|
|
|
using System.Runtime.InteropServices; |
|
|
|
|
|
|
|
namespace SixLabors.ImageSharp.PixelFormats |
|
|
|
{ |
|
|
|
/// <summary>
|
|
|
|
/// Packed pixel type containing four 8-bit unsigned normalized values ranging from 0 to 255.
|
|
|
|
/// The color components are stored in alpha, red, green, and blue order.
|
|
|
|
/// The color components are stored in alpha, red, green, and blue order (least significant to most significant byte).
|
|
|
|
/// <para>
|
|
|
|
/// Ranges from [0, 0, 0, 0] to [1, 1, 1, 1] in vector form.
|
|
|
|
/// </para>
|
|
|
|
@ -18,27 +18,28 @@ namespace SixLabors.ImageSharp.PixelFormats |
|
|
|
/// This struct is fully mutable. This is done (against the guidelines) for the sake of performance,
|
|
|
|
/// as it avoids the need to create new values for modification operations.
|
|
|
|
/// </remarks>
|
|
|
|
[StructLayout(LayoutKind.Sequential)] |
|
|
|
public struct Argb32 : IPixel<Argb32>, IPackedVector<uint> |
|
|
|
{ |
|
|
|
/// <summary>
|
|
|
|
/// The shift count for the blue component
|
|
|
|
/// Gets or sets the alpha component.
|
|
|
|
/// </summary>
|
|
|
|
private const int BlueShift = 0; |
|
|
|
public byte A; |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// The shift count for the green component
|
|
|
|
/// Gets or sets the red component.
|
|
|
|
/// </summary>
|
|
|
|
private const int GreenShift = 8; |
|
|
|
public byte R; |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// The shift count for the red component
|
|
|
|
/// Gets or sets the green component.
|
|
|
|
/// </summary>
|
|
|
|
private const int RedShift = 16; |
|
|
|
public byte G; |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// The shift count for the alpha component
|
|
|
|
/// Gets or sets the blue component.
|
|
|
|
/// </summary>
|
|
|
|
private const int AlphaShift = 24; |
|
|
|
public byte B; |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// The maximum byte value.
|
|
|
|
@ -56,11 +57,13 @@ namespace SixLabors.ImageSharp.PixelFormats |
|
|
|
/// <param name="r">The red component.</param>
|
|
|
|
/// <param name="g">The green component.</param>
|
|
|
|
/// <param name="b">The blue component.</param>
|
|
|
|
/// <param name="a">The alpha component.</param>
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|
|
|
public Argb32(byte r, byte g, byte b, byte a) |
|
|
|
public Argb32(byte r, byte g, byte b) |
|
|
|
{ |
|
|
|
this.PackedValue = Pack(r, g, b, a); |
|
|
|
this.R = r; |
|
|
|
this.G = g; |
|
|
|
this.B = b; |
|
|
|
this.A = 255; |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
@ -69,10 +72,14 @@ namespace SixLabors.ImageSharp.PixelFormats |
|
|
|
/// <param name="r">The red component.</param>
|
|
|
|
/// <param name="g">The green component.</param>
|
|
|
|
/// <param name="b">The blue component.</param>
|
|
|
|
/// <param name="a">The alpha component.</param>
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|
|
|
public Argb32(byte r, byte g, byte b) |
|
|
|
public Argb32(byte r, byte g, byte b, byte a) |
|
|
|
{ |
|
|
|
this.PackedValue = Pack(r, g, b, 255); |
|
|
|
this.R = r; |
|
|
|
this.G = g; |
|
|
|
this.B = b; |
|
|
|
this.A = a; |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
@ -82,9 +89,11 @@ namespace SixLabors.ImageSharp.PixelFormats |
|
|
|
/// <param name="g">The green component.</param>
|
|
|
|
/// <param name="b">The blue component.</param>
|
|
|
|
/// <param name="a">The alpha component.</param>
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|
|
|
public Argb32(float r, float g, float b, float a = 1) |
|
|
|
: this() |
|
|
|
{ |
|
|
|
this.PackedValue = Pack(r, g, b, a); |
|
|
|
this.Pack(r, g, b, a); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
@ -93,9 +102,11 @@ namespace SixLabors.ImageSharp.PixelFormats |
|
|
|
/// <param name="vector">
|
|
|
|
/// The vector containing the components for the packed vector.
|
|
|
|
/// </param>
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|
|
|
public Argb32(Vector3 vector) |
|
|
|
: this() |
|
|
|
{ |
|
|
|
this.PackedValue = Pack(ref vector); |
|
|
|
this.Pack(ref vector); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
@ -104,9 +115,11 @@ namespace SixLabors.ImageSharp.PixelFormats |
|
|
|
/// <param name="vector">
|
|
|
|
/// The vector containing the components for the packed vector.
|
|
|
|
/// </param>
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|
|
|
public Argb32(Vector4 vector) |
|
|
|
: this() |
|
|
|
{ |
|
|
|
this.PackedValue = Pack(ref vector); |
|
|
|
this.Pack(ref vector); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
@ -115,84 +128,30 @@ namespace SixLabors.ImageSharp.PixelFormats |
|
|
|
/// <param name="packed">
|
|
|
|
/// The packed value.
|
|
|
|
/// </param>
|
|
|
|
public Argb32(uint packed = 0) |
|
|
|
{ |
|
|
|
this.PackedValue = packed; |
|
|
|
} |
|
|
|
|
|
|
|
/// <inheritdoc/>
|
|
|
|
public uint PackedValue { get; set; } |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Gets or sets the red component.
|
|
|
|
/// </summary>
|
|
|
|
public byte R |
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|
|
|
public Argb32(uint packed) |
|
|
|
: this() |
|
|
|
{ |
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|
|
|
get |
|
|
|
{ |
|
|
|
return (byte)(this.PackedValue >> RedShift); |
|
|
|
} |
|
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|
|
|
set |
|
|
|
{ |
|
|
|
this.PackedValue = this.PackedValue & 0xFF00FFFF | (uint)value << RedShift; |
|
|
|
} |
|
|
|
this.Argb = packed; |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Gets or sets the green component.
|
|
|
|
/// Gets or sets the packed representation of the Argb32 struct.
|
|
|
|
/// </summary>
|
|
|
|
public byte G |
|
|
|
public uint Argb |
|
|
|
{ |
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|
|
|
get |
|
|
|
{ |
|
|
|
return (byte)(this.PackedValue >> GreenShift); |
|
|
|
} |
|
|
|
get => Unsafe.As<Argb32, uint>(ref this); |
|
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|
|
|
set |
|
|
|
{ |
|
|
|
this.PackedValue = this.PackedValue & 0xFFFF00FF | (uint)value << GreenShift; |
|
|
|
} |
|
|
|
set => Unsafe.As<Argb32, uint>(ref this) = value; |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Gets or sets the blue component.
|
|
|
|
/// </summary>
|
|
|
|
public byte B |
|
|
|
/// <inheritdoc/>
|
|
|
|
public uint PackedValue |
|
|
|
{ |
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|
|
|
get |
|
|
|
{ |
|
|
|
return (byte)(this.PackedValue >> BlueShift); |
|
|
|
} |
|
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|
|
|
set |
|
|
|
{ |
|
|
|
this.PackedValue = this.PackedValue & 0xFFFFFF00 | (uint)value << BlueShift; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Gets or sets the alpha component.
|
|
|
|
/// </summary>
|
|
|
|
public byte A |
|
|
|
{ |
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|
|
|
get |
|
|
|
{ |
|
|
|
return (byte)(this.PackedValue >> AlphaShift); |
|
|
|
} |
|
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|
|
|
set |
|
|
|
{ |
|
|
|
this.PackedValue = this.PackedValue & 0x00FFFFFF | (uint)value << AlphaShift; |
|
|
|
} |
|
|
|
get => this.Argb; |
|
|
|
set => this.Argb = value; |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
@ -210,7 +169,7 @@ namespace SixLabors.ImageSharp.PixelFormats |
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|
|
|
public static bool operator ==(Argb32 left, Argb32 right) |
|
|
|
{ |
|
|
|
return left.PackedValue == right.PackedValue; |
|
|
|
return left.Argb == right.Argb; |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
@ -224,14 +183,14 @@ namespace SixLabors.ImageSharp.PixelFormats |
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|
|
|
public static bool operator !=(Argb32 left, Argb32 right) |
|
|
|
{ |
|
|
|
return left.PackedValue != right.PackedValue; |
|
|
|
return left.Argb != right.Argb; |
|
|
|
} |
|
|
|
|
|
|
|
/// <inheritdoc/>
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|
|
|
public void PackFromVector4(Vector4 vector) |
|
|
|
{ |
|
|
|
this.PackedValue = Pack(ref vector); |
|
|
|
this.Pack(ref vector); |
|
|
|
} |
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
@ -262,7 +221,27 @@ namespace SixLabors.ImageSharp.PixelFormats |
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|
|
|
public void PackFromRgba32(Rgba32 source) |
|
|
|
{ |
|
|
|
this.PackedValue = Pack(source.R, source.G, source.B, source.A); |
|
|
|
this.R = source.R; |
|
|
|
this.G = source.G; |
|
|
|
this.B = source.B; |
|
|
|
this.A = source.A; |
|
|
|
} |
|
|
|
|
|
|
|
/// <inheritdoc/>
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|
|
|
public void PackFromArgb32(Argb32 source) |
|
|
|
{ |
|
|
|
this.PackedValue = source.PackedValue; |
|
|
|
} |
|
|
|
|
|
|
|
/// <inheritdoc/>
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|
|
|
public void PackFromBgra32(Bgra32 source) |
|
|
|
{ |
|
|
|
this.R = source.R; |
|
|
|
this.G = source.G; |
|
|
|
this.B = source.B; |
|
|
|
this.A = source.A; |
|
|
|
} |
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
@ -284,6 +263,13 @@ namespace SixLabors.ImageSharp.PixelFormats |
|
|
|
dest.A = this.A; |
|
|
|
} |
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|
|
|
public void ToArgb32(ref Argb32 dest) |
|
|
|
{ |
|
|
|
dest = this; |
|
|
|
} |
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|
|
|
public void ToBgr24(ref Bgr24 dest) |
|
|
|
@ -303,17 +289,47 @@ namespace SixLabors.ImageSharp.PixelFormats |
|
|
|
dest.A = this.A; |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Converts the pixel to <see cref="Rgba32"/> format.
|
|
|
|
/// </summary>
|
|
|
|
/// <returns>The RGBA value</returns>
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|
|
|
public Rgba32 ToRgba32() => new Rgba32(this.R, this.G, this.B, this.A); |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Converts the pixel to <see cref="Bgra32"/> format.
|
|
|
|
/// </summary>
|
|
|
|
/// <returns>The RGBA value</returns>
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|
|
|
public Bgra32 ToBgra32() => new Bgra32(this.R, this.G, this.B, this.A); |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Converts the pixel to <see cref="Argb32"/> format.
|
|
|
|
/// </summary>
|
|
|
|
/// <returns>The RGBA value</returns>
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|
|
|
public Argb32 ToArgb32() => this; |
|
|
|
|
|
|
|
/// <inheritdoc/>
|
|
|
|
public override bool Equals(object obj) |
|
|
|
{ |
|
|
|
return obj is Argb32 && this.Equals((Argb32)obj); |
|
|
|
return obj is Argb32 argb32 && this.Equals(argb32); |
|
|
|
} |
|
|
|
|
|
|
|
/// <inheritdoc/>
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|
|
|
public bool Equals(Argb32 other) |
|
|
|
{ |
|
|
|
return this.PackedValue == other.PackedValue; |
|
|
|
return this.Argb == other.Argb; |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Gets a string representation of the packed vector.
|
|
|
|
/// </summary>
|
|
|
|
/// <returns>A string representation of the packed vector.</returns>
|
|
|
|
public override string ToString() |
|
|
|
{ |
|
|
|
return $"({this.R},{this.G},{this.B},{this.A})"; |
|
|
|
} |
|
|
|
|
|
|
|
/// <inheritdoc/>
|
|
|
|
@ -321,65 +337,59 @@ namespace SixLabors.ImageSharp.PixelFormats |
|
|
|
public override int GetHashCode() |
|
|
|
{ |
|
|
|
// ReSharper disable once NonReadonlyMemberInGetHashCode
|
|
|
|
return this.PackedValue.GetHashCode(); |
|
|
|
return this.Argb.GetHashCode(); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Packs the four floats into a <see cref="uint"/>.
|
|
|
|
/// Gets the <see cref="Vector4"/> representation without normalizing to [0, 1]
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="x">The x-component</param>
|
|
|
|
/// <param name="y">The y-component</param>
|
|
|
|
/// <param name="z">The z-component</param>
|
|
|
|
/// <param name="w">The w-component</param>
|
|
|
|
/// <returns>The <see cref="uint"/></returns>
|
|
|
|
/// <returns>A <see cref="Vector4"/> of values in [0, 255] </returns>
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|
|
|
private static uint Pack(float x, float y, float z, float w) |
|
|
|
internal Vector4 ToByteScaledVector4() |
|
|
|
{ |
|
|
|
var value = new Vector4(x, y, z, w); |
|
|
|
return Pack(ref value); |
|
|
|
return new Vector4(this.R, this.G, this.B, this.A); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Packs the four floats into a <see cref="uint"/>.
|
|
|
|
/// Packs the four floats into a color.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="x">The x-component</param>
|
|
|
|
/// <param name="y">The y-component</param>
|
|
|
|
/// <param name="z">The z-component</param>
|
|
|
|
/// <param name="w">The w-component</param>
|
|
|
|
/// <returns>The <see cref="uint"/></returns>
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|
|
|
private static uint Pack(byte x, byte y, byte z, byte w) |
|
|
|
private void Pack(float x, float y, float z, float w) |
|
|
|
{ |
|
|
|
return (uint)(x << RedShift | y << GreenShift | z << BlueShift | w << AlphaShift); |
|
|
|
var value = new Vector4(x, y, z, w); |
|
|
|
this.Pack(ref value); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Packs a <see cref="Vector3"/> into a uint.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="vector">The vector containing the values to pack.</param>
|
|
|
|
/// <returns>The <see cref="uint"/> containing the packed values.</returns>
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|
|
|
private static uint Pack(ref Vector3 vector) |
|
|
|
private void Pack(ref Vector3 vector) |
|
|
|
{ |
|
|
|
var value = new Vector4(vector, 1); |
|
|
|
return Pack(ref value); |
|
|
|
this.Pack(ref value); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Packs a <see cref="Vector4"/> into a uint.
|
|
|
|
/// Packs a <see cref="Vector4"/> into a color.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="vector">The vector containing the values to pack.</param>
|
|
|
|
/// <returns>The <see cref="uint"/> containing the packed values.</returns>
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|
|
|
private static uint Pack(ref Vector4 vector) |
|
|
|
private void Pack(ref Vector4 vector) |
|
|
|
{ |
|
|
|
vector *= MaxBytes; |
|
|
|
vector += Half; |
|
|
|
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); |
|
|
|
return (uint)(((byte)vector.X << RedShift) |
|
|
|
| ((byte)vector.Y << GreenShift) |
|
|
|
| ((byte)vector.Z << BlueShift) |
|
|
|
| (byte)vector.W << AlphaShift); |
|
|
|
|
|
|
|
this.R = (byte)vector.X; |
|
|
|
this.G = (byte)vector.Y; |
|
|
|
this.B = (byte)vector.Z; |
|
|
|
this.A = (byte)vector.W; |
|
|
|
} |
|
|
|
} |
|
|
|
} |