mirror of https://github.com/SixLabors/ImageSharp
committed by
GitHub
158 changed files with 4924 additions and 806 deletions
@ -0,0 +1,98 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Runtime.CompilerServices; |
|||
|
|||
namespace SixLabors.ImageSharp.Common.Helpers |
|||
{ |
|||
internal static class HexConverter |
|||
{ |
|||
/// <summary>
|
|||
/// Parses a hexadecimal string into a byte array without allocations. Throws on non-hexadecimal character.
|
|||
/// Adapted from https://source.dot.net/#System.Private.CoreLib/Convert.cs,c9e4fbeaca708991.
|
|||
/// </summary>
|
|||
/// <param name="chars">The hexadecimal string to parse.</param>
|
|||
/// <param name="bytes">The destination for the parsed bytes. Must be at least <paramref name="chars"/>.Length / 2 bytes long.</param>
|
|||
/// <returns>The number of bytes written to <paramref name="bytes"/>.</returns>
|
|||
public static int HexStringToBytes(ReadOnlySpan<char> chars, Span<byte> bytes) |
|||
{ |
|||
if ((chars.Length % 2) != 0) |
|||
{ |
|||
throw new ArgumentException("Input string length must be a multiple of 2", nameof(chars)); |
|||
} |
|||
|
|||
if ((bytes.Length * 2) < chars.Length) |
|||
{ |
|||
throw new ArgumentException("Output span must be at least half the length of the input string"); |
|||
} |
|||
else |
|||
{ |
|||
// Slightly better performance in the loop below, allows us to skip a bounds check
|
|||
// while still supporting output buffers that are larger than necessary
|
|||
bytes = bytes.Slice(0, chars.Length / 2); |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
static int FromChar(int c) |
|||
{ |
|||
// Map from an ASCII char to its hex value, e.g. arr['b'] == 11. 0xFF means it's not a hex digit.
|
|||
// This doesn't actually allocate.
|
|||
ReadOnlySpan<byte> charToHexLookup = new byte[] |
|||
{ |
|||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 15
|
|||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 31
|
|||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 47
|
|||
0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 63
|
|||
0xFF, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 79
|
|||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 95
|
|||
0xFF, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 111
|
|||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 127
|
|||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 143
|
|||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 159
|
|||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 175
|
|||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 191
|
|||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 207
|
|||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 223
|
|||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 239
|
|||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 255
|
|||
}; |
|||
|
|||
return c >= charToHexLookup.Length ? 0xFF : charToHexLookup[c]; |
|||
} |
|||
|
|||
// See https://source.dot.net/#System.Private.CoreLib/HexConverter.cs,4681d45a0aa0b361
|
|||
int i = 0; |
|||
int j = 0; |
|||
int byteLo = 0; |
|||
int byteHi = 0; |
|||
while (j < bytes.Length) |
|||
{ |
|||
byteLo = FromChar(chars[i + 1]); |
|||
byteHi = FromChar(chars[i]); |
|||
|
|||
// byteHi hasn't been shifted to the high half yet, so the only way the bitwise or produces this pattern
|
|||
// is if either byteHi or byteLo was not a hex character.
|
|||
if ((byteLo | byteHi) == 0xFF) |
|||
{ |
|||
break; |
|||
} |
|||
|
|||
bytes[j++] = (byte)((byteHi << 4) | byteLo); |
|||
i += 2; |
|||
} |
|||
|
|||
if (byteLo == 0xFF) |
|||
{ |
|||
i++; |
|||
} |
|||
|
|||
if ((byteLo | byteHi) == 0xFF) |
|||
{ |
|||
throw new ArgumentException("Input string contained non-hexadecimal characters", nameof(chars)); |
|||
} |
|||
|
|||
return j; |
|||
} |
|||
} |
|||
} |
|||
@ -1,64 +1,78 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.IO; |
|||
using SixLabors.ImageSharp.Formats.Tiff.Constants; |
|||
using SixLabors.ImageSharp.Memory; |
|||
using SixLabors.ImageSharp.Metadata.Profiles.Exif; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Tiff |
|||
{ |
|||
internal class EntryReader : BaseExifReader |
|||
{ |
|||
private readonly uint startOffset; |
|||
|
|||
private readonly SortedList<uint, Action> lazyLoaders; |
|||
|
|||
public EntryReader(Stream stream, ByteOrder byteOrder, uint ifdOffset, SortedList<uint, Action> lazyLoaders) |
|||
: base(stream) |
|||
{ |
|||
public EntryReader(Stream stream, ByteOrder byteOrder, MemoryAllocator allocator) |
|||
: base(stream, allocator) => |
|||
this.IsBigEndian = byteOrder == ByteOrder.BigEndian; |
|||
this.startOffset = ifdOffset; |
|||
this.lazyLoaders = lazyLoaders; |
|||
} |
|||
|
|||
public List<IExifValue> Values { get; } = new(); |
|||
|
|||
public uint NextIfdOffset { get; private set; } |
|||
public ulong NextIfdOffset { get; private set; } |
|||
|
|||
public void ReadTags() |
|||
public void ReadTags(bool isBigTiff, ulong ifdOffset) |
|||
{ |
|||
this.ReadValues(this.Values, this.startOffset); |
|||
this.NextIfdOffset = this.ReadUInt32(); |
|||
if (!isBigTiff) |
|||
{ |
|||
this.ReadValues(this.Values, (uint)ifdOffset); |
|||
this.NextIfdOffset = this.ReadUInt32(); |
|||
|
|||
this.ReadSubIfd(this.Values); |
|||
} |
|||
else |
|||
{ |
|||
this.ReadValues64(this.Values, ifdOffset); |
|||
this.NextIfdOffset = this.ReadUInt64(); |
|||
|
|||
this.ReadSubIfd(this.Values); |
|||
//// this.ReadSubIfd64(this.Values);
|
|||
} |
|||
} |
|||
|
|||
protected override void RegisterExtLoader(uint offset, Action reader) => |
|||
this.lazyLoaders.Add(offset, reader); |
|||
public void ReadBigValues() => this.ReadBigValues(this.Values); |
|||
} |
|||
|
|||
internal class HeaderReader : BaseExifReader |
|||
{ |
|||
public HeaderReader(Stream stream, ByteOrder byteOrder) |
|||
: base(stream) => |
|||
: base(stream, null) => |
|||
this.IsBigEndian = byteOrder == ByteOrder.BigEndian; |
|||
|
|||
public uint FirstIfdOffset { get; private set; } |
|||
public bool IsBigTiff { get; private set; } |
|||
|
|||
public uint ReadFileHeader() |
|||
public ulong FirstIfdOffset { get; private set; } |
|||
|
|||
public void ReadFileHeader() |
|||
{ |
|||
ushort magic = this.ReadUInt16(); |
|||
if (magic != TiffConstants.HeaderMagicNumber) |
|||
if (magic == TiffConstants.HeaderMagicNumber) |
|||
{ |
|||
TiffThrowHelper.ThrowInvalidHeader(); |
|||
this.IsBigTiff = false; |
|||
this.FirstIfdOffset = this.ReadUInt32(); |
|||
return; |
|||
} |
|||
else if (magic == TiffConstants.BigTiffHeaderMagicNumber) |
|||
{ |
|||
this.IsBigTiff = true; |
|||
|
|||
this.FirstIfdOffset = this.ReadUInt32(); |
|||
return this.FirstIfdOffset; |
|||
} |
|||
ushort bytesize = this.ReadUInt16(); |
|||
ushort reserve = this.ReadUInt16(); |
|||
if (bytesize == TiffConstants.BigTiffBytesize && reserve == 0) |
|||
{ |
|||
this.FirstIfdOffset = this.ReadUInt64(); |
|||
return; |
|||
} |
|||
} |
|||
|
|||
protected override void RegisterExtLoader(uint offset, Action reader) => throw new NotSupportedException(); |
|||
TiffThrowHelper.ThrowInvalidHeader(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,21 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Tiff |
|||
{ |
|||
/// <summary>
|
|||
/// The TIFF format type enum.
|
|||
/// </summary>
|
|||
public enum TiffFormatType |
|||
{ |
|||
/// <summary>
|
|||
/// The TIFF file format type.
|
|||
/// </summary>
|
|||
Default, |
|||
|
|||
/// <summary>
|
|||
/// The BigTIFF format type.
|
|||
/// </summary>
|
|||
BigTIFF |
|||
} |
|||
} |
|||
@ -0,0 +1,52 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Buffers; |
|||
using SixLabors.ImageSharp.Memory.Internals; |
|||
|
|||
namespace SixLabors.ImageSharp.Memory |
|||
{ |
|||
/// <summary>
|
|||
/// Cached pointer or array data enabling fast <see cref="Span{T}"/> access from
|
|||
/// known <see cref="IMemoryOwner{T}"/> implementations.
|
|||
/// </summary>
|
|||
internal unsafe struct MemoryGroupSpanCache |
|||
{ |
|||
public SpanCacheMode Mode; |
|||
public byte[] SingleArray; |
|||
public void* SinglePointer; |
|||
public void*[] MultiPointer; |
|||
|
|||
public static MemoryGroupSpanCache Create<T>(IMemoryOwner<T>[] memoryOwners) |
|||
where T : struct |
|||
{ |
|||
IMemoryOwner<T> owner0 = memoryOwners[0]; |
|||
MemoryGroupSpanCache memoryGroupSpanCache = default; |
|||
if (memoryOwners.Length == 1) |
|||
{ |
|||
if (owner0 is SharedArrayPoolBuffer<T> sharedPoolBuffer) |
|||
{ |
|||
memoryGroupSpanCache.Mode = SpanCacheMode.SingleArray; |
|||
memoryGroupSpanCache.SingleArray = sharedPoolBuffer.Array; |
|||
} |
|||
else if (owner0 is UnmanagedBuffer<T> unmanagedBuffer) |
|||
{ |
|||
memoryGroupSpanCache.Mode = SpanCacheMode.SinglePointer; |
|||
memoryGroupSpanCache.SinglePointer = unmanagedBuffer.Pointer; |
|||
} |
|||
} |
|||
else if (owner0 is UnmanagedBuffer<T>) |
|||
{ |
|||
memoryGroupSpanCache.Mode = SpanCacheMode.MultiPointer; |
|||
memoryGroupSpanCache.MultiPointer = new void*[memoryOwners.Length]; |
|||
for (int i = 0; i < memoryOwners.Length; i++) |
|||
{ |
|||
memoryGroupSpanCache.MultiPointer[i] = ((UnmanagedBuffer<T>)memoryOwners[i]).Pointer; |
|||
} |
|||
} |
|||
|
|||
return memoryGroupSpanCache; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,16 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
namespace SixLabors.ImageSharp.Memory |
|||
{ |
|||
/// <summary>
|
|||
/// Selects active values in <see cref="MemoryGroupSpanCache"/>.
|
|||
/// </summary>
|
|||
internal enum SpanCacheMode |
|||
{ |
|||
Default = default, |
|||
SingleArray, |
|||
SinglePointer, |
|||
MultiPointer |
|||
} |
|||
} |
|||
@ -0,0 +1,66 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System.Globalization; |
|||
|
|||
namespace SixLabors.ImageSharp.Metadata.Profiles.Exif |
|||
{ |
|||
internal sealed class ExifLong8 : ExifValue<ulong> |
|||
{ |
|||
public ExifLong8(ExifTag<ulong> tag) |
|||
: base(tag) |
|||
{ |
|||
} |
|||
|
|||
public ExifLong8(ExifTagValue tag) |
|||
: base(tag) |
|||
{ |
|||
} |
|||
|
|||
private ExifLong8(ExifLong8 value) |
|||
: base(value) |
|||
{ |
|||
} |
|||
|
|||
public override ExifDataType DataType => ExifDataType.Long8; |
|||
|
|||
protected override string StringValue => this.Value.ToString(CultureInfo.InvariantCulture); |
|||
|
|||
public override bool TrySetValue(object value) |
|||
{ |
|||
if (base.TrySetValue(value)) |
|||
{ |
|||
return true; |
|||
} |
|||
|
|||
switch (value) |
|||
{ |
|||
case int intValue: |
|||
if (intValue >= uint.MinValue) |
|||
{ |
|||
this.Value = (uint)intValue; |
|||
return true; |
|||
} |
|||
|
|||
return false; |
|||
case uint uintValue: |
|||
this.Value = uintValue; |
|||
|
|||
return true; |
|||
case long intValue: |
|||
if (intValue >= 0) |
|||
{ |
|||
this.Value = (ulong)intValue; |
|||
return true; |
|||
} |
|||
|
|||
return false; |
|||
default: |
|||
|
|||
return false; |
|||
} |
|||
} |
|||
|
|||
public override IExifValue DeepClone() => new ExifLong8(this); |
|||
} |
|||
} |
|||
@ -0,0 +1,171 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System.Runtime.CompilerServices; |
|||
|
|||
namespace SixLabors.ImageSharp.Metadata.Profiles.Exif |
|||
{ |
|||
internal sealed class ExifLong8Array : ExifArrayValue<ulong> |
|||
{ |
|||
public ExifLong8Array(ExifTagValue tag) |
|||
: base(tag) |
|||
{ |
|||
} |
|||
|
|||
private ExifLong8Array(ExifLong8Array value) |
|||
: base(value) |
|||
{ |
|||
} |
|||
|
|||
public override ExifDataType DataType |
|||
{ |
|||
get |
|||
{ |
|||
if (this.Value is not null) |
|||
{ |
|||
foreach (ulong value in this.Value) |
|||
{ |
|||
if (value > uint.MaxValue) |
|||
{ |
|||
return ExifDataType.Long8; |
|||
} |
|||
} |
|||
} |
|||
|
|||
return ExifDataType.Long; |
|||
} |
|||
} |
|||
|
|||
public override bool TrySetValue(object value) |
|||
{ |
|||
if (base.TrySetValue(value)) |
|||
{ |
|||
return true; |
|||
} |
|||
|
|||
switch (value) |
|||
{ |
|||
case int val: |
|||
return this.SetSingle((ulong)Numerics.Clamp(val, 0, int.MaxValue)); |
|||
|
|||
case uint val: |
|||
return this.SetSingle((ulong)val); |
|||
|
|||
case short val: |
|||
return this.SetSingle((ulong)Numerics.Clamp(val, 0, short.MaxValue)); |
|||
|
|||
case ushort val: |
|||
return this.SetSingle((ulong)val); |
|||
|
|||
case long val: |
|||
return this.SetSingle((ulong)Numerics.Clamp(val, 0, long.MaxValue)); |
|||
|
|||
case long[] array: |
|||
{ |
|||
if (value.GetType() == typeof(ulong[])) |
|||
{ |
|||
return this.SetArray((ulong[])value); |
|||
} |
|||
|
|||
return this.SetArray(array); |
|||
} |
|||
|
|||
case int[] array: |
|||
{ |
|||
if (value.GetType() == typeof(uint[])) |
|||
{ |
|||
return this.SetArray((uint[])value); |
|||
} |
|||
|
|||
return this.SetArray(array); |
|||
} |
|||
|
|||
case short[] array: |
|||
{ |
|||
if (value.GetType() == typeof(ushort[])) |
|||
{ |
|||
return this.SetArray((ushort[])value); |
|||
} |
|||
|
|||
return this.SetArray(array); |
|||
} |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
public override IExifValue DeepClone() => new ExifLong8Array(this); |
|||
|
|||
private bool SetSingle(ulong value) |
|||
{ |
|||
this.Value = new[] { value }; |
|||
return true; |
|||
} |
|||
|
|||
private bool SetArray(long[] values) |
|||
{ |
|||
var numbers = new ulong[values.Length]; |
|||
for (int i = 0; i < values.Length; i++) |
|||
{ |
|||
numbers[i] = (ulong)(values[i] < 0 ? 0 : values[i]); |
|||
} |
|||
|
|||
this.Value = numbers; |
|||
return true; |
|||
} |
|||
|
|||
private bool SetArray(ulong[] values) |
|||
{ |
|||
this.Value = values; |
|||
return true; |
|||
} |
|||
|
|||
private bool SetArray(int[] values) |
|||
{ |
|||
var numbers = new ulong[values.Length]; |
|||
for (int i = 0; i < values.Length; i++) |
|||
{ |
|||
numbers[i] = (ulong)Numerics.Clamp(values[i], 0, int.MaxValue); |
|||
} |
|||
|
|||
this.Value = numbers; |
|||
return true; |
|||
} |
|||
|
|||
private bool SetArray(uint[] values) |
|||
{ |
|||
var numbers = new ulong[values.Length]; |
|||
for (int i = 0; i < values.Length; i++) |
|||
{ |
|||
numbers[i] = (ulong)values[i]; |
|||
} |
|||
|
|||
this.Value = numbers; |
|||
return true; |
|||
} |
|||
|
|||
private bool SetArray(short[] values) |
|||
{ |
|||
var numbers = new ulong[values.Length]; |
|||
for (int i = 0; i < values.Length; i++) |
|||
{ |
|||
numbers[i] = (ulong)Numerics.Clamp(values[i], 0, short.MaxValue); |
|||
} |
|||
|
|||
this.Value = numbers; |
|||
return true; |
|||
} |
|||
|
|||
private bool SetArray(ushort[] values) |
|||
{ |
|||
var numbers = new ulong[values.Length]; |
|||
for (int i = 0; i < values.Length; i++) |
|||
{ |
|||
numbers[i] = (ulong)values[i]; |
|||
} |
|||
|
|||
this.Value = numbers; |
|||
return true; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,26 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System.Globalization; |
|||
|
|||
namespace SixLabors.ImageSharp.Metadata.Profiles.Exif |
|||
{ |
|||
internal sealed class ExifSignedLong8 : ExifValue<long> |
|||
{ |
|||
public ExifSignedLong8(ExifTagValue tag) |
|||
: base(tag) |
|||
{ |
|||
} |
|||
|
|||
private ExifSignedLong8(ExifSignedLong8 value) |
|||
: base(value) |
|||
{ |
|||
} |
|||
|
|||
public override ExifDataType DataType => ExifDataType.SignedLong8; |
|||
|
|||
protected override string StringValue => this.Value.ToString(CultureInfo.InvariantCulture); |
|||
|
|||
public override IExifValue DeepClone() => new ExifSignedLong8(this); |
|||
} |
|||
} |
|||
@ -0,0 +1,22 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
namespace SixLabors.ImageSharp.Metadata.Profiles.Exif |
|||
{ |
|||
internal sealed class ExifSignedLong8Array : ExifArrayValue<long> |
|||
{ |
|||
public ExifSignedLong8Array(ExifTagValue tag) |
|||
: base(tag) |
|||
{ |
|||
} |
|||
|
|||
private ExifSignedLong8Array(ExifSignedLong8Array value) |
|||
: base(value) |
|||
{ |
|||
} |
|||
|
|||
public override ExifDataType DataType => ExifDataType.SignedLong8; |
|||
|
|||
public override IExifValue DeepClone() => new ExifSignedLong8Array(this); |
|||
} |
|||
} |
|||
@ -0,0 +1,396 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// 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 (least significant to most significant byte).
|
|||
/// <para>
|
|||
/// Ranges from [0, 0, 0, 0] to [1, 1, 1, 1] in vector form.
|
|||
/// </para>
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// 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 partial struct Abgr32 : IPixel<Abgr32>, IPackedVector<uint> |
|||
{ |
|||
/// <summary>
|
|||
/// Gets or sets the alpha component.
|
|||
/// </summary>
|
|||
public byte A; |
|||
|
|||
/// <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>
|
|||
/// The maximum byte value.
|
|||
/// </summary>
|
|||
private static readonly Vector4 MaxBytes = new(255); |
|||
|
|||
/// <summary>
|
|||
/// The half vector value.
|
|||
/// </summary>
|
|||
private static readonly Vector4 Half = new(0.5F); |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Abgr32"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="r">The red component.</param>
|
|||
/// <param name="g">The green component.</param>
|
|||
/// <param name="b">The blue component.</param>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public Abgr32(byte r, byte g, byte b) |
|||
{ |
|||
this.R = r; |
|||
this.G = g; |
|||
this.B = b; |
|||
this.A = byte.MaxValue; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Abgr32"/> 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(InliningOptions.ShortMethod)] |
|||
public Abgr32(byte r, byte g, byte b, byte a) |
|||
{ |
|||
this.R = r; |
|||
this.G = g; |
|||
this.B = b; |
|||
this.A = a; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Abgr32"/> 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(InliningOptions.ShortMethod)] |
|||
public Abgr32(float r, float g, float b, float a = 1) |
|||
: this() => this.Pack(r, g, b, a); |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Abgr32"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="vector">
|
|||
/// The vector containing the components for the packed vector.
|
|||
/// </param>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public Abgr32(Vector3 vector) |
|||
: this() => this.Pack(ref vector); |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Abgr32"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="vector">
|
|||
/// The vector containing the components for the packed vector.
|
|||
/// </param>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public Abgr32(Vector4 vector) |
|||
: this() => this.Pack(ref vector); |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Abgr32"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="packed">
|
|||
/// The packed value.
|
|||
/// </param>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public Abgr32(uint packed) |
|||
: this() => this.Abgr = packed; |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the packed representation of the Abgrb32 struct.
|
|||
/// </summary>
|
|||
public uint Abgr |
|||
{ |
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
readonly get => Unsafe.As<Abgr32, uint>(ref Unsafe.AsRef(this)); |
|||
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
set => Unsafe.As<Abgr32, uint>(ref this) = value; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public uint PackedValue |
|||
{ |
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
readonly get => this.Abgr; |
|||
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
set => this.Abgr = value; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Converts an <see cref="Abgr32"/> to <see cref="Color"/>.
|
|||
/// </summary>
|
|||
/// <param name="source">The <see cref="Abgr32"/>.</param>
|
|||
/// <returns>The <see cref="Color"/>.</returns>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public static implicit operator Color(Abgr32 source) => new(source); |
|||
|
|||
/// <summary>
|
|||
/// Converts a <see cref="Color"/> to <see cref="Abgr32"/>.
|
|||
/// </summary>
|
|||
/// <param name="color">The <see cref="Color"/>.</param>
|
|||
/// <returns>The <see cref="Abgr32"/>.</returns>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public static implicit operator Abgr32(Color color) => color.ToAbgr32(); |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="Argb32"/> objects for equality.
|
|||
/// </summary>
|
|||
/// <param name="left">The <see cref="Abgr32"/> on the left side of the operand.</param>
|
|||
/// <param name="right">The <see cref="Abgr32"/> on the right side of the operand.</param>
|
|||
/// <returns>
|
|||
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public static bool operator ==(Abgr32 left, Abgr32 right) => left.Equals(right); |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="Abgr32"/> objects for equality.
|
|||
/// </summary>
|
|||
/// <param name="left">The <see cref="Abgr32"/> on the left side of the operand.</param>
|
|||
/// <param name="right">The <see cref="Abgr32"/> on the right side of the operand.</param>
|
|||
/// <returns>
|
|||
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public static bool operator !=(Abgr32 left, Abgr32 right) => !left.Equals(right); |
|||
|
|||
/// <inheritdoc />
|
|||
public readonly PixelOperations<Abgr32> CreatePixelOperations() => new PixelOperations(); |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public readonly Vector4 ToScaledVector4() => this.ToVector4(); |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public void FromVector4(Vector4 vector) => this.Pack(ref vector); |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public readonly Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A) / MaxBytes; |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public void FromAbgr32(Abgr32 source) => this = source; |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public void FromBgr24(Bgr24 source) |
|||
{ |
|||
// We can assign the Bgr24 value directly to last three bytes of this instance.
|
|||
ref byte thisRef = ref Unsafe.As<Abgr32, byte>(ref this); |
|||
ref byte thisRefFromB = ref Unsafe.AddByteOffset(ref thisRef, new IntPtr(1)); |
|||
Unsafe.As<byte, Bgr24>(ref thisRefFromB) = source; |
|||
this.A = byte.MaxValue; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public void FromArgb32(Argb32 source) |
|||
{ |
|||
this.R = source.R; |
|||
this.G = source.G; |
|||
this.B = source.B; |
|||
this.A = source.A; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public void FromBgra32(Bgra32 source) |
|||
{ |
|||
this.R = source.R; |
|||
this.G = source.G; |
|||
this.B = source.B; |
|||
this.A = source.A; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public void FromL8(L8 source) |
|||
{ |
|||
this.R = source.PackedValue; |
|||
this.G = source.PackedValue; |
|||
this.B = source.PackedValue; |
|||
this.A = byte.MaxValue; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public void FromL16(L16 source) |
|||
{ |
|||
byte rgb = ColorNumerics.DownScaleFrom16BitTo8Bit(source.PackedValue); |
|||
this.R = rgb; |
|||
this.G = rgb; |
|||
this.B = rgb; |
|||
this.A = byte.MaxValue; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public void FromLa16(La16 source) |
|||
{ |
|||
this.R = source.L; |
|||
this.G = source.L; |
|||
this.B = source.L; |
|||
this.A = source.A; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public void FromLa32(La32 source) |
|||
{ |
|||
byte rgb = ColorNumerics.DownScaleFrom16BitTo8Bit(source.L); |
|||
this.R = rgb; |
|||
this.G = rgb; |
|||
this.B = rgb; |
|||
this.A = ColorNumerics.DownScaleFrom16BitTo8Bit(source.A); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public void FromRgb24(Rgb24 source) |
|||
{ |
|||
this.R = source.R; |
|||
this.G = source.G; |
|||
this.B = source.B; |
|||
this.A = byte.MaxValue; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public void FromRgba32(Rgba32 source) |
|||
{ |
|||
this.R = source.R; |
|||
this.G = source.G; |
|||
this.B = source.B; |
|||
this.A = source.A; |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public void ToRgba32(ref Rgba32 dest) |
|||
{ |
|||
dest.R = this.R; |
|||
dest.G = this.G; |
|||
dest.B = this.B; |
|||
dest.A = this.A; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public void FromRgb48(Rgb48 source) |
|||
{ |
|||
this.R = ColorNumerics.DownScaleFrom16BitTo8Bit(source.R); |
|||
this.G = ColorNumerics.DownScaleFrom16BitTo8Bit(source.G); |
|||
this.B = ColorNumerics.DownScaleFrom16BitTo8Bit(source.B); |
|||
this.A = byte.MaxValue; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public void FromRgba64(Rgba64 source) |
|||
{ |
|||
this.R = ColorNumerics.DownScaleFrom16BitTo8Bit(source.R); |
|||
this.G = ColorNumerics.DownScaleFrom16BitTo8Bit(source.G); |
|||
this.B = ColorNumerics.DownScaleFrom16BitTo8Bit(source.B); |
|||
this.A = ColorNumerics.DownScaleFrom16BitTo8Bit(source.A); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override readonly bool Equals(object obj) => obj is Abgr32 abgr32 && this.Equals(abgr32); |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public readonly bool Equals(Abgr32 other) => this.Abgr == other.Abgr; |
|||
|
|||
/// <summary>
|
|||
/// Gets a string representation of the packed vector.
|
|||
/// </summary>
|
|||
/// <returns>A string representation of the packed vector.</returns>
|
|||
public override readonly string ToString() => $"Abgr({this.A}, {this.B}, {this.G}, {this.R})"; |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public override readonly int GetHashCode() => this.Abgr.GetHashCode(); |
|||
|
|||
/// <summary>
|
|||
/// 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>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
private void Pack(float x, float y, float z, float w) |
|||
{ |
|||
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>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
private void Pack(ref Vector3 vector) |
|||
{ |
|||
var value = new Vector4(vector, 1); |
|||
this.Pack(ref value); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Packs a <see cref="Vector4"/> into a color.
|
|||
/// </summary>
|
|||
/// <param name="vector">The vector containing the values to pack.</param>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
private void Pack(ref Vector4 vector) |
|||
{ |
|||
vector *= MaxBytes; |
|||
vector += Half; |
|||
vector = Numerics.Clamp(vector, Vector4.Zero, MaxBytes); |
|||
|
|||
this.R = (byte)vector.X; |
|||
this.G = (byte)vector.Y; |
|||
this.B = (byte)vector.Z; |
|||
this.A = (byte)vector.W; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,26 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using SixLabors.ImageSharp.Formats; |
|||
|
|||
namespace SixLabors.ImageSharp.PixelFormats |
|||
{ |
|||
/// <content>
|
|||
/// Provides optimized overrides for bulk operations.
|
|||
/// </content>
|
|||
public partial struct Abgr32 |
|||
{ |
|||
/// <summary>
|
|||
/// Provides optimized overrides for bulk operations.
|
|||
/// </summary>
|
|||
internal partial class PixelOperations : PixelOperations<Abgr32> |
|||
{ |
|||
private static readonly Lazy<PixelTypeInfo> LazyInfo = |
|||
new Lazy<PixelTypeInfo>(() => PixelTypeInfo.Create<Abgr32>(PixelAlphaRepresentation.Unassociated), true); |
|||
|
|||
/// <inheritdoc />
|
|||
public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,346 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
// <auto-generated />
|
|||
|
|||
using System; |
|||
using System.Numerics; |
|||
using System.Runtime.CompilerServices; |
|||
using System.Runtime.InteropServices; |
|||
using SixLabors.ImageSharp.PixelFormats.Utils; |
|||
|
|||
namespace SixLabors.ImageSharp.PixelFormats |
|||
{ |
|||
/// <content>
|
|||
/// Provides optimized overrides for bulk operations.
|
|||
/// </content>
|
|||
public partial struct Abgr32 |
|||
{ |
|||
/// <summary>
|
|||
/// Provides optimized overrides for bulk operations.
|
|||
/// </summary>
|
|||
internal partial class PixelOperations : PixelOperations<Abgr32> |
|||
{ |
|||
/// <inheritdoc />
|
|||
public override void FromAbgr32(Configuration configuration, ReadOnlySpan<Abgr32> source, Span<Abgr32> destinationPixels) |
|||
{ |
|||
Guard.NotNull(configuration, nameof(configuration)); |
|||
Guard.DestinationShouldNotBeTooShort(source, destinationPixels, nameof(destinationPixels)); |
|||
|
|||
source.CopyTo(destinationPixels.Slice(0, source.Length)); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override void ToAbgr32(Configuration configuration, ReadOnlySpan<Abgr32> sourcePixels, Span<Abgr32> destinationPixels) |
|||
{ |
|||
Guard.NotNull(configuration, nameof(configuration)); |
|||
Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); |
|||
|
|||
sourcePixels.CopyTo(destinationPixels.Slice(0, sourcePixels.Length)); |
|||
} |
|||
/// <inheritdoc />
|
|||
public override void FromVector4Destructive( |
|||
Configuration configuration, |
|||
Span<Vector4> sourceVectors, |
|||
Span<Abgr32> destinationPixels, |
|||
PixelConversionModifiers modifiers) |
|||
{ |
|||
Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destinationPixels, modifiers.Remove(PixelConversionModifiers.Scale)); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override void ToVector4( |
|||
Configuration configuration, |
|||
ReadOnlySpan<Abgr32> sourcePixels, |
|||
Span<Vector4> destVectors, |
|||
PixelConversionModifiers modifiers) |
|||
{ |
|||
Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, modifiers.Remove(PixelConversionModifiers.Scale)); |
|||
} |
|||
/// <inheritdoc />
|
|||
public override void ToRgba32( |
|||
Configuration configuration, |
|||
ReadOnlySpan<Abgr32> sourcePixels, |
|||
Span<Rgba32> destinationPixels) |
|||
{ |
|||
Guard.NotNull(configuration, nameof(configuration)); |
|||
Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); |
|||
|
|||
ReadOnlySpan<byte> source = MemoryMarshal.Cast<Abgr32, byte>(sourcePixels); |
|||
Span<byte> dest = MemoryMarshal.Cast<Rgba32, byte>(destinationPixels); |
|||
PixelConverter.FromAbgr32.ToRgba32(source, dest); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override void FromRgba32( |
|||
Configuration configuration, |
|||
ReadOnlySpan<Rgba32> sourcePixels, |
|||
Span<Abgr32> destinationPixels) |
|||
{ |
|||
Guard.NotNull(configuration, nameof(configuration)); |
|||
Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); |
|||
|
|||
ReadOnlySpan<byte> source = MemoryMarshal.Cast<Rgba32, byte>(sourcePixels); |
|||
Span<byte> dest = MemoryMarshal.Cast<Abgr32, byte>(destinationPixels); |
|||
PixelConverter.FromRgba32.ToAbgr32(source, dest); |
|||
} |
|||
/// <inheritdoc />
|
|||
public override void ToArgb32( |
|||
Configuration configuration, |
|||
ReadOnlySpan<Abgr32> sourcePixels, |
|||
Span<Argb32> destinationPixels) |
|||
{ |
|||
Guard.NotNull(configuration, nameof(configuration)); |
|||
Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); |
|||
|
|||
ReadOnlySpan<byte> source = MemoryMarshal.Cast<Abgr32, byte>(sourcePixels); |
|||
Span<byte> dest = MemoryMarshal.Cast<Argb32, byte>(destinationPixels); |
|||
PixelConverter.FromAbgr32.ToArgb32(source, dest); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override void FromArgb32( |
|||
Configuration configuration, |
|||
ReadOnlySpan<Argb32> sourcePixels, |
|||
Span<Abgr32> destinationPixels) |
|||
{ |
|||
Guard.NotNull(configuration, nameof(configuration)); |
|||
Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); |
|||
|
|||
ReadOnlySpan<byte> source = MemoryMarshal.Cast<Argb32, byte>(sourcePixels); |
|||
Span<byte> dest = MemoryMarshal.Cast<Abgr32, byte>(destinationPixels); |
|||
PixelConverter.FromArgb32.ToAbgr32(source, dest); |
|||
} |
|||
/// <inheritdoc />
|
|||
public override void ToBgra32( |
|||
Configuration configuration, |
|||
ReadOnlySpan<Abgr32> sourcePixels, |
|||
Span<Bgra32> destinationPixels) |
|||
{ |
|||
Guard.NotNull(configuration, nameof(configuration)); |
|||
Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); |
|||
|
|||
ReadOnlySpan<byte> source = MemoryMarshal.Cast<Abgr32, byte>(sourcePixels); |
|||
Span<byte> dest = MemoryMarshal.Cast<Bgra32, byte>(destinationPixels); |
|||
PixelConverter.FromAbgr32.ToBgra32(source, dest); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override void FromBgra32( |
|||
Configuration configuration, |
|||
ReadOnlySpan<Bgra32> sourcePixels, |
|||
Span<Abgr32> destinationPixels) |
|||
{ |
|||
Guard.NotNull(configuration, nameof(configuration)); |
|||
Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); |
|||
|
|||
ReadOnlySpan<byte> source = MemoryMarshal.Cast<Bgra32, byte>(sourcePixels); |
|||
Span<byte> dest = MemoryMarshal.Cast<Abgr32, byte>(destinationPixels); |
|||
PixelConverter.FromBgra32.ToAbgr32(source, dest); |
|||
} |
|||
/// <inheritdoc />
|
|||
public override void ToRgb24( |
|||
Configuration configuration, |
|||
ReadOnlySpan<Abgr32> sourcePixels, |
|||
Span<Rgb24> destinationPixels) |
|||
{ |
|||
Guard.NotNull(configuration, nameof(configuration)); |
|||
Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); |
|||
|
|||
ReadOnlySpan<byte> source = MemoryMarshal.Cast<Abgr32, byte>(sourcePixels); |
|||
Span<byte> dest = MemoryMarshal.Cast<Rgb24, byte>(destinationPixels); |
|||
PixelConverter.FromAbgr32.ToRgb24(source, dest); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override void FromRgb24( |
|||
Configuration configuration, |
|||
ReadOnlySpan<Rgb24> sourcePixels, |
|||
Span<Abgr32> destinationPixels) |
|||
{ |
|||
Guard.NotNull(configuration, nameof(configuration)); |
|||
Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); |
|||
|
|||
ReadOnlySpan<byte> source = MemoryMarshal.Cast<Rgb24, byte>(sourcePixels); |
|||
Span<byte> dest = MemoryMarshal.Cast<Abgr32, byte>(destinationPixels); |
|||
PixelConverter.FromRgb24.ToAbgr32(source, dest); |
|||
} |
|||
/// <inheritdoc />
|
|||
public override void ToBgr24( |
|||
Configuration configuration, |
|||
ReadOnlySpan<Abgr32> sourcePixels, |
|||
Span<Bgr24> destinationPixels) |
|||
{ |
|||
Guard.NotNull(configuration, nameof(configuration)); |
|||
Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); |
|||
|
|||
ReadOnlySpan<byte> source = MemoryMarshal.Cast<Abgr32, byte>(sourcePixels); |
|||
Span<byte> dest = MemoryMarshal.Cast<Bgr24, byte>(destinationPixels); |
|||
PixelConverter.FromAbgr32.ToBgr24(source, dest); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override void FromBgr24( |
|||
Configuration configuration, |
|||
ReadOnlySpan<Bgr24> sourcePixels, |
|||
Span<Abgr32> destinationPixels) |
|||
{ |
|||
Guard.NotNull(configuration, nameof(configuration)); |
|||
Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); |
|||
|
|||
ReadOnlySpan<byte> source = MemoryMarshal.Cast<Bgr24, byte>(sourcePixels); |
|||
Span<byte> dest = MemoryMarshal.Cast<Abgr32, byte>(destinationPixels); |
|||
PixelConverter.FromBgr24.ToAbgr32(source, dest); |
|||
} |
|||
/// <inheritdoc />
|
|||
public override void ToL8( |
|||
Configuration configuration, |
|||
ReadOnlySpan<Abgr32> sourcePixels, |
|||
Span<L8> destinationPixels) |
|||
{ |
|||
Guard.NotNull(configuration, nameof(configuration)); |
|||
Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); |
|||
|
|||
ref Abgr32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); |
|||
ref L8 destRef = ref MemoryMarshal.GetReference(destinationPixels); |
|||
|
|||
for (nint i = 0; i < sourcePixels.Length; i++) |
|||
{ |
|||
ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, i); |
|||
ref L8 dp = ref Unsafe.Add(ref destRef, i); |
|||
|
|||
dp.FromAbgr32(sp); |
|||
} |
|||
} |
|||
/// <inheritdoc />
|
|||
public override void ToL16( |
|||
Configuration configuration, |
|||
ReadOnlySpan<Abgr32> sourcePixels, |
|||
Span<L16> destinationPixels) |
|||
{ |
|||
Guard.NotNull(configuration, nameof(configuration)); |
|||
Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); |
|||
|
|||
ref Abgr32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); |
|||
ref L16 destRef = ref MemoryMarshal.GetReference(destinationPixels); |
|||
|
|||
for (nint i = 0; i < sourcePixels.Length; i++) |
|||
{ |
|||
ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, i); |
|||
ref L16 dp = ref Unsafe.Add(ref destRef, i); |
|||
|
|||
dp.FromAbgr32(sp); |
|||
} |
|||
} |
|||
/// <inheritdoc />
|
|||
public override void ToLa16( |
|||
Configuration configuration, |
|||
ReadOnlySpan<Abgr32> sourcePixels, |
|||
Span<La16> destinationPixels) |
|||
{ |
|||
Guard.NotNull(configuration, nameof(configuration)); |
|||
Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); |
|||
|
|||
ref Abgr32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); |
|||
ref La16 destRef = ref MemoryMarshal.GetReference(destinationPixels); |
|||
|
|||
for (nint i = 0; i < sourcePixels.Length; i++) |
|||
{ |
|||
ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, i); |
|||
ref La16 dp = ref Unsafe.Add(ref destRef, i); |
|||
|
|||
dp.FromAbgr32(sp); |
|||
} |
|||
} |
|||
/// <inheritdoc />
|
|||
public override void ToLa32( |
|||
Configuration configuration, |
|||
ReadOnlySpan<Abgr32> sourcePixels, |
|||
Span<La32> destinationPixels) |
|||
{ |
|||
Guard.NotNull(configuration, nameof(configuration)); |
|||
Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); |
|||
|
|||
ref Abgr32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); |
|||
ref La32 destRef = ref MemoryMarshal.GetReference(destinationPixels); |
|||
|
|||
for (nint i = 0; i < sourcePixels.Length; i++) |
|||
{ |
|||
ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, i); |
|||
ref La32 dp = ref Unsafe.Add(ref destRef, i); |
|||
|
|||
dp.FromAbgr32(sp); |
|||
} |
|||
} |
|||
/// <inheritdoc />
|
|||
public override void ToRgb48( |
|||
Configuration configuration, |
|||
ReadOnlySpan<Abgr32> sourcePixels, |
|||
Span<Rgb48> destinationPixels) |
|||
{ |
|||
Guard.NotNull(configuration, nameof(configuration)); |
|||
Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); |
|||
|
|||
ref Abgr32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); |
|||
ref Rgb48 destRef = ref MemoryMarshal.GetReference(destinationPixels); |
|||
|
|||
for (nint i = 0; i < sourcePixels.Length; i++) |
|||
{ |
|||
ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, i); |
|||
ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); |
|||
|
|||
dp.FromAbgr32(sp); |
|||
} |
|||
} |
|||
/// <inheritdoc />
|
|||
public override void ToRgba64( |
|||
Configuration configuration, |
|||
ReadOnlySpan<Abgr32> sourcePixels, |
|||
Span<Rgba64> destinationPixels) |
|||
{ |
|||
Guard.NotNull(configuration, nameof(configuration)); |
|||
Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); |
|||
|
|||
ref Abgr32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); |
|||
ref Rgba64 destRef = ref MemoryMarshal.GetReference(destinationPixels); |
|||
|
|||
for (nint i = 0; i < sourcePixels.Length; i++) |
|||
{ |
|||
ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, i); |
|||
ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); |
|||
|
|||
dp.FromAbgr32(sp); |
|||
} |
|||
} |
|||
/// <inheritdoc />
|
|||
public override void ToBgra5551( |
|||
Configuration configuration, |
|||
ReadOnlySpan<Abgr32> sourcePixels, |
|||
Span<Bgra5551> destinationPixels) |
|||
{ |
|||
Guard.NotNull(configuration, nameof(configuration)); |
|||
Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); |
|||
|
|||
ref Abgr32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); |
|||
ref Bgra5551 destRef = ref MemoryMarshal.GetReference(destinationPixels); |
|||
|
|||
for (nint i = 0; i < sourcePixels.Length; i++) |
|||
{ |
|||
ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, i); |
|||
ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i); |
|||
|
|||
dp.FromAbgr32(sp); |
|||
} |
|||
} |
|||
/// <inheritdoc />
|
|||
public override void From<TSourcePixel>( |
|||
Configuration configuration, |
|||
ReadOnlySpan<TSourcePixel> sourcePixels, |
|||
Span<Abgr32> destinationPixels) |
|||
{ |
|||
PixelOperations<TSourcePixel>.Instance.ToAbgr32(configuration, sourcePixels, destinationPixels.Slice(0, sourcePixels.Length)); |
|||
} |
|||
|
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,18 @@ |
|||
<#@include file="_Common.ttinclude" #> |
|||
<#@ output extension=".cs" #> |
|||
namespace SixLabors.ImageSharp.PixelFormats |
|||
{ |
|||
/// <content> |
|||
/// Provides optimized overrides for bulk operations. |
|||
/// </content> |
|||
public partial struct Abgr32 |
|||
{ |
|||
/// <summary> |
|||
/// Provides optimized overrides for bulk operations. |
|||
/// </summary> |
|||
internal partial class PixelOperations : PixelOperations<Abgr32> |
|||
{ |
|||
<# GenerateAllDefaultConversionMethods("Abgr32"); #> |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,46 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System.Runtime.CompilerServices; |
|||
using BenchmarkDotNet.Attributes; |
|||
using SixLabors.ImageSharp.Memory; |
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
|
|||
namespace SixLabors.ImageSharp.Benchmarks.General |
|||
{ |
|||
public class Buffer2D_DangerousGetRowSpan |
|||
{ |
|||
private const int Height = 1024; |
|||
|
|||
[Params(0.5, 2.0, 10.0)] public double SizeMegaBytes { get; set; } |
|||
|
|||
private Buffer2D<Rgba32> buffer; |
|||
|
|||
[GlobalSetup] |
|||
public unsafe void Setup() |
|||
{ |
|||
int totalElements = (int)(1024 * 1024 * this.SizeMegaBytes) / sizeof(Rgba32); |
|||
|
|||
int width = totalElements / Height; |
|||
MemoryAllocator allocator = Configuration.Default.MemoryAllocator; |
|||
this.buffer = allocator.Allocate2D<Rgba32>(width, Height); |
|||
} |
|||
|
|||
[GlobalCleanup] |
|||
public void Cleanup() => this.buffer.Dispose(); |
|||
|
|||
[Benchmark] |
|||
public int DangerousGetRowSpan() => |
|||
this.buffer.DangerousGetRowSpan(1).Length + |
|||
this.buffer.DangerousGetRowSpan(Height - 1).Length; |
|||
|
|||
// BenchmarkDotNet=v0.13.0, OS=Windows 10.0.19044
|
|||
// Intel Core i9-10900X CPU 3.70GHz, 1 CPU, 20 logical and 10 physical cores
|
|||
//
|
|||
// | Method | SizeMegaBytes | Mean | Error | StdDev |
|
|||
// |-------------------- |-------------- |----------:|----------:|----------:|
|
|||
// | DangerousGetRowSpan | 0.5 | 7.498 ns | 0.1784 ns | 0.3394 ns |
|
|||
// | DangerousGetRowSpan | 2 | 6.542 ns | 0.1565 ns | 0.3659 ns |
|
|||
// | DangerousGetRowSpan | 10 | 38.556 ns | 0.6604 ns | 0.8587 ns |
|
|||
} |
|||
} |
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue