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.
|
// Copyright (c) Six Labors.
|
||||
// Licensed under the Apache License, Version 2.0.
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
|
||||
using System; |
|
||||
using System.Collections.Generic; |
using System.Collections.Generic; |
||||
using System.IO; |
using System.IO; |
||||
using SixLabors.ImageSharp.Formats.Tiff.Constants; |
using SixLabors.ImageSharp.Formats.Tiff.Constants; |
||||
|
using SixLabors.ImageSharp.Memory; |
||||
using SixLabors.ImageSharp.Metadata.Profiles.Exif; |
using SixLabors.ImageSharp.Metadata.Profiles.Exif; |
||||
|
|
||||
namespace SixLabors.ImageSharp.Formats.Tiff |
namespace SixLabors.ImageSharp.Formats.Tiff |
||||
{ |
{ |
||||
internal class EntryReader : BaseExifReader |
internal class EntryReader : BaseExifReader |
||||
{ |
{ |
||||
private readonly uint startOffset; |
public EntryReader(Stream stream, ByteOrder byteOrder, MemoryAllocator allocator) |
||||
|
: base(stream, allocator) => |
||||
private readonly SortedList<uint, Action> lazyLoaders; |
|
||||
|
|
||||
public EntryReader(Stream stream, ByteOrder byteOrder, uint ifdOffset, SortedList<uint, Action> lazyLoaders) |
|
||||
: base(stream) |
|
||||
{ |
|
||||
this.IsBigEndian = byteOrder == ByteOrder.BigEndian; |
this.IsBigEndian = byteOrder == ByteOrder.BigEndian; |
||||
this.startOffset = ifdOffset; |
|
||||
this.lazyLoaders = lazyLoaders; |
|
||||
} |
|
||||
|
|
||||
public List<IExifValue> Values { get; } = new(); |
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); |
if (!isBigTiff) |
||||
this.NextIfdOffset = this.ReadUInt32(); |
{ |
||||
|
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) => |
public void ReadBigValues() => this.ReadBigValues(this.Values); |
||||
this.lazyLoaders.Add(offset, reader); |
|
||||
} |
} |
||||
|
|
||||
internal class HeaderReader : BaseExifReader |
internal class HeaderReader : BaseExifReader |
||||
{ |
{ |
||||
public HeaderReader(Stream stream, ByteOrder byteOrder) |
public HeaderReader(Stream stream, ByteOrder byteOrder) |
||||
: base(stream) => |
: base(stream, null) => |
||||
this.IsBigEndian = byteOrder == ByteOrder.BigEndian; |
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(); |
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(); |
ushort bytesize = this.ReadUInt16(); |
||||
return this.FirstIfdOffset; |
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