diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs new file mode 100644 index 0000000000..467170d310 --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs @@ -0,0 +1,230 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace SixLabors.ImageSharp.PixelFormats +{ + /// + /// Packed pixel type containing two 16-bit normalized values representing luminance and alpha. + /// + /// Ranges from [0, 0, 0, 0] to [1, 1, 1, 1] in vector form. + /// + /// + [StructLayout(LayoutKind.Explicit)] + public struct La32 : IPixel, IPackedVector + { + private const float Max = ushort.MaxValue; + + /// + /// Gets or sets the luminance component. + /// + [FieldOffset(0)] + public ushort L; + + /// + /// Gets or sets the alpha component. + /// + [FieldOffset(2)] + public ushort A; + + /// + /// Initializes a new instance of the struct. + /// + /// The luminance component. + /// The alpha componant. + public La32(ushort l, ushort a) + { + this.L = l; + this.A = a; + } + + /// + public uint PackedValue + { + get => Unsafe.As(ref this); + + set => Unsafe.As(ref this) = value; + } + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(La32 left, La32 right) => left.Equals(right); + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is not equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(La32 left, La32 right) => !left.Equals(right); + + /// + public PixelOperations CreatePixelOperations() => new PixelOperations(); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(La32 other) => this.PackedValue.Equals(other.PackedValue); + + /// + public override bool Equals(object obj) => obj is La32 other && this.Equals(other); + + /// + public override string ToString() => $"La32({this.L}, {this.A})"; + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public override int GetHashCode() => this.PackedValue.GetHashCode(); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromArgb32(Argb32 source) + { + this.L = ImageMaths.Get16BitBT709Luminance( + ImageMaths.UpscaleFrom8BitTo16Bit(source.R), + ImageMaths.UpscaleFrom8BitTo16Bit(source.G), + ImageMaths.UpscaleFrom8BitTo16Bit(source.B)); + + this.A = ImageMaths.UpscaleFrom8BitTo16Bit(source.A); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromBgr24(Bgr24 source) + { + this.L = ImageMaths.Get16BitBT709Luminance( + ImageMaths.UpscaleFrom8BitTo16Bit(source.R), + ImageMaths.UpscaleFrom8BitTo16Bit(source.G), + ImageMaths.UpscaleFrom8BitTo16Bit(source.B)); + + this.A = ushort.MaxValue; + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromBgra32(Bgra32 source) + { + this.L = ImageMaths.Get16BitBT709Luminance( + ImageMaths.UpscaleFrom8BitTo16Bit(source.R), + ImageMaths.UpscaleFrom8BitTo16Bit(source.G), + ImageMaths.UpscaleFrom8BitTo16Bit(source.B)); + + this.A = ImageMaths.UpscaleFrom8BitTo16Bit(source.A); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromL16(L16 source) + { + this.L = source.PackedValue; + this.A = ushort.MaxValue; + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromL8(L8 source) + { + this.L = ImageMaths.UpscaleFrom8BitTo16Bit(source.PackedValue); + this.A = ushort.MaxValue; + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgb24(Rgb24 source) + { + this.L = ImageMaths.Get16BitBT709Luminance( + ImageMaths.UpscaleFrom8BitTo16Bit(source.R), + ImageMaths.UpscaleFrom8BitTo16Bit(source.G), + ImageMaths.UpscaleFrom8BitTo16Bit(source.B)); + + this.A = ushort.MaxValue; + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgb48(Rgb48 source) + { + this.L = ImageMaths.Get16BitBT709Luminance(source.R, source.G, source.B); + this.A = ushort.MaxValue; + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgba32(Rgba32 source) + { + this.L = ImageMaths.Get16BitBT709Luminance( + ImageMaths.UpscaleFrom8BitTo16Bit(source.R), + ImageMaths.UpscaleFrom8BitTo16Bit(source.G), + ImageMaths.UpscaleFrom8BitTo16Bit(source.B)); + + this.A = ImageMaths.UpscaleFrom8BitTo16Bit(source.A); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgba64(Rgba64 source) + { + this.L = ImageMaths.Get16BitBT709Luminance(source.R, source.G, source.B); + this.A = source.A; + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromScaledVector4(Vector4 vector) => this.ConvertFromRgbaScaledVector4(vector); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromVector4(Vector4 vector) => this.ConvertFromRgbaScaledVector4(vector); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void ToRgba32(ref Rgba32 dest) + { + byte rgb = ImageMaths.DownScaleFrom16BitTo8Bit(this.L); + dest.R = rgb; + dest.G = rgb; + dest.B = rgb; + dest.A = ImageMaths.DownScaleFrom16BitTo8Bit(this.A); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() + { + float scaled = this.L / Max; + return new Vector4(scaled, scaled, scaled, this.A / Max); + } + + [MethodImpl(InliningOptions.ShortMethod)] + internal void ConvertFromRgbaScaledVector4(Vector4 vector) + { + vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Max; + this.L = ImageMaths.Get16BitBT709Luminance( + vector.X, + vector.Y, + vector.Z); + + this.A = (ushort)vector.W; + } + } +}