mirror of https://github.com/SixLabors/ImageSharp
committed by
GitHub
85 changed files with 3361 additions and 1353 deletions
@ -0,0 +1,135 @@ |
|||
// <copyright file="Bgr24.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp.PixelFormats |
|||
{ |
|||
using System; |
|||
using System.Numerics; |
|||
using System.Runtime.CompilerServices; |
|||
using System.Runtime.InteropServices; |
|||
|
|||
/// <summary>
|
|||
/// Pixel type containing three 8-bit unsigned normalized values ranging from 0 to 255.
|
|||
/// The color components are stored in blue, green, red order.
|
|||
/// </summary>
|
|||
[StructLayout(LayoutKind.Sequential)] |
|||
public struct Bgr24 : IPixel<Bgr24> |
|||
{ |
|||
/// <summary>
|
|||
/// The blue component.
|
|||
/// </summary>
|
|||
public byte B; |
|||
|
|||
/// <summary>
|
|||
/// The green component.
|
|||
/// </summary>
|
|||
public byte G; |
|||
|
|||
/// <summary>
|
|||
/// The red component.
|
|||
/// </summary>
|
|||
public byte R; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Bgr24"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="r">The red component.</param>
|
|||
/// <param name="g">The green component.</param>
|
|||
/// <param name="b">The blue component.</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public Bgr24(byte r, byte g, byte b) |
|||
{ |
|||
this.R = r; |
|||
this.G = g; |
|||
this.B = b; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public PixelOperations<Bgr24> CreatePixelOperations() => new PixelOperations<Bgr24>(); |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public bool Equals(Bgr24 other) |
|||
{ |
|||
return this.R == other.R && this.G == other.G && this.B == other.B; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override bool Equals(object obj) |
|||
{ |
|||
return obj?.GetType() == typeof(Bgr24) && this.Equals((Bgr24)obj); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public override int GetHashCode() |
|||
{ |
|||
unchecked |
|||
{ |
|||
int hashCode = this.B; |
|||
hashCode = (hashCode * 397) ^ this.G; |
|||
hashCode = (hashCode * 397) ^ this.R; |
|||
return hashCode; |
|||
} |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void PackFromRgba32(Rgba32 source) |
|||
{ |
|||
this = source.Bgr; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void PackFromVector4(Vector4 vector) |
|||
{ |
|||
var rgba = default(Rgba32); |
|||
rgba.PackFromVector4(vector); |
|||
this.PackFromRgba32(rgba); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public Vector4 ToVector4() |
|||
{ |
|||
return new Rgba32(this.R, this.G, this.B, 255).ToVector4(); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void ToRgb24(ref Rgb24 dest) |
|||
{ |
|||
dest.R = this.R; |
|||
dest.G = this.G; |
|||
dest.B = this.B; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void ToRgba32(ref Rgba32 dest) |
|||
{ |
|||
dest.R = this.R; |
|||
dest.G = this.G; |
|||
dest.B = this.B; |
|||
dest.A = 255; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public void ToBgr24(ref Bgr24 dest) |
|||
{ |
|||
dest = this; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public void ToBgra32(ref Bgra32 dest) |
|||
{ |
|||
dest.R = this.R; |
|||
dest.G = this.G; |
|||
dest.B = this.B; |
|||
dest.A = 255; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,187 @@ |
|||
// <copyright file="Bgra32.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp.PixelFormats |
|||
{ |
|||
using System; |
|||
using System.Numerics; |
|||
using System.Runtime.CompilerServices; |
|||
using System.Runtime.InteropServices; |
|||
|
|||
/// <summary>
|
|||
/// Packed pixel type containing four 8-bit unsigned normalized values ranging from 0 to 255.
|
|||
/// The color components are stored in blue, green, red, and alpha order.
|
|||
/// </summary>
|
|||
[StructLayout(LayoutKind.Sequential)] |
|||
public struct Bgra32 : IPixel<Bgra32>, IPackedVector<uint> |
|||
{ |
|||
/// <summary>
|
|||
/// Gets or sets the blue component.
|
|||
/// </summary>
|
|||
public byte B; |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the green component.
|
|||
/// </summary>
|
|||
public byte G; |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the red component.
|
|||
/// </summary>
|
|||
public byte R; |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the alpha component.
|
|||
/// </summary>
|
|||
public byte A; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Bgra32"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="r">The red component.</param>
|
|||
/// <param name="g">The green component.</param>
|
|||
/// <param name="b">The blue component.</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public Bgra32(byte r, byte g, byte b) |
|||
{ |
|||
this.R = r; |
|||
this.G = g; |
|||
this.B = b; |
|||
this.A = 255; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Bgra32"/> struct.
|
|||
/// </summary>
|
|||
/// <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 Bgra32(byte r, byte g, byte b, byte a) |
|||
{ |
|||
this.R = r; |
|||
this.G = g; |
|||
this.B = b; |
|||
this.A = a; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the packed representation of the Bgra32 struct.
|
|||
/// </summary>
|
|||
public uint Bgra |
|||
{ |
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
get |
|||
{ |
|||
return Unsafe.As<Bgra32, uint>(ref this); |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
set |
|||
{ |
|||
Unsafe.As<Bgra32, uint>(ref this) = value; |
|||
} |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public uint PackedValue |
|||
{ |
|||
get => this.Bgra; |
|||
set => this.Bgra = value; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public PixelOperations<Bgra32> CreatePixelOperations() => new PixelOperations<Bgra32>(); |
|||
|
|||
/// <inheritdoc/>
|
|||
public bool Equals(Bgra32 other) |
|||
{ |
|||
return this.R == other.R && this.G == other.G && this.B == other.B && this.A == other.A; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override bool Equals(object obj) => obj?.GetType() == typeof(Bgra32) && this.Equals((Bgra32)obj); |
|||
|
|||
/// <inheritdoc/>
|
|||
public override int GetHashCode() |
|||
{ |
|||
unchecked |
|||
{ |
|||
int hashCode = this.B; |
|||
hashCode = (hashCode * 397) ^ this.G; |
|||
hashCode = (hashCode * 397) ^ this.R; |
|||
hashCode = (hashCode * 397) ^ this.A; |
|||
return hashCode; |
|||
} |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void PackFromVector4(Vector4 vector) |
|||
{ |
|||
var rgba = default(Rgba32); |
|||
rgba.PackFromVector4(vector); |
|||
this.PackFromRgba32(rgba); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public Vector4 ToVector4() |
|||
{ |
|||
return this.ToRgba32().ToVector4(); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void PackFromRgba32(Rgba32 source) |
|||
{ |
|||
this.R = source.R; |
|||
this.G = source.G; |
|||
this.B = source.B; |
|||
this.A = source.A; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void ToRgb24(ref Rgb24 dest) |
|||
{ |
|||
dest.R = this.R; |
|||
dest.G = this.G; |
|||
dest.B = this.B; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void ToRgba32(ref Rgba32 dest) |
|||
{ |
|||
dest.R = this.R; |
|||
dest.G = this.G; |
|||
dest.B = this.B; |
|||
dest.A = this.A; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void ToBgr24(ref Bgr24 dest) |
|||
{ |
|||
dest = Unsafe.As<Bgra32, Bgr24>(ref this); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void ToBgra32(ref Bgra32 dest) |
|||
{ |
|||
dest = this; |
|||
} |
|||
|
|||
/// <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); |
|||
} |
|||
} |
|||
@ -0,0 +1,302 @@ |
|||
// <auto-generated />
|
|||
|
|||
// <copyright file="PixelOperations{TPixel}.Generated.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp.PixelFormats |
|||
{ |
|||
using System; |
|||
using System.Numerics; |
|||
using System.Runtime.CompilerServices; |
|||
|
|||
public partial class PixelOperations<TPixel> |
|||
{ |
|||
|
|||
/// <summary>
|
|||
/// Converts 'count' elements in 'source` span of <see cref="Rgba32"/> data to a span of <typeparamref name="TPixel"/>-s.
|
|||
/// </summary>
|
|||
/// <param name="source">The source <see cref="Span{T}"/> of <see cref="Rgba32"/> data.</param>
|
|||
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
|
|||
/// <param name="count">The number of pixels to convert.</param>
|
|||
internal virtual void PackFromRgba32(Span<Rgba32> source, Span<TPixel> destPixels, int count) |
|||
{ |
|||
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); |
|||
|
|||
ref Rgba32 sourceRef = ref source.DangerousGetPinnableReference(); |
|||
ref TPixel destRef = ref destPixels.DangerousGetPinnableReference(); |
|||
|
|||
Rgba32 rgba = new Rgba32(0, 0, 0, 255); |
|||
|
|||
for (int i = 0; i < count; i++) |
|||
{ |
|||
ref TPixel dp = ref Unsafe.Add(ref destRef, i); |
|||
rgba = Unsafe.Add(ref sourceRef, i); |
|||
dp.PackFromRgba32(rgba); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// A helper for <see cref="PackFromRgba32(Span{Rgba32}, Span{TPixel}, int)"/> that expects a byte span.
|
|||
/// The layout of the data in 'sourceBytes' must be compatible with <see cref="Rgba32"/> layout.
|
|||
/// </summary>
|
|||
/// <param name="sourceBytes">The <see cref="Span{T}"/> to the source bytes.</param>
|
|||
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
|
|||
/// <param name="count">The number of pixels to convert.</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
internal void PackFromRgba32Bytes(Span<byte> sourceBytes, Span<TPixel> destPixels, int count) |
|||
{ |
|||
this.PackFromRgba32(sourceBytes.NonPortableCast<byte, Rgba32>(), destPixels, count); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Converts 'count' pixels in 'sourcePixels` span to a span of <see cref="Rgba32"/>-s.
|
|||
/// Bulk version of <see cref="IPixel.ToRgba32(ref Rgba32)"/>.
|
|||
/// </summary>
|
|||
/// <param name="sourcePixels">The span of source pixels</param>
|
|||
/// <param name="dest">The destination span of <see cref="Rgba32"/> data.</param>
|
|||
/// <param name="count">The number of pixels to convert.</param>
|
|||
internal virtual void ToRgba32(Span<TPixel> sourcePixels, Span<Rgba32> dest, int count) |
|||
{ |
|||
GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); |
|||
|
|||
ref TPixel sourceBaseRef = ref sourcePixels.DangerousGetPinnableReference(); |
|||
ref Rgba32 destBaseRef = ref dest.DangerousGetPinnableReference(); |
|||
|
|||
for (int i = 0; i < count; i++) |
|||
{ |
|||
ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); |
|||
ref Rgba32 dp = ref Unsafe.Add(ref destBaseRef, i); |
|||
sp.ToRgba32(ref dp); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// A helper for <see cref="ToRgba32(Span{TPixel}, Span{Rgba32}, int)"/> that expects a byte span as destination.
|
|||
/// The layout of the data in 'destBytes' must be compatible with <see cref="Rgba32"/> layout.
|
|||
/// </summary>
|
|||
/// <param name="sourceColors">The <see cref="Span{T}"/> to the source colors.</param>
|
|||
/// <param name="destBytes">The <see cref="Span{T}"/> to the destination bytes.</param>
|
|||
/// <param name="count">The number of pixels to convert.</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
internal void ToRgba32Bytes(Span<TPixel> sourceColors, Span<byte> destBytes, int count) |
|||
{ |
|||
this.ToRgba32(sourceColors, destBytes.NonPortableCast<byte, Rgba32>(), count); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Converts 'count' elements in 'source` span of <see cref="Bgra32"/> data to a span of <typeparamref name="TPixel"/>-s.
|
|||
/// </summary>
|
|||
/// <param name="source">The source <see cref="Span{T}"/> of <see cref="Bgra32"/> data.</param>
|
|||
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
|
|||
/// <param name="count">The number of pixels to convert.</param>
|
|||
internal virtual void PackFromBgra32(Span<Bgra32> source, Span<TPixel> destPixels, int count) |
|||
{ |
|||
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); |
|||
|
|||
ref Bgra32 sourceRef = ref source.DangerousGetPinnableReference(); |
|||
ref TPixel destRef = ref destPixels.DangerousGetPinnableReference(); |
|||
|
|||
Rgba32 rgba = new Rgba32(0, 0, 0, 255); |
|||
|
|||
for (int i = 0; i < count; i++) |
|||
{ |
|||
ref TPixel dp = ref Unsafe.Add(ref destRef, i); |
|||
rgba = Unsafe.Add(ref sourceRef, i).ToRgba32(); |
|||
dp.PackFromRgba32(rgba); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// A helper for <see cref="PackFromBgra32(Span{Bgra32}, Span{TPixel}, int)"/> that expects a byte span.
|
|||
/// The layout of the data in 'sourceBytes' must be compatible with <see cref="Bgra32"/> layout.
|
|||
/// </summary>
|
|||
/// <param name="sourceBytes">The <see cref="Span{T}"/> to the source bytes.</param>
|
|||
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
|
|||
/// <param name="count">The number of pixels to convert.</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
internal void PackFromBgra32Bytes(Span<byte> sourceBytes, Span<TPixel> destPixels, int count) |
|||
{ |
|||
this.PackFromBgra32(sourceBytes.NonPortableCast<byte, Bgra32>(), destPixels, count); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Converts 'count' pixels in 'sourcePixels` span to a span of <see cref="Bgra32"/>-s.
|
|||
/// Bulk version of <see cref="IPixel.ToBgra32(ref Bgra32)"/>.
|
|||
/// </summary>
|
|||
/// <param name="sourcePixels">The span of source pixels</param>
|
|||
/// <param name="dest">The destination span of <see cref="Bgra32"/> data.</param>
|
|||
/// <param name="count">The number of pixels to convert.</param>
|
|||
internal virtual void ToBgra32(Span<TPixel> sourcePixels, Span<Bgra32> dest, int count) |
|||
{ |
|||
GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); |
|||
|
|||
ref TPixel sourceBaseRef = ref sourcePixels.DangerousGetPinnableReference(); |
|||
ref Bgra32 destBaseRef = ref dest.DangerousGetPinnableReference(); |
|||
|
|||
for (int i = 0; i < count; i++) |
|||
{ |
|||
ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); |
|||
ref Bgra32 dp = ref Unsafe.Add(ref destBaseRef, i); |
|||
sp.ToBgra32(ref dp); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// A helper for <see cref="ToBgra32(Span{TPixel}, Span{Bgra32}, int)"/> that expects a byte span as destination.
|
|||
/// The layout of the data in 'destBytes' must be compatible with <see cref="Bgra32"/> layout.
|
|||
/// </summary>
|
|||
/// <param name="sourceColors">The <see cref="Span{T}"/> to the source colors.</param>
|
|||
/// <param name="destBytes">The <see cref="Span{T}"/> to the destination bytes.</param>
|
|||
/// <param name="count">The number of pixels to convert.</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
internal void ToBgra32Bytes(Span<TPixel> sourceColors, Span<byte> destBytes, int count) |
|||
{ |
|||
this.ToBgra32(sourceColors, destBytes.NonPortableCast<byte, Bgra32>(), count); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Converts 'count' elements in 'source` span of <see cref="Rgb24"/> data to a span of <typeparamref name="TPixel"/>-s.
|
|||
/// </summary>
|
|||
/// <param name="source">The source <see cref="Span{T}"/> of <see cref="Rgb24"/> data.</param>
|
|||
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
|
|||
/// <param name="count">The number of pixels to convert.</param>
|
|||
internal virtual void PackFromRgb24(Span<Rgb24> source, Span<TPixel> destPixels, int count) |
|||
{ |
|||
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); |
|||
|
|||
ref Rgb24 sourceRef = ref source.DangerousGetPinnableReference(); |
|||
ref TPixel destRef = ref destPixels.DangerousGetPinnableReference(); |
|||
|
|||
Rgba32 rgba = new Rgba32(0, 0, 0, 255); |
|||
|
|||
for (int i = 0; i < count; i++) |
|||
{ |
|||
ref TPixel dp = ref Unsafe.Add(ref destRef, i); |
|||
rgba.Rgb = Unsafe.Add(ref sourceRef, i); |
|||
dp.PackFromRgba32(rgba); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// A helper for <see cref="PackFromRgb24(Span{Rgb24}, Span{TPixel}, int)"/> that expects a byte span.
|
|||
/// The layout of the data in 'sourceBytes' must be compatible with <see cref="Rgb24"/> layout.
|
|||
/// </summary>
|
|||
/// <param name="sourceBytes">The <see cref="Span{T}"/> to the source bytes.</param>
|
|||
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
|
|||
/// <param name="count">The number of pixels to convert.</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
internal void PackFromRgb24Bytes(Span<byte> sourceBytes, Span<TPixel> destPixels, int count) |
|||
{ |
|||
this.PackFromRgb24(sourceBytes.NonPortableCast<byte, Rgb24>(), destPixels, count); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Converts 'count' pixels in 'sourcePixels` span to a span of <see cref="Rgb24"/>-s.
|
|||
/// Bulk version of <see cref="IPixel.ToRgb24(ref Rgb24)"/>.
|
|||
/// </summary>
|
|||
/// <param name="sourcePixels">The span of source pixels</param>
|
|||
/// <param name="dest">The destination span of <see cref="Rgb24"/> data.</param>
|
|||
/// <param name="count">The number of pixels to convert.</param>
|
|||
internal virtual void ToRgb24(Span<TPixel> sourcePixels, Span<Rgb24> dest, int count) |
|||
{ |
|||
GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); |
|||
|
|||
ref TPixel sourceBaseRef = ref sourcePixels.DangerousGetPinnableReference(); |
|||
ref Rgb24 destBaseRef = ref dest.DangerousGetPinnableReference(); |
|||
|
|||
for (int i = 0; i < count; i++) |
|||
{ |
|||
ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); |
|||
ref Rgb24 dp = ref Unsafe.Add(ref destBaseRef, i); |
|||
sp.ToRgb24(ref dp); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// A helper for <see cref="ToRgb24(Span{TPixel}, Span{Rgb24}, int)"/> that expects a byte span as destination.
|
|||
/// The layout of the data in 'destBytes' must be compatible with <see cref="Rgb24"/> layout.
|
|||
/// </summary>
|
|||
/// <param name="sourceColors">The <see cref="Span{T}"/> to the source colors.</param>
|
|||
/// <param name="destBytes">The <see cref="Span{T}"/> to the destination bytes.</param>
|
|||
/// <param name="count">The number of pixels to convert.</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
internal void ToRgb24Bytes(Span<TPixel> sourceColors, Span<byte> destBytes, int count) |
|||
{ |
|||
this.ToRgb24(sourceColors, destBytes.NonPortableCast<byte, Rgb24>(), count); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Converts 'count' elements in 'source` span of <see cref="Bgr24"/> data to a span of <typeparamref name="TPixel"/>-s.
|
|||
/// </summary>
|
|||
/// <param name="source">The source <see cref="Span{T}"/> of <see cref="Bgr24"/> data.</param>
|
|||
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
|
|||
/// <param name="count">The number of pixels to convert.</param>
|
|||
internal virtual void PackFromBgr24(Span<Bgr24> source, Span<TPixel> destPixels, int count) |
|||
{ |
|||
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); |
|||
|
|||
ref Bgr24 sourceRef = ref source.DangerousGetPinnableReference(); |
|||
ref TPixel destRef = ref destPixels.DangerousGetPinnableReference(); |
|||
|
|||
Rgba32 rgba = new Rgba32(0, 0, 0, 255); |
|||
|
|||
for (int i = 0; i < count; i++) |
|||
{ |
|||
ref TPixel dp = ref Unsafe.Add(ref destRef, i); |
|||
rgba.Bgr = Unsafe.Add(ref sourceRef, i); |
|||
dp.PackFromRgba32(rgba); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// A helper for <see cref="PackFromBgr24(Span{Bgr24}, Span{TPixel}, int)"/> that expects a byte span.
|
|||
/// The layout of the data in 'sourceBytes' must be compatible with <see cref="Bgr24"/> layout.
|
|||
/// </summary>
|
|||
/// <param name="sourceBytes">The <see cref="Span{T}"/> to the source bytes.</param>
|
|||
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
|
|||
/// <param name="count">The number of pixels to convert.</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
internal void PackFromBgr24Bytes(Span<byte> sourceBytes, Span<TPixel> destPixels, int count) |
|||
{ |
|||
this.PackFromBgr24(sourceBytes.NonPortableCast<byte, Bgr24>(), destPixels, count); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Converts 'count' pixels in 'sourcePixels` span to a span of <see cref="Bgr24"/>-s.
|
|||
/// Bulk version of <see cref="IPixel.ToBgr24(ref Bgr24)"/>.
|
|||
/// </summary>
|
|||
/// <param name="sourcePixels">The span of source pixels</param>
|
|||
/// <param name="dest">The destination span of <see cref="Bgr24"/> data.</param>
|
|||
/// <param name="count">The number of pixels to convert.</param>
|
|||
internal virtual void ToBgr24(Span<TPixel> sourcePixels, Span<Bgr24> dest, int count) |
|||
{ |
|||
GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); |
|||
|
|||
ref TPixel sourceBaseRef = ref sourcePixels.DangerousGetPinnableReference(); |
|||
ref Bgr24 destBaseRef = ref dest.DangerousGetPinnableReference(); |
|||
|
|||
for (int i = 0; i < count; i++) |
|||
{ |
|||
ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); |
|||
ref Bgr24 dp = ref Unsafe.Add(ref destBaseRef, i); |
|||
sp.ToBgr24(ref dp); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// A helper for <see cref="ToBgr24(Span{TPixel}, Span{Bgr24}, int)"/> that expects a byte span as destination.
|
|||
/// The layout of the data in 'destBytes' must be compatible with <see cref="Bgr24"/> layout.
|
|||
/// </summary>
|
|||
/// <param name="sourceColors">The <see cref="Span{T}"/> to the source colors.</param>
|
|||
/// <param name="destBytes">The <see cref="Span{T}"/> to the destination bytes.</param>
|
|||
/// <param name="count">The number of pixels to convert.</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
internal void ToBgr24Bytes(Span<TPixel> sourceColors, Span<byte> destBytes, int count) |
|||
{ |
|||
this.ToBgr24(sourceColors, destBytes.NonPortableCast<byte, Bgr24>(), count); |
|||
} |
|||
|
|||
} |
|||
} |
|||
@ -0,0 +1,130 @@ |
|||
<# |
|||
// <copyright file="PixelOperations{TPixel}.Generated.tt" company="James Jackson-South"> |
|||
// Copyright (c) James Jackson-South and contributors. |
|||
// Licensed under the Apache License, Version 2.0. |
|||
// </copyright> |
|||
#> |
|||
<#@ template debug="false" hostspecific="false" language="C#" #> |
|||
<#@ assembly name="System.Core" #> |
|||
<#@ import namespace="System.Linq" #> |
|||
<#@ import namespace="System.Text" #> |
|||
<#@ import namespace="System.Collections.Generic" #> |
|||
<#@ output extension=".cs" #> |
|||
<# |
|||
void GenerateToDestFormatMethods(string pixelType) |
|||
{ |
|||
#> |
|||
|
|||
/// <summary> |
|||
/// Converts 'count' pixels in 'sourcePixels` span to a span of <see cref="<#=pixelType#>"/>-s. |
|||
/// Bulk version of <see cref="IPixel.To<#=pixelType#>(ref <#=pixelType#>)"/>. |
|||
/// </summary> |
|||
/// <param name="sourcePixels">The span of source pixels</param> |
|||
/// <param name="dest">The destination span of <see cref="<#=pixelType#>"/> data.</param> |
|||
/// <param name="count">The number of pixels to convert.</param> |
|||
internal virtual void To<#=pixelType#>(Span<TPixel> sourcePixels, Span<<#=pixelType#>> dest, int count) |
|||
{ |
|||
GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); |
|||
|
|||
ref TPixel sourceBaseRef = ref sourcePixels.DangerousGetPinnableReference(); |
|||
ref <#=pixelType#> destBaseRef = ref dest.DangerousGetPinnableReference(); |
|||
|
|||
for (int i = 0; i < count; i++) |
|||
{ |
|||
ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); |
|||
ref <#=pixelType#> dp = ref Unsafe.Add(ref destBaseRef, i); |
|||
sp.To<#=pixelType#>(ref dp); |
|||
} |
|||
} |
|||
|
|||
/// <summary> |
|||
/// A helper for <see cref="To<#=pixelType#>(Span{TPixel}, Span{<#=pixelType#>}, int)"/> that expects a byte span as destination. |
|||
/// The layout of the data in 'destBytes' must be compatible with <see cref="<#=pixelType#>"/> layout. |
|||
/// </summary> |
|||
/// <param name="sourceColors">The <see cref="Span{T}"/> to the source colors.</param> |
|||
/// <param name="destBytes">The <see cref="Span{T}"/> to the destination bytes.</param> |
|||
/// <param name="count">The number of pixels to convert.</param> |
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
internal void To<#=pixelType#>Bytes(Span<TPixel> sourceColors, Span<byte> destBytes, int count) |
|||
{ |
|||
this.To<#=pixelType#>(sourceColors, destBytes.NonPortableCast<byte, <#=pixelType#>>(), count); |
|||
} |
|||
<# |
|||
} |
|||
|
|||
void GeneratePackFromMethodUsingPackFromRgba32(string pixelType, string rgbaOperationCode) |
|||
{ |
|||
#> |
|||
|
|||
/// <summary> |
|||
/// Converts 'count' elements in 'source` span of <see cref="<#=pixelType#>"/> data to a span of <typeparamref name="TPixel"/>-s. |
|||
/// </summary> |
|||
/// <param name="source">The source <see cref="Span{T}"/> of <see cref="<#=pixelType#>"/> data.</param> |
|||
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param> |
|||
/// <param name="count">The number of pixels to convert.</param> |
|||
internal virtual void PackFrom<#=pixelType#>(Span<<#=pixelType#>> source, Span<TPixel> destPixels, int count) |
|||
{ |
|||
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); |
|||
|
|||
ref <#=pixelType#> sourceRef = ref source.DangerousGetPinnableReference(); |
|||
ref TPixel destRef = ref destPixels.DangerousGetPinnableReference(); |
|||
|
|||
Rgba32 rgba = new Rgba32(0, 0, 0, 255); |
|||
|
|||
for (int i = 0; i < count; i++) |
|||
{ |
|||
ref TPixel dp = ref Unsafe.Add(ref destRef, i); |
|||
<#=rgbaOperationCode#> |
|||
dp.PackFromRgba32(rgba); |
|||
} |
|||
} |
|||
|
|||
/// <summary> |
|||
/// A helper for <see cref="PackFrom<#=pixelType#>(Span{<#=pixelType#>}, Span{TPixel}, int)"/> that expects a byte span. |
|||
/// The layout of the data in 'sourceBytes' must be compatible with <see cref="<#=pixelType#>"/> layout. |
|||
/// </summary> |
|||
/// <param name="sourceBytes">The <see cref="Span{T}"/> to the source bytes.</param> |
|||
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param> |
|||
/// <param name="count">The number of pixels to convert.</param> |
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
internal void PackFrom<#=pixelType#>Bytes(Span<byte> sourceBytes, Span<TPixel> destPixels, int count) |
|||
{ |
|||
this.PackFrom<#=pixelType#>(sourceBytes.NonPortableCast<byte, <#=pixelType#>>(), destPixels, count); |
|||
} |
|||
<# |
|||
} |
|||
|
|||
#> |
|||
// <auto-generated /> |
|||
|
|||
// <copyright file="PixelOperations{TPixel}.Generated.cs" company="James Jackson-South"> |
|||
// Copyright (c) James Jackson-South and contributors. |
|||
// Licensed under the Apache License, Version 2.0. |
|||
// </copyright> |
|||
|
|||
namespace ImageSharp.PixelFormats |
|||
{ |
|||
using System; |
|||
using System.Numerics; |
|||
using System.Runtime.CompilerServices; |
|||
|
|||
public partial class PixelOperations<TPixel> |
|||
{ |
|||
<# |
|||
|
|||
GeneratePackFromMethodUsingPackFromRgba32("Rgba32", "rgba = Unsafe.Add(ref sourceRef, i);"); |
|||
GenerateToDestFormatMethods("Rgba32"); |
|||
|
|||
GeneratePackFromMethodUsingPackFromRgba32("Bgra32", "rgba = Unsafe.Add(ref sourceRef, i).ToRgba32();"); |
|||
GenerateToDestFormatMethods("Bgra32"); |
|||
|
|||
GeneratePackFromMethodUsingPackFromRgba32("Rgb24", "rgba.Rgb = Unsafe.Add(ref sourceRef, i);"); |
|||
GenerateToDestFormatMethods("Rgb24"); |
|||
|
|||
GeneratePackFromMethodUsingPackFromRgba32("Bgr24", "rgba.Bgr = Unsafe.Add(ref sourceRef, i);"); |
|||
GenerateToDestFormatMethods("Bgr24"); |
|||
|
|||
#> |
|||
|
|||
} |
|||
} |
|||
@ -0,0 +1,130 @@ |
|||
// <auto-generated />
|
|||
|
|||
// <copyright file="PixelOperations{TPixel}.Generated.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; |
|||
using System.Runtime.CompilerServices; |
|||
using System.Runtime.InteropServices; |
|||
|
|||
using ImageSharp.Memory; |
|||
using ImageSharp.PixelFormats; |
|||
|
|||
/// <content>
|
|||
/// Provides optimized overrides for bulk operations.
|
|||
/// </content>
|
|||
public partial struct Rgba32 |
|||
{ |
|||
internal partial class PixelOperations : PixelOperations<Rgba32> |
|||
{ |
|||
|
|||
/// <inheritdoc />
|
|||
internal override void PackFromRgb24(Span<Rgb24> source, Span<Rgba32> destPixels, int count) |
|||
{ |
|||
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); |
|||
|
|||
ref Rgb24 sourceRef = ref source.DangerousGetPinnableReference(); |
|||
ref Rgba32 destRef = ref destPixels.DangerousGetPinnableReference(); |
|||
|
|||
for (int i = 0; i < count; i++) |
|||
{ |
|||
ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); |
|||
ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); |
|||
Unsafe.As<Rgba32, Rgb24>(ref dp) = sp; dp.A = 255; |
|||
} |
|||
} |
|||
|
|||
|
|||
/// <inheritdoc />
|
|||
internal override void ToRgb24(Span<Rgba32> sourcePixels, Span<Rgb24> dest, int count) |
|||
{ |
|||
GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); |
|||
|
|||
ref Rgba32 sourceRef = ref sourcePixels.DangerousGetPinnableReference(); |
|||
ref Rgb24 destRef = ref dest.DangerousGetPinnableReference(); |
|||
|
|||
for (int i = 0; i < count; i++) |
|||
{ |
|||
ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); |
|||
ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); |
|||
dp = Unsafe.As<Rgba32, Rgb24>(ref sp); |
|||
} |
|||
} |
|||
|
|||
|
|||
/// <inheritdoc />
|
|||
internal override void PackFromBgr24(Span<Bgr24> source, Span<Rgba32> destPixels, int count) |
|||
{ |
|||
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); |
|||
|
|||
ref Bgr24 sourceRef = ref source.DangerousGetPinnableReference(); |
|||
ref Rgba32 destRef = ref destPixels.DangerousGetPinnableReference(); |
|||
|
|||
for (int i = 0; i < count; i++) |
|||
{ |
|||
ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); |
|||
ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); |
|||
dp.Bgr = sp; dp.A = 255; |
|||
} |
|||
} |
|||
|
|||
|
|||
/// <inheritdoc />
|
|||
internal override void ToBgr24(Span<Rgba32> sourcePixels, Span<Bgr24> dest, int count) |
|||
{ |
|||
GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); |
|||
|
|||
ref Rgba32 sourceRef = ref sourcePixels.DangerousGetPinnableReference(); |
|||
ref Bgr24 destRef = ref dest.DangerousGetPinnableReference(); |
|||
|
|||
for (int i = 0; i < count; i++) |
|||
{ |
|||
ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); |
|||
ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); |
|||
dp = sp.Bgr; |
|||
} |
|||
} |
|||
|
|||
|
|||
/// <inheritdoc />
|
|||
internal override void PackFromBgra32(Span<Bgra32> source, Span<Rgba32> destPixels, int count) |
|||
{ |
|||
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); |
|||
|
|||
ref Bgra32 sourceRef = ref source.DangerousGetPinnableReference(); |
|||
ref Rgba32 destRef = ref destPixels.DangerousGetPinnableReference(); |
|||
|
|||
for (int i = 0; i < count; i++) |
|||
{ |
|||
ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); |
|||
ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); |
|||
dp = sp.ToRgba32(); |
|||
} |
|||
} |
|||
|
|||
|
|||
/// <inheritdoc />
|
|||
internal override void ToBgra32(Span<Rgba32> sourcePixels, Span<Bgra32> dest, int count) |
|||
{ |
|||
GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); |
|||
|
|||
ref Rgba32 sourceRef = ref sourcePixels.DangerousGetPinnableReference(); |
|||
ref Bgra32 destRef = ref dest.DangerousGetPinnableReference(); |
|||
|
|||
for (int i = 0; i < count; i++) |
|||
{ |
|||
ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); |
|||
ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); |
|||
dp = sp.ToBgra32(); |
|||
} |
|||
} |
|||
|
|||
|
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,99 @@ |
|||
<# |
|||
// <copyright file="Rgba32.PixelOperations.Generated.tt" company="James Jackson-South"> |
|||
// Copyright (c) James Jackson-South and contributors. |
|||
// Licensed under the Apache License, Version 2.0. |
|||
// </copyright> |
|||
#> |
|||
<#@ template debug="false" hostspecific="false" language="C#" #> |
|||
<#@ assembly name="System.Core" #> |
|||
<#@ import namespace="System.Linq" #> |
|||
<#@ import namespace="System.Text" #> |
|||
<#@ import namespace="System.Collections.Generic" #> |
|||
<#@ output extension=".cs" #> |
|||
<# |
|||
|
|||
void GeneratePackFromMethod(string pixelType, string converterCode) |
|||
{ |
|||
#> |
|||
|
|||
/// <inheritdoc /> |
|||
internal override void PackFrom<#=pixelType#>(Span<<#=pixelType#>> source, Span<Rgba32> destPixels, int count) |
|||
{ |
|||
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); |
|||
|
|||
ref <#=pixelType#> sourceRef = ref source.DangerousGetPinnableReference(); |
|||
ref Rgba32 destRef = ref destPixels.DangerousGetPinnableReference(); |
|||
|
|||
for (int i = 0; i < count; i++) |
|||
{ |
|||
ref <#=pixelType#> sp = ref Unsafe.Add(ref sourceRef, i); |
|||
ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); |
|||
<#=converterCode#> |
|||
} |
|||
} |
|||
|
|||
<# |
|||
} |
|||
|
|||
void GenerateConvertToMethod(string pixelType, string converterCode) |
|||
{ |
|||
#> |
|||
|
|||
/// <inheritdoc /> |
|||
internal override void To<#=pixelType#>(Span<Rgba32> sourcePixels, Span<<#=pixelType#>> dest, int count) |
|||
{ |
|||
GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); |
|||
|
|||
ref Rgba32 sourceRef = ref sourcePixels.DangerousGetPinnableReference(); |
|||
ref <#=pixelType#> destRef = ref dest.DangerousGetPinnableReference(); |
|||
|
|||
for (int i = 0; i < count; i++) |
|||
{ |
|||
ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); |
|||
ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); |
|||
<#=converterCode#> |
|||
} |
|||
} |
|||
|
|||
<# |
|||
} |
|||
|
|||
#> |
|||
// <auto-generated /> |
|||
|
|||
// <copyright file="PixelOperations{TPixel}.Generated.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; |
|||
using System.Runtime.CompilerServices; |
|||
using System.Runtime.InteropServices; |
|||
|
|||
using ImageSharp.Memory; |
|||
using ImageSharp.PixelFormats; |
|||
|
|||
/// <content> |
|||
/// Provides optimized overrides for bulk operations. |
|||
/// </content> |
|||
public partial struct Rgba32 |
|||
{ |
|||
internal partial class PixelOperations : PixelOperations<Rgba32> |
|||
{ |
|||
<# |
|||
GeneratePackFromMethod("Rgb24", "Unsafe.As<Rgba32, Rgb24>(ref dp) = sp; dp.A = 255;"); |
|||
GenerateConvertToMethod("Rgb24", "dp = Unsafe.As<Rgba32, Rgb24>(ref sp);"); |
|||
|
|||
GeneratePackFromMethod("Bgr24", "dp.Bgr = sp; dp.A = 255;"); |
|||
GenerateConvertToMethod("Bgr24", "dp = sp.Bgr;"); |
|||
|
|||
GeneratePackFromMethod("Bgra32", "dp = sp.ToRgba32();"); |
|||
GenerateConvertToMethod("Bgra32", "dp = sp.ToBgra32();"); |
|||
#> |
|||
|
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,76 @@ |
|||
namespace ImageSharp.PixelFormats |
|||
{ |
|||
using System; |
|||
using System.Runtime.CompilerServices; |
|||
|
|||
/// <summary>
|
|||
/// Extension methods for copying single pixel data into byte Spans.
|
|||
/// TODO: This utility class exists for legacy reasons. Need to do a lot of chore work to remove it (mostly in test classes).
|
|||
/// </summary>
|
|||
internal static class PixelConversionExtensions |
|||
{ |
|||
/// <summary>
|
|||
/// Expands the packed representation into a given byte array.
|
|||
/// Output is expanded to X-> Y-> Z order. Equivalent to R-> G-> B in <see cref="Rgb24"/>
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel type.</typeparam>
|
|||
/// <param name="pixel">The pixel to copy the data from.</param>
|
|||
/// <param name="bytes">The bytes to set the color in.</param>
|
|||
/// <param name="startIndex">The starting index of the <paramref name="bytes"/>.</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static void ToXyzBytes<TPixel>(this TPixel pixel, Span<byte> bytes, int startIndex) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
ref Rgb24 dest = ref bytes.GetRgb24(startIndex); |
|||
pixel.ToRgb24(ref dest); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Expands the packed representation into a given byte array.
|
|||
/// Output is expanded to X-> Y-> Z-> W order. Equivalent to R-> G-> B-> A in <see cref="Rgba32"/>
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel type.</typeparam>
|
|||
/// <param name="pixel">The pixel to copy the data from.</param>
|
|||
/// <param name="bytes">The bytes to set the color in.</param>
|
|||
/// <param name="startIndex">The starting index of the <paramref name="bytes"/>.</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static void ToXyzwBytes<TPixel>(this TPixel pixel, Span<byte> bytes, int startIndex) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
ref Rgba32 dest = ref Unsafe.As<byte, Rgba32>(ref bytes[startIndex]); |
|||
pixel.ToRgba32(ref dest); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Expands the packed representation into a given byte array.
|
|||
/// Output is expanded to Z-> Y-> X order. Equivalent to B-> G-> R in <see cref="Bgr24"/>
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel type.</typeparam>
|
|||
/// <param name="pixel">The pixel to copy the data from.</param>
|
|||
/// <param name="bytes">The bytes to set the color in.</param>
|
|||
/// <param name="startIndex">The starting index of the <paramref name="bytes"/>.</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static void ToZyxBytes<TPixel>(this TPixel pixel, Span<byte> bytes, int startIndex) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
ref Bgr24 dest = ref Unsafe.As<byte, Bgr24>(ref bytes[startIndex]); |
|||
pixel.ToBgr24(ref dest); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Expands the packed representation into a given byte array.
|
|||
/// Output is expanded to Z-> Y-> X-> W order. Equivalent to B-> G-> R-> A in <see cref="Bgra32"/>
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel type.</typeparam>
|
|||
/// <param name="pixel">The pixel to copy the data from.</param>
|
|||
/// <param name="bytes">The bytes to set the color in.</param>
|
|||
/// <param name="startIndex">The starting index of the <paramref name="bytes"/>.</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static void ToZyxwBytes<TPixel>(this TPixel pixel, Span<byte> bytes, int startIndex) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
ref Bgra32 dest = ref Unsafe.As<byte, Bgra32>(ref bytes[startIndex]); |
|||
pixel.ToBgra32(ref dest); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,132 @@ |
|||
// <copyright file="Rgb24.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp.PixelFormats |
|||
{ |
|||
using System; |
|||
using System.Numerics; |
|||
using System.Runtime.CompilerServices; |
|||
using System.Runtime.InteropServices; |
|||
|
|||
/// <summary>
|
|||
/// Pixel type containing three 8-bit unsigned normalized values ranging from 0 to 255.
|
|||
/// The color components are stored in red, green, blue order.
|
|||
/// </summary>
|
|||
[StructLayout(LayoutKind.Sequential)] |
|||
public struct Rgb24 : IPixel<Rgb24> |
|||
{ |
|||
/// <summary>
|
|||
/// The red component.
|
|||
/// </summary>
|
|||
public byte R; |
|||
|
|||
/// <summary>
|
|||
/// The green component.
|
|||
/// </summary>
|
|||
public byte G; |
|||
|
|||
/// <summary>
|
|||
/// The blue component.
|
|||
/// </summary>
|
|||
public byte B; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Rgb24"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="r">The red component.</param>
|
|||
/// <param name="g">The green component.</param>
|
|||
/// <param name="b">The blue component.</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public Rgb24(byte r, byte g, byte b) |
|||
{ |
|||
this.R = r; |
|||
this.G = g; |
|||
this.B = b; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public PixelOperations<Rgb24> CreatePixelOperations() => new PixelOperations<Rgb24>(); |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public bool Equals(Rgb24 other) |
|||
{ |
|||
return this.R == other.R && this.G == other.G && this.B == other.B; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override bool Equals(object obj) |
|||
{ |
|||
return obj?.GetType() == typeof(Rgb24) && this.Equals((Rgb24)obj); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public override int GetHashCode() |
|||
{ |
|||
unchecked |
|||
{ |
|||
int hashCode = this.R; |
|||
hashCode = (hashCode * 397) ^ this.G; |
|||
hashCode = (hashCode * 397) ^ this.B; |
|||
return hashCode; |
|||
} |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void PackFromRgba32(Rgba32 source) |
|||
{ |
|||
this = Unsafe.As<Rgba32, Rgb24>(ref source); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void PackFromVector4(Vector4 vector) |
|||
{ |
|||
var rgba = default(Rgba32); |
|||
rgba.PackFromVector4(vector); |
|||
this.PackFromRgba32(rgba); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public Vector4 ToVector4() |
|||
{ |
|||
return new Rgba32(this.R, this.G, this.B, 255).ToVector4(); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void ToRgb24(ref Rgb24 dest) |
|||
{ |
|||
dest = this; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public void ToRgba32(ref Rgba32 dest) |
|||
{ |
|||
dest.Rgb = this; |
|||
dest.A = 255; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public void ToBgr24(ref Bgr24 dest) |
|||
{ |
|||
dest.R = this.R; |
|||
dest.G = this.G; |
|||
dest.B = this.B; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public void ToBgra32(ref Bgra32 dest) |
|||
{ |
|||
dest.R = this.R; |
|||
dest.G = this.G; |
|||
dest.B = this.B; |
|||
dest.A = 255; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,206 @@ |
|||
// ReSharper disable InconsistentNaming
|
|||
namespace ImageSharp.Benchmarks.General |
|||
{ |
|||
using System.Runtime.CompilerServices; |
|||
using System.Runtime.InteropServices; |
|||
|
|||
using BenchmarkDotNet.Attributes; |
|||
|
|||
public class PixelConversion_ConvertFromRgba32 |
|||
{ |
|||
interface ITestPixel<T> |
|||
where T : struct, ITestPixel<T> |
|||
{ |
|||
void FromRgba32(Rgba32 source); |
|||
|
|||
void FromRgba32(ref Rgba32 source); |
|||
|
|||
void FromBytes(byte r, byte g, byte b, byte a); |
|||
} |
|||
|
|||
[StructLayout(LayoutKind.Sequential)] |
|||
struct TestArgb : ITestPixel<TestArgb> |
|||
{ |
|||
private byte a, r, g, b; |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromRgba32(Rgba32 p) |
|||
{ |
|||
this.r = p.R; |
|||
this.g = p.G; |
|||
this.b = p.B; |
|||
this.a = p.A; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromRgba32(ref Rgba32 p) |
|||
{ |
|||
this.r = p.R; |
|||
this.g = p.G; |
|||
this.b = p.B; |
|||
this.a = p.A; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromBytes(byte r, byte g, byte b, byte a) |
|||
{ |
|||
this.r = r; |
|||
this.g = g; |
|||
this.b = b; |
|||
this.a = a; |
|||
} |
|||
} |
|||
|
|||
[StructLayout(LayoutKind.Sequential)] |
|||
struct TestRgba : ITestPixel<TestRgba> |
|||
{ |
|||
private byte r, g, b, a; |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromRgba32(Rgba32 source) |
|||
{ |
|||
this = Unsafe.As<Rgba32, TestRgba>(ref source); |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromRgba32(ref Rgba32 source) |
|||
{ |
|||
this = Unsafe.As<Rgba32, TestRgba>(ref source); |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromBytes(byte r, byte g, byte b, byte a) |
|||
{ |
|||
this.r = r; |
|||
this.g = g; |
|||
this.b = b; |
|||
this.a = a; |
|||
} |
|||
} |
|||
|
|||
struct ConversionRunner<T> |
|||
where T : struct, ITestPixel<T> |
|||
{ |
|||
private T[] dest; |
|||
|
|||
private Rgba32[] source; |
|||
|
|||
public ConversionRunner(int count) |
|||
{ |
|||
this.dest = new T[count]; |
|||
this.source = new Rgba32[count]; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void RunByRefConversion() |
|||
{ |
|||
int count = this.dest.Length; |
|||
|
|||
ref T destBaseRef = ref this.dest[0]; |
|||
ref Rgba32 sourceBaseRef = ref this.source[0]; |
|||
|
|||
for (int i = 0; i < count; i++) |
|||
{ |
|||
Unsafe.Add(ref destBaseRef, i).FromRgba32(ref Unsafe.Add(ref sourceBaseRef, i)); |
|||
} |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void RunByValConversion() |
|||
{ |
|||
int count = this.dest.Length; |
|||
|
|||
ref T destBaseRef = ref this.dest[0]; |
|||
ref Rgba32 sourceBaseRef = ref this.source[0]; |
|||
|
|||
for (int i = 0; i < count; i++) |
|||
{ |
|||
Unsafe.Add(ref destBaseRef, i).FromRgba32(Unsafe.Add(ref sourceBaseRef, i)); |
|||
} |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void RunFromBytesConversion() |
|||
{ |
|||
int count = this.dest.Length; |
|||
|
|||
ref T destBaseRef = ref this.dest[0]; |
|||
ref Rgba32 sourceBaseRef = ref this.source[0]; |
|||
|
|||
for (int i = 0; i < count; i++) |
|||
{ |
|||
ref Rgba32 s = ref Unsafe.Add(ref sourceBaseRef, i); |
|||
Unsafe.Add(ref destBaseRef, i).FromBytes(s.R, s.G, s.B, s.A); |
|||
} |
|||
} |
|||
} |
|||
|
|||
private ConversionRunner<TestRgba> compatibleMemLayoutRunner; |
|||
|
|||
private ConversionRunner<TestArgb> permutedRunner; |
|||
|
|||
[Params(32)] |
|||
public int Count { get; set; } |
|||
|
|||
[Setup] |
|||
public void Setup() |
|||
{ |
|||
this.compatibleMemLayoutRunner = new ConversionRunner<TestRgba>(this.Count); |
|||
this.permutedRunner = new ConversionRunner<TestArgb>(this.Count); |
|||
} |
|||
|
|||
[Benchmark(Baseline = true)] |
|||
public void CompatibleByRef() |
|||
{ |
|||
this.compatibleMemLayoutRunner.RunByRefConversion(); |
|||
} |
|||
|
|||
[Benchmark] |
|||
public void CompatibleByVal() |
|||
{ |
|||
this.compatibleMemLayoutRunner.RunByValConversion(); |
|||
} |
|||
|
|||
[Benchmark] |
|||
public void CompatibleFromBytes() |
|||
{ |
|||
this.compatibleMemLayoutRunner.RunFromBytesConversion(); |
|||
} |
|||
|
|||
|
|||
[Benchmark] |
|||
public void PermutedByRef() |
|||
{ |
|||
this.permutedRunner.RunByRefConversion(); |
|||
} |
|||
|
|||
[Benchmark] |
|||
public void PermutedByVal() |
|||
{ |
|||
this.permutedRunner.RunByValConversion(); |
|||
} |
|||
|
|||
[Benchmark] |
|||
public void PermutedFromBytes() |
|||
{ |
|||
this.permutedRunner.RunFromBytesConversion(); |
|||
} |
|||
} |
|||
|
|||
/* |
|||
* Results: |
|||
* Method | Count | Mean | StdDev | Scaled | Scaled-StdDev | |
|||
* ------------------ |------ |----------- |---------- |------- |-------------- | |
|||
* CompatibleByRef | 32 | 20.6339 ns | 0.0742 ns | 1.00 | 0.00 | |
|||
* CompatibleByVal | 32 | 23.7425 ns | 0.0997 ns | 1.15 | 0.01 | |
|||
* CompatibleFromBytes | 32 | 38.7017 ns | 0.1103 ns | 1.88 | 0.01 | |
|||
* PermutedByRef | 32 | 39.2892 ns | 0.1366 ns | 1.90 | 0.01 | |
|||
* PermutedByVal | 32 | 38.5178 ns | 0.1946 ns | 1.87 | 0.01 | |
|||
* PermutedFromBytes | 32 | 38.6683 ns | 0.0801 ns | 1.87 | 0.01 | |
|||
* |
|||
* !!! Conclusion !!! |
|||
* All memory-incompatible (permuted) variants are equivalent with the the "FromBytes" solution. |
|||
* In memory compatible cases we should use the optimized Bulk-copying variant anyways, |
|||
* so there is no benefit introducing non-bulk API-s other than PackFromBytes() OR PackFromRgba32(). |
|||
*/ |
|||
} |
|||
@ -0,0 +1,156 @@ |
|||
// ReSharper disable InconsistentNaming
|
|||
namespace ImageSharp.Benchmarks.General |
|||
{ |
|||
using System.Numerics; |
|||
using System.Runtime.CompilerServices; |
|||
using System.Runtime.InteropServices; |
|||
|
|||
using BenchmarkDotNet.Attributes; |
|||
|
|||
public class PixelConversion_ConvertFromVector4 |
|||
{ |
|||
interface ITestPixel<T> |
|||
where T : struct, ITestPixel<T> |
|||
{ |
|||
void FromVector4(Vector4 source); |
|||
|
|||
void FromVector4(ref Vector4 source); |
|||
} |
|||
|
|||
[StructLayout(LayoutKind.Sequential)] |
|||
struct TestArgb : ITestPixel<TestArgb> |
|||
{ |
|||
private byte a, r, g, b; |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromVector4(Vector4 p) |
|||
{ |
|||
this.r = (byte)p.X; |
|||
this.g = (byte)p.Y; |
|||
this.b = (byte)p.Z; |
|||
this.a = (byte)p.W; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromVector4(ref Vector4 p) |
|||
{ |
|||
this.r = (byte)p.X; |
|||
this.g = (byte)p.Y; |
|||
this.b = (byte)p.Z; |
|||
this.a = (byte)p.W; |
|||
} |
|||
} |
|||
|
|||
[StructLayout(LayoutKind.Sequential)] |
|||
struct TestRgbaVector : ITestPixel<TestRgbaVector> |
|||
{ |
|||
private Vector4 v; |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromVector4(Vector4 p) |
|||
{ |
|||
this.v = p; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void FromVector4(ref Vector4 p) |
|||
{ |
|||
this.v = p; |
|||
} |
|||
} |
|||
|
|||
struct ConversionRunner<T> |
|||
where T : struct, ITestPixel<T> |
|||
{ |
|||
private T[] dest; |
|||
|
|||
private Vector4[] source; |
|||
|
|||
public ConversionRunner(int count) |
|||
{ |
|||
this.dest = new T[count]; |
|||
this.source = new Vector4[count]; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void RunByRefConversion() |
|||
{ |
|||
int count = this.dest.Length; |
|||
|
|||
ref T destBaseRef = ref this.dest[0]; |
|||
ref Vector4 sourceBaseRef = ref this.source[0]; |
|||
|
|||
for (int i = 0; i < count; i++) |
|||
{ |
|||
Unsafe.Add(ref destBaseRef, i).FromVector4(ref Unsafe.Add(ref sourceBaseRef, i)); |
|||
} |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void RunByValConversion() |
|||
{ |
|||
int count = this.dest.Length; |
|||
|
|||
ref T destBaseRef = ref this.dest[0]; |
|||
ref Vector4 sourceBaseRef = ref this.source[0]; |
|||
|
|||
for (int i = 0; i < count; i++) |
|||
{ |
|||
Unsafe.Add(ref destBaseRef, i).FromVector4(Unsafe.Add(ref sourceBaseRef, i)); |
|||
} |
|||
} |
|||
} |
|||
|
|||
private ConversionRunner<TestArgb> nonVectorRunner; |
|||
|
|||
private ConversionRunner<TestRgbaVector> vectorRunner; |
|||
|
|||
[Params(32)] |
|||
public int Count { get; set; } |
|||
|
|||
[Setup] |
|||
public void Setup() |
|||
{ |
|||
this.nonVectorRunner = new ConversionRunner<TestArgb>(this.Count); |
|||
this.vectorRunner = new ConversionRunner<TestRgbaVector>(this.Count); |
|||
} |
|||
|
|||
[Benchmark(Baseline = true)] |
|||
public void VectorByRef() |
|||
{ |
|||
this.vectorRunner.RunByRefConversion(); |
|||
} |
|||
|
|||
[Benchmark] |
|||
public void VectorByVal() |
|||
{ |
|||
this.vectorRunner.RunByValConversion(); |
|||
} |
|||
|
|||
[Benchmark] |
|||
public void NonVectorByRef() |
|||
{ |
|||
this.nonVectorRunner.RunByRefConversion(); |
|||
} |
|||
|
|||
[Benchmark] |
|||
public void NonVectorByVal() |
|||
{ |
|||
this.nonVectorRunner.RunByValConversion(); |
|||
} |
|||
|
|||
} |
|||
|
|||
/* |
|||
* Results: |
|||
* Method | Count | Mean | StdDev | Scaled | Scaled-StdDev | |
|||
* --------------- |------ |----------- |---------- |------- |-------------- | |
|||
* VectorByRef | 32 | 23.6678 ns | 0.1141 ns | 1.00 | 0.00 | |
|||
* VectorByVal | 32 | 24.5347 ns | 0.0771 ns | 1.04 | 0.01 | |
|||
* NonVectorByRef | 32 | 59.0187 ns | 0.2114 ns | 2.49 | 0.01 | |
|||
* NonVectorByVal | 32 | 58.7529 ns | 0.2545 ns | 2.48 | 0.02 | |
|||
* |
|||
* !!! Conclusion !!! |
|||
* We do not need by-ref version of ConvertFromVector4() stuff |
|||
*/ |
|||
} |
|||
@ -0,0 +1,156 @@ |
|||
// ReSharper disable InconsistentNaming
|
|||
namespace ImageSharp.Benchmarks.General |
|||
{ |
|||
using System.Runtime.CompilerServices; |
|||
using System.Runtime.InteropServices; |
|||
|
|||
using BenchmarkDotNet.Attributes; |
|||
|
|||
/// <summary>
|
|||
/// When implementing TPixel --> Rgba32 style conversions on IPixel, should which API should we prefer?
|
|||
/// 1. Rgba32 ToRgba32();
|
|||
/// OR
|
|||
/// 2. void CopyToRgba32(ref Rgba32 dest);
|
|||
/// ?
|
|||
/// </summary>
|
|||
public class PixelConversion_ConvertToRgba32 |
|||
{ |
|||
interface ITestPixel<T> |
|||
where T : struct, ITestPixel<T> |
|||
{ |
|||
Rgba32 ToRgba32(); |
|||
|
|||
void CopyToRgba32(ref Rgba32 dest); |
|||
} |
|||
|
|||
[StructLayout(LayoutKind.Sequential)] |
|||
struct TestArgb : ITestPixel<TestArgb> |
|||
{ |
|||
private byte a, r, g, b; |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public Rgba32 ToRgba32() |
|||
{ |
|||
return new Rgba32(this.r, this.g, this.b, this.a); |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void CopyToRgba32(ref Rgba32 dest) |
|||
{ |
|||
dest.R = this.r; |
|||
dest.G = this.g; |
|||
dest.B = this.b; |
|||
dest.A = this.a; |
|||
} |
|||
} |
|||
|
|||
[StructLayout(LayoutKind.Sequential)] |
|||
struct TestRgba : ITestPixel<TestRgba> |
|||
{ |
|||
private byte r, g, b, a; |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public Rgba32 ToRgba32() |
|||
{ |
|||
return Unsafe.As<TestRgba, Rgba32>(ref this); |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void CopyToRgba32(ref Rgba32 dest) |
|||
{ |
|||
dest = Unsafe.As<TestRgba, Rgba32>(ref this); |
|||
} |
|||
} |
|||
|
|||
struct ConversionRunner<T> |
|||
where T : struct, ITestPixel<T> |
|||
{ |
|||
private T[] source; |
|||
|
|||
private Rgba32[] dest; |
|||
|
|||
public ConversionRunner(int count) |
|||
{ |
|||
this.source = new T[count]; |
|||
this.dest = new Rgba32[count]; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void RunRetvalConversion() |
|||
{ |
|||
int count = this.source.Length; |
|||
|
|||
ref T sourceBaseRef = ref this.source[0]; |
|||
ref Rgba32 destBaseRef = ref this.dest[0]; |
|||
|
|||
for (int i = 0; i < count; i++) |
|||
{ |
|||
Unsafe.Add(ref destBaseRef, i) = Unsafe.Add(ref sourceBaseRef, i).ToRgba32(); |
|||
} |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void RunCopyToConversion() |
|||
{ |
|||
int count = this.source.Length; |
|||
|
|||
ref T sourceBaseRef = ref this.source[0]; |
|||
ref Rgba32 destBaseRef = ref this.dest[0]; |
|||
|
|||
for (int i = 0; i < count; i++) |
|||
{ |
|||
Unsafe.Add(ref sourceBaseRef, i).CopyToRgba32(ref Unsafe.Add(ref destBaseRef, i)); |
|||
} |
|||
} |
|||
} |
|||
|
|||
private ConversionRunner<TestRgba> compatibleMemoryLayoutRunner; |
|||
|
|||
private ConversionRunner<TestArgb> permutedRunner; |
|||
|
|||
[Params(128)] |
|||
public int Count { get; set; } |
|||
|
|||
[Setup] |
|||
public void Setup() |
|||
{ |
|||
this.compatibleMemoryLayoutRunner = new ConversionRunner<TestRgba>(this.Count); |
|||
this.permutedRunner = new ConversionRunner<TestArgb>(this.Count); |
|||
} |
|||
|
|||
[Benchmark(Baseline = true)] |
|||
public void CompatibleRetval() |
|||
{ |
|||
this.compatibleMemoryLayoutRunner.RunRetvalConversion(); |
|||
} |
|||
|
|||
[Benchmark] |
|||
public void CompatibleCopyTo() |
|||
{ |
|||
this.compatibleMemoryLayoutRunner.RunCopyToConversion(); |
|||
} |
|||
|
|||
[Benchmark] |
|||
public void PermutedRetval() |
|||
{ |
|||
this.permutedRunner.RunRetvalConversion(); |
|||
} |
|||
|
|||
[Benchmark] |
|||
public void PermutedCopyTo() |
|||
{ |
|||
this.permutedRunner.RunCopyToConversion(); |
|||
} |
|||
} |
|||
|
|||
/* |
|||
* Results: |
|||
* |
|||
* Method | Count | Mean | StdDev | Scaled | Scaled-StdDev | |
|||
* --------------- |------ |------------ |---------- |------- |-------------- | |
|||
* CompatibleRetval | 128 | 89.7358 ns | 2.2389 ns | 1.00 | 0.00 | |
|||
* CompatibleCopyTo | 128 | 89.4112 ns | 2.2901 ns | 1.00 | 0.03 | |
|||
* PermutedRetval | 128 | 845.4038 ns | 5.6154 ns | 9.43 | 0.23 | |
|||
* PermutedCopyTo | 128 | 155.6004 ns | 3.8870 ns | 1.73 | 0.06 | |
|||
*/ |
|||
} |
|||
@ -0,0 +1,143 @@ |
|||
// ReSharper disable InconsistentNaming
|
|||
namespace ImageSharp.Tests |
|||
{ |
|||
using System.Numerics; |
|||
|
|||
using ImageSharp.PixelFormats; |
|||
|
|||
using Xunit; |
|||
|
|||
public class Bgr24Tests |
|||
{ |
|||
public static readonly TheoryData<byte, byte, byte> ColorData = |
|||
new TheoryData<byte, byte, byte>() { { 1, 2, 3 }, { 4, 5, 6 }, { 0, 255, 42 } }; |
|||
|
|||
[Theory] |
|||
[MemberData(nameof(ColorData))] |
|||
public void Constructor(byte r, byte g, byte b) |
|||
{ |
|||
var p = new Rgb24(r, g, b); |
|||
|
|||
Assert.Equal(r, p.R); |
|||
Assert.Equal(g, p.G); |
|||
Assert.Equal(b, p.B); |
|||
} |
|||
|
|||
[Fact] |
|||
public unsafe void ByteLayoutIsSequentialBgr() |
|||
{ |
|||
var color = new Bgr24(1, 2, 3); |
|||
byte* ptr = (byte*)&color; |
|||
|
|||
Assert.Equal(3, ptr[0]); |
|||
Assert.Equal(2, ptr[1]); |
|||
Assert.Equal(1, ptr[2]); |
|||
} |
|||
|
|||
[Theory] |
|||
[MemberData(nameof(ColorData))] |
|||
public void Equals_WhenTrue(byte r, byte g, byte b) |
|||
{ |
|||
var x = new Bgr24(r, g, b); |
|||
var y = new Bgr24(r, g, b); |
|||
|
|||
Assert.True(x.Equals(y)); |
|||
Assert.True(x.Equals((object)y)); |
|||
Assert.Equal(x.GetHashCode(), y.GetHashCode()); |
|||
} |
|||
|
|||
[Theory] |
|||
[InlineData(1, 2, 3, 1, 2, 4)] |
|||
[InlineData(0, 255, 0, 0, 244, 0)] |
|||
[InlineData(1, 255, 0, 0, 255, 0)] |
|||
public void Equals_WhenFalse(byte r1, byte g1, byte b1, byte r2, byte g2, byte b2) |
|||
{ |
|||
var a = new Bgr24(r1, g1, b1); |
|||
var b = new Bgr24(r2, g2, b2); |
|||
|
|||
Assert.False(a.Equals(b)); |
|||
Assert.False(a.Equals((object)b)); |
|||
} |
|||
|
|||
|
|||
[Fact] |
|||
public void PackFromRgba32() |
|||
{ |
|||
var rgb = default(Bgr24); |
|||
rgb.PackFromRgba32(new Rgba32(1, 2, 3, 4)); |
|||
|
|||
Assert.Equal(1, rgb.R); |
|||
Assert.Equal(2, rgb.G); |
|||
Assert.Equal(3, rgb.B); |
|||
} |
|||
|
|||
private static Vector4 Vec(byte r, byte g, byte b, byte a = 255) => new Vector4( |
|||
r / 255f, |
|||
g / 255f, |
|||
b / 255f, |
|||
a / 255f); |
|||
|
|||
[Fact] |
|||
public void PackFromVector4() |
|||
{ |
|||
var rgb = default(Bgr24); |
|||
rgb.PackFromVector4(Vec(1, 2, 3, 4)); |
|||
|
|||
Assert.Equal(1, rgb.R); |
|||
Assert.Equal(2, rgb.G); |
|||
Assert.Equal(3, rgb.B); |
|||
} |
|||
|
|||
[Fact] |
|||
public void ToVector4() |
|||
{ |
|||
var rgb = new Bgr24(1, 2, 3); |
|||
|
|||
Assert.Equal(Vec(1, 2, 3), rgb.ToVector4()); |
|||
} |
|||
|
|||
[Fact] |
|||
public void ToRgb24() |
|||
{ |
|||
var rgb = new Bgr24(1, 2, 3); |
|||
var dest = default(Rgb24); |
|||
|
|||
rgb.ToRgb24(ref dest); |
|||
|
|||
Assert.Equal(new Rgb24(1, 2, 3), dest); |
|||
} |
|||
|
|||
[Fact] |
|||
public void ToRgba32() |
|||
{ |
|||
var rgb = new Bgr24(1, 2, 3); |
|||
var rgba = default(Rgba32); |
|||
|
|||
rgb.ToRgba32(ref rgba); |
|||
|
|||
Assert.Equal(new Rgba32(1, 2, 3, 255), rgba); |
|||
} |
|||
|
|||
[Fact] |
|||
public void ToBgr24() |
|||
{ |
|||
var rgb = new Bgr24(1, 2, 3); |
|||
var bgr = default(Bgr24); |
|||
|
|||
rgb.ToBgr24(ref bgr); |
|||
|
|||
Assert.Equal(new Bgr24(1, 2, 3), bgr); |
|||
} |
|||
|
|||
[Fact] |
|||
public void ToBgra32() |
|||
{ |
|||
var rgb = new Bgr24(1, 2, 3); |
|||
var bgra = default(Bgra32); |
|||
|
|||
rgb.ToBgra32(ref bgra); |
|||
|
|||
Assert.Equal(new Bgra32(1, 2, 3, 255), bgra); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,150 @@ |
|||
// ReSharper disable InconsistentNaming
|
|||
namespace ImageSharp.Tests |
|||
{ |
|||
using System.Numerics; |
|||
|
|||
using ImageSharp.PixelFormats; |
|||
|
|||
using Xunit; |
|||
|
|||
public class Bgra32Tests |
|||
{ |
|||
public static readonly TheoryData<byte, byte, byte, byte> ColorData = |
|||
new TheoryData<byte, byte, byte, byte>() |
|||
{ |
|||
{ 1, 2, 3, 4 }, { 4, 5, 6, 7 }, { 0, 255, 42, 0 }, { 1, 2, 3, 255 } |
|||
}; |
|||
|
|||
[Theory] |
|||
[MemberData(nameof(ColorData))] |
|||
public void Constructor(byte b, byte g, byte r, byte a) |
|||
{ |
|||
var p = new Bgra32(r, g, b, a); |
|||
|
|||
Assert.Equal(r, p.R); |
|||
Assert.Equal(g, p.G); |
|||
Assert.Equal(b, p.B); |
|||
Assert.Equal(a, p.A); |
|||
} |
|||
|
|||
[Fact] |
|||
public unsafe void ByteLayoutIsSequentialBgra() |
|||
{ |
|||
var color = new Bgra32(1, 2, 3, 4); |
|||
byte* ptr = (byte*)&color; |
|||
|
|||
Assert.Equal(3, ptr[0]); |
|||
Assert.Equal(2, ptr[1]); |
|||
Assert.Equal(1, ptr[2]); |
|||
Assert.Equal(4, ptr[3]); |
|||
} |
|||
|
|||
[Theory] |
|||
[MemberData(nameof(ColorData))] |
|||
public void Equality_WhenTrue(byte b, byte g, byte r, byte a) |
|||
{ |
|||
var x = new Bgra32(r, g, b, a); |
|||
var y = new Bgra32(r, g, b, a); |
|||
|
|||
Assert.True(x.Equals(y)); |
|||
Assert.True(x.Equals((object)y)); |
|||
Assert.Equal(x.GetHashCode(), y.GetHashCode()); |
|||
} |
|||
|
|||
[Theory] |
|||
[InlineData(1, 2, 3, 4, 1, 2, 3, 5)] |
|||
[InlineData(0, 0, 255, 0, 0, 0, 244, 0)] |
|||
[InlineData(0, 255, 0, 0, 0, 244, 0, 0)] |
|||
[InlineData(1, 255, 0, 0, 0, 255, 0, 0)] |
|||
public void Equality_WhenFalse(byte b1, byte g1, byte r1, byte a1, byte b2, byte g2, byte r2, byte a2) |
|||
{ |
|||
var x = new Bgra32(r1, g1, b1, a1); |
|||
var y = new Bgra32(r2, g2, b2, a2); |
|||
|
|||
Assert.False(x.Equals(y)); |
|||
Assert.False(x.Equals((object)y)); |
|||
} |
|||
|
|||
|
|||
[Fact] |
|||
public void PackFromRgba32() |
|||
{ |
|||
var rgb = default(Rgb24); |
|||
rgb.PackFromRgba32(new Rgba32(1, 2, 3, 4)); |
|||
|
|||
Assert.Equal(1, rgb.R); |
|||
Assert.Equal(2, rgb.G); |
|||
Assert.Equal(3, rgb.B); |
|||
} |
|||
|
|||
private static Vector4 Vec(byte r, byte g, byte b, byte a = 255) => new Vector4( |
|||
r / 255f, |
|||
g / 255f, |
|||
b / 255f, |
|||
a / 255f); |
|||
|
|||
[Fact] |
|||
public void PackFromVector4() |
|||
{ |
|||
var c = default(Bgra32); |
|||
c.PackFromVector4(Vec(1, 2, 3, 4)); |
|||
|
|||
Assert.Equal(1, c.R); |
|||
Assert.Equal(2, c.G); |
|||
Assert.Equal(3, c.B); |
|||
Assert.Equal(4, c.A); |
|||
} |
|||
|
|||
[Fact] |
|||
public void ToVector4() |
|||
{ |
|||
var rgb = new Bgra32(1, 2, 3, 4); |
|||
|
|||
Assert.Equal(Vec(1, 2, 3, 4), rgb.ToVector4()); |
|||
} |
|||
|
|||
[Fact] |
|||
public void ToRgb24() |
|||
{ |
|||
var c = new Bgra32(1, 2, 3, 4); |
|||
var dest = default(Rgb24); |
|||
|
|||
c.ToRgb24(ref dest); |
|||
|
|||
Assert.Equal(new Rgb24(1, 2, 3), dest); |
|||
} |
|||
|
|||
[Fact] |
|||
public void ToRgba32() |
|||
{ |
|||
var c = new Bgra32(1, 2, 3, 4); |
|||
var rgba = default(Rgba32); |
|||
|
|||
c.ToRgba32(ref rgba); |
|||
|
|||
Assert.Equal(new Rgba32(1, 2, 3, 4), rgba); |
|||
} |
|||
|
|||
[Fact] |
|||
public void ToBgr24() |
|||
{ |
|||
var rgb = new Bgra32(1, 2, 3, 4); |
|||
var bgr = default(Bgr24); |
|||
|
|||
rgb.ToBgr24(ref bgr); |
|||
|
|||
Assert.Equal(new Bgr24(1, 2, 3), bgr); |
|||
} |
|||
|
|||
[Fact] |
|||
public void ToBgra32() |
|||
{ |
|||
var rgb = new Bgra32(1, 2, 3, 4); |
|||
var bgra = default(Bgra32); |
|||
|
|||
rgb.ToBgra32(ref bgra); |
|||
|
|||
Assert.Equal(new Bgra32(1, 2, 3, 4), bgra); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,50 @@ |
|||
// <copyright file="PixelBlenderTests.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp.Tests.PixelFormats |
|||
{ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Text; |
|||
using ImageSharp.PixelFormats; |
|||
using ImageSharp.PixelFormats.PixelBlenders; |
|||
using ImageSharp.Tests.TestUtilities; |
|||
using Xunit; |
|||
|
|||
public partial class PixelOperationsTests |
|||
{ |
|||
public static TheoryData<object, Type, PixelBlenderMode> BlenderMappings = new TheoryData<object, Type, PixelBlenderMode>() |
|||
{ |
|||
{ new TestPixel<Rgba32>(), typeof(DefaultNormalPixelBlender<Rgba32>), PixelBlenderMode.Normal }, |
|||
{ new TestPixel<Rgba32>(), typeof(DefaultScreenPixelBlender<Rgba32>), PixelBlenderMode.Screen }, |
|||
{ new TestPixel<Rgba32>(), typeof(DefaultHardLightPixelBlender<Rgba32>), PixelBlenderMode.HardLight }, |
|||
{ new TestPixel<Rgba32>(), typeof(DefaultOverlayPixelBlender<Rgba32>), PixelBlenderMode.Overlay }, |
|||
{ new TestPixel<Rgba32>(), typeof(DefaultDarkenPixelBlender<Rgba32>), PixelBlenderMode.Darken }, |
|||
{ new TestPixel<Rgba32>(), typeof(DefaultLightenPixelBlender<Rgba32>), PixelBlenderMode.Lighten }, |
|||
{ new TestPixel<Rgba32>(), typeof(DefaultAddPixelBlender<Rgba32>), PixelBlenderMode.Add }, |
|||
{ new TestPixel<Rgba32>(), typeof(DefaultSubstractPixelBlender<Rgba32>), PixelBlenderMode.Substract }, |
|||
{ new TestPixel<Rgba32>(), typeof(DefaultMultiplyPixelBlender<Rgba32>), PixelBlenderMode.Multiply }, |
|||
|
|||
{ new TestPixel<RgbaVector>(), typeof(DefaultNormalPixelBlender<RgbaVector>), PixelBlenderMode.Normal }, |
|||
{ new TestPixel<RgbaVector>(), typeof(DefaultScreenPixelBlender<RgbaVector>), PixelBlenderMode.Screen }, |
|||
{ new TestPixel<RgbaVector>(), typeof(DefaultHardLightPixelBlender<RgbaVector>), PixelBlenderMode.HardLight }, |
|||
{ new TestPixel<RgbaVector>(), typeof(DefaultOverlayPixelBlender<RgbaVector>), PixelBlenderMode.Overlay }, |
|||
{ new TestPixel<RgbaVector>(), typeof(DefaultDarkenPixelBlender<RgbaVector>), PixelBlenderMode.Darken }, |
|||
{ new TestPixel<RgbaVector>(), typeof(DefaultLightenPixelBlender<RgbaVector>), PixelBlenderMode.Lighten }, |
|||
{ new TestPixel<RgbaVector>(), typeof(DefaultAddPixelBlender<RgbaVector>), PixelBlenderMode.Add }, |
|||
{ new TestPixel<RgbaVector>(), typeof(DefaultSubstractPixelBlender<RgbaVector>), PixelBlenderMode.Substract }, |
|||
{ new TestPixel<RgbaVector>(), typeof(DefaultMultiplyPixelBlender<RgbaVector>), PixelBlenderMode.Multiply }, |
|||
}; |
|||
|
|||
[Theory] |
|||
[MemberData(nameof(BlenderMappings))] |
|||
public void ReturnsCorrectBlender<TPixel>(TestPixel<TPixel> pixel, Type type, PixelBlenderMode mode) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
PixelBlender<TPixel> blender = PixelOperations<TPixel>.Instance.GetPixelBlender(mode); |
|||
Assert.IsType(type, blender); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,143 @@ |
|||
// ReSharper disable InconsistentNaming
|
|||
namespace ImageSharp.Tests |
|||
{ |
|||
using System; |
|||
using System.Numerics; |
|||
|
|||
using ImageSharp.PixelFormats; |
|||
|
|||
using Xunit; |
|||
|
|||
public class Rgb24Tests |
|||
{ |
|||
public static readonly TheoryData<byte, byte, byte> ColorData = |
|||
new TheoryData<byte, byte, byte>() { { 1, 2, 3 }, { 4, 5, 6 }, { 0, 255, 42 } }; |
|||
|
|||
[Theory] |
|||
[MemberData(nameof(ColorData))] |
|||
public void Constructor(byte r, byte g, byte b) |
|||
{ |
|||
var p = new Rgb24(r, g, b); |
|||
|
|||
Assert.Equal(r, p.R); |
|||
Assert.Equal(g, p.G); |
|||
Assert.Equal(b, p.B); |
|||
} |
|||
|
|||
[Fact] |
|||
public unsafe void ByteLayoutIsSequentialRgb() |
|||
{ |
|||
var color = new Rgb24(1, 2, 3); |
|||
byte* ptr = (byte*)&color; |
|||
|
|||
Assert.Equal(1, ptr[0]); |
|||
Assert.Equal(2, ptr[1]); |
|||
Assert.Equal(3, ptr[2]); |
|||
} |
|||
|
|||
[Theory] |
|||
[MemberData(nameof(ColorData))] |
|||
public void Equals_WhenTrue(byte r, byte g, byte b) |
|||
{ |
|||
var x = new Rgb24(r, g, b); |
|||
var y = new Rgb24(r, g, b); |
|||
|
|||
Assert.True(x.Equals(y)); |
|||
Assert.True(x.Equals((object)y)); |
|||
Assert.Equal(x.GetHashCode(), y.GetHashCode()); |
|||
} |
|||
|
|||
[Theory] |
|||
[InlineData(1, 2, 3, 1, 2, 4)] |
|||
[InlineData(0, 255, 0, 0, 244, 0)] |
|||
[InlineData(1, 255, 0, 0, 255, 0)] |
|||
public void Equals_WhenFalse(byte r1, byte g1, byte b1, byte r2, byte g2, byte b2) |
|||
{ |
|||
var a = new Rgb24(r1, g1, b1); |
|||
var b = new Rgb24(r2, g2, b2); |
|||
|
|||
Assert.False(a.Equals(b)); |
|||
Assert.False(a.Equals((object)b)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void PackFromRgba32() |
|||
{ |
|||
var rgb = default(Rgb24); |
|||
rgb.PackFromRgba32(new Rgba32(1, 2, 3, 4)); |
|||
|
|||
Assert.Equal(1, rgb.R); |
|||
Assert.Equal(2, rgb.G); |
|||
Assert.Equal(3, rgb.B); |
|||
} |
|||
|
|||
private static Vector4 Vec(byte r, byte g, byte b, byte a = 255) => new Vector4( |
|||
r / 255f, |
|||
g / 255f, |
|||
b / 255f, |
|||
a / 255f); |
|||
|
|||
[Fact] |
|||
public void PackFromVector4() |
|||
{ |
|||
var rgb = default(Rgb24); |
|||
rgb.PackFromVector4(Vec(1, 2, 3, 4)); |
|||
|
|||
Assert.Equal(1, rgb.R); |
|||
Assert.Equal(2, rgb.G); |
|||
Assert.Equal(3, rgb.B); |
|||
} |
|||
|
|||
[Fact] |
|||
public void ToVector4() |
|||
{ |
|||
var rgb = new Rgb24(1, 2, 3); |
|||
|
|||
Assert.Equal(Vec(1, 2, 3), rgb.ToVector4()); |
|||
} |
|||
|
|||
[Fact] |
|||
public void ToRgb24() |
|||
{ |
|||
var rgb = new Rgb24(1, 2, 3); |
|||
var dest = default(Rgb24); |
|||
|
|||
rgb.ToRgb24(ref dest); |
|||
|
|||
Assert.Equal(rgb, dest); |
|||
} |
|||
|
|||
[Fact] |
|||
public void ToRgba32() |
|||
{ |
|||
var rgb = new Rgb24(1, 2, 3); |
|||
var rgba = default(Rgba32); |
|||
|
|||
rgb.ToRgba32(ref rgba); |
|||
|
|||
Assert.Equal(new Rgba32(1, 2, 3, 255), rgba); |
|||
} |
|||
|
|||
[Fact] |
|||
public void ToBgr24() |
|||
{ |
|||
var rgb = new Rgb24(1, 2, 3); |
|||
var bgr = default(Bgr24); |
|||
|
|||
rgb.ToBgr24(ref bgr); |
|||
|
|||
Assert.Equal(new Bgr24(1, 2, 3), bgr); |
|||
} |
|||
|
|||
[Fact] |
|||
public void ToBgra32() |
|||
{ |
|||
var rgb = new Rgb24(1, 2, 3); |
|||
var bgra = default(Bgra32); |
|||
|
|||
rgb.ToBgra32(ref bgra); |
|||
|
|||
Assert.Equal(new Bgra32(1, 2, 3, 255), bgra); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue