From fdfb547936fdcb55ca71707699e67e8d7b3d0301 Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Sat, 11 Sep 2021 22:14:11 +0300 Subject: [PATCH 001/121] Support long8 types for exif reader --- src/ImageSharp/Common/Helpers/Numerics.cs | 32 ++++ .../Metadata/Profiles/Exif/ExifDataType.cs | 17 +- .../Metadata/Profiles/Exif/ExifDataTypes.cs | 5 +- .../Metadata/Profiles/Exif/ExifReader.cs | 147 +++++++++++++++++- .../Profiles/Exif/Values/ExifLong8.cs | 53 +++++++ .../Profiles/Exif/Values/ExifLong8Array.cs | 27 ++++ .../Profiles/Exif/Values/ExifNumber.cs | 17 ++ .../Profiles/Exif/Values/ExifNumberArray.cs | 37 +++++ .../Profiles/Exif/Values/ExifSignedLong8.cs | 26 ++++ .../Exif/Values/ExifSignedLong8Array.cs | 22 +++ .../Profiles/Exif/Values/ExifValues.cs | 4 +- src/ImageSharp/Primitives/Number.cs | 75 +++++++-- 12 files changed, 442 insertions(+), 20 deletions(-) create mode 100644 src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong8.cs create mode 100644 src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong8Array.cs create mode 100644 src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedLong8.cs create mode 100644 src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedLong8Array.cs diff --git a/src/ImageSharp/Common/Helpers/Numerics.cs b/src/ImageSharp/Common/Helpers/Numerics.cs index ba5c588ca..885443e86 100644 --- a/src/ImageSharp/Common/Helpers/Numerics.cs +++ b/src/ImageSharp/Common/Helpers/Numerics.cs @@ -226,6 +226,38 @@ namespace SixLabors.ImageSharp return value; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ulong Clamp(ulong value, ulong min, ulong max) + { + if (value > max) + { + return max; + } + + if (value < min) + { + return min; + } + + return value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static long Clamp(long value, long min, long max) + { + if (value > max) + { + return max; + } + + if (value < min) + { + return min; + } + + return value; + } + /// /// Returns the value clamped to the inclusive range of min and max. /// diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifDataType.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifDataType.cs index 733eb4a79..0185afb50 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/ExifDataType.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifDataType.cs @@ -80,6 +80,21 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif /// /// Reference to an IFD (32-bit (4-byte) unsigned integer). /// - Ifd = 13 + Ifd = 13, + + /// + /// A 64-bit (8-byte) unsigned integer. + /// + Long8 = 16, + + /// + /// A 64-bit (8-byte) signed integer (2's complement notation). + /// + SignedLong8 = 17, + + /// + /// Reference to an IFD (64-bit (8-byte) unsigned integer). + /// + Ifd8 = 18, } } diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifDataTypes.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifDataTypes.cs index 4f75999bb..ee30c6b08 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/ExifDataTypes.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifDataTypes.cs @@ -32,10 +32,13 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif case ExifDataType.Long: case ExifDataType.SignedLong: case ExifDataType.SingleFloat: + case ExifDataType.Ifd: return 4; case ExifDataType.DoubleFloat: case ExifDataType.Rational: - case ExifDataType.SignedRational: + case ExifDataType.Long8: + case ExifDataType.SignedLong8: + case ExifDataType.Ifd8: return 8; default: throw new NotSupportedException(dataType.ToString()); diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs index 6e671b3ec..5c26fde7b 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs @@ -55,7 +55,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif return values; } - protected override void RegisterExtLoader(uint offset, Action loader) => this.loaders.Add(loader); + protected override void RegisterExtLoader(ulong offset, Action loader) => this.loaders.Add(loader); private void GetThumbnail(uint offset) { @@ -87,6 +87,8 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif internal abstract class BaseExifReader { private readonly byte[] offsetBuffer = new byte[4]; + private readonly byte[] offsetBuffer8 = new byte[8]; + private readonly byte[] buf8 = new byte[8]; private readonly byte[] buf4 = new byte[4]; private readonly byte[] buf2 = new byte[2]; @@ -119,7 +121,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif public bool IsBigEndian { get; protected set; } - protected abstract void RegisterExtLoader(uint offset, Action loader); + protected abstract void RegisterExtLoader(ulong offset, Action loader); /// /// Reads the values to the values collection. @@ -155,6 +157,35 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif } } + protected void ReadValues64(List values, ulong offset) + { + if (offset > (ulong)this.data.Length) + { + return; + } + + this.Seek(offset); + ulong count = this.ReadUInt64(); + + for (ulong i = 0; i < count; i++) + { + this.ReadValue64(values); + } + } + + protected void ReadSubIfd64(List values) + { + if (this.exifOffset != 0) + { + this.ReadValues64(values, this.exifOffset); + } + + if (this.gpsOffset != 0) + { + this.ReadValues64(values, this.gpsOffset); + } + } + private static TDataType[] ToArray(ExifDataType dataType, ReadOnlySpan data, ConverterMethod converter) { int dataTypeSize = (int)ExifDataTypes.GetSize(dataType); @@ -186,7 +217,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif return Encoding.UTF8.GetString(buffer); } - private object ConvertValue(ExifDataType dataType, ReadOnlySpan buffer, uint numberOfComponents) + private object ConvertValue(ExifDataType dataType, ReadOnlySpan buffer, ulong numberOfComponents) { if (buffer.Length == 0) { @@ -269,6 +300,20 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif } return ToArray(dataType, buffer, this.ConvertToSingle); + case ExifDataType.Long8: + if (numberOfComponents == 1) + { + return this.ConvertToUInt64(buffer); + } + + return ToArray(dataType, buffer, this.ConvertToUInt64); + case ExifDataType.SignedLong8: + if (numberOfComponents == 1) + { + return this.ConvertToInt64(buffer); + } + + return ToArray(dataType, buffer, this.ConvertToUInt64); case ExifDataType.Undefined: if (numberOfComponents == 1) { @@ -349,6 +394,69 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif } } + private void ReadValue64(List values) + { + if ((this.data.Length - this.data.Position) < 20) + { + return; + } + + var tag = (ExifTagValue)this.ReadUInt16(); + ExifDataType dataType = EnumUtils.Parse(this.ReadUInt16(), ExifDataType.Unknown); + + ulong numberOfComponents = this.ReadUInt64(); + + this.TryReadSpan(this.offsetBuffer8); + + if (dataType == ExifDataType.Unknown) + { + return; + } + + if (dataType == ExifDataType.Undefined && numberOfComponents == 0) + { + numberOfComponents = 8; + } + + // The StripOffsets, StripByteCounts, TileOffsets, and TileByteCounts tags are allowed to have the datatype TIFF_LONG8 in BigTIFF. + // Old datatypes TIFF_LONG, and TIFF_SHORT where allowed in the TIFF 6.0 specification, are still valid in BigTIFF, too. + // https://www.awaresystems.be/imaging/tiff/bigtiff.html + ExifValue exifValue = exifValue = ExifValues.Create(tag) ?? ExifValues.Create(tag, dataType, numberOfComponents); + + if (exifValue is null) + { + this.AddInvalidTag(new UnkownExifTag(tag)); + return; + } + + ulong size = numberOfComponents * ExifDataTypes.GetSize(dataType); + if (size > 8) + { + ulong newOffset = this.ConvertToUInt64(this.offsetBuffer8); + if (newOffset > ulong.MaxValue || (newOffset + size) > (ulong)this.data.Length) + { + this.AddInvalidTag(new UnkownExifTag(tag)); + return; + } + + this.RegisterExtLoader(newOffset, () => + { + byte[] dataBuffer = new byte[size]; + this.Seek(newOffset); + if (this.TryReadSpan(dataBuffer)) + { + object value = this.ConvertValue(dataType, dataBuffer, numberOfComponents); + this.Add(values, exifValue, value); + } + }); + } + else + { + object value = this.ConvertValue(dataType, ((Span)this.offsetBuffer8).Slice(0, (int)size), numberOfComponents); + this.Add(values, exifValue, value); + } + } + private void Add(IList values, IExifValue exif, object value) { if (!exif.TrySetValue(value)) @@ -383,8 +491,8 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif private void AddInvalidTag(ExifTag tag) => (this.invalidTags ??= new List()).Add(tag); - private void Seek(long pos) - => this.data.Seek(pos, SeekOrigin.Begin); + private void Seek(ulong pos) + => this.data.Seek((long)pos, SeekOrigin.Begin); private bool TryReadSpan(Span span) { @@ -398,6 +506,11 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif return read == length; } + protected ulong ReadUInt64() => + this.TryReadSpan(this.buf8) + ? this.ConvertToUInt64(this.buf8) + : default; + // Known as Long in Exif Specification. protected uint ReadUInt32() => this.TryReadSpan(this.buf4) @@ -408,6 +521,30 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif ? this.ConvertToShort(this.buf2) : default; + private long ConvertToInt64(ReadOnlySpan buffer) + { + if (buffer.Length < 8) + { + return default; + } + + return this.IsBigEndian + ? BinaryPrimitives.ReadInt64BigEndian(buffer) + : BinaryPrimitives.ReadInt64LittleEndian(buffer); + } + + private ulong ConvertToUInt64(ReadOnlySpan buffer) + { + if (buffer.Length < 8) + { + return default; + } + + return this.IsBigEndian + ? BinaryPrimitives.ReadUInt64BigEndian(buffer) + : BinaryPrimitives.ReadUInt64LittleEndian(buffer); + } + private double ConvertToDouble(ReadOnlySpan buffer) { if (buffer.Length < 8) diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong8.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong8.cs new file mode 100644 index 000000000..47da962f3 --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong8.cs @@ -0,0 +1,53 @@ +// 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 + { + public ExifLong8(ExifTag 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 long intValue: + if (intValue >= 0) + { + this.Value = (ulong)intValue; + return true; + } + + return false; + default: + return false; + } + } + + public override IExifValue DeepClone() => new ExifLong8(this); + } +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong8Array.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong8Array.cs new file mode 100644 index 000000000..3cf59adac --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong8Array.cs @@ -0,0 +1,27 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.Metadata.Profiles.Exif +{ + internal sealed class ExifLong8Array : ExifArrayValue + { + public ExifLong8Array(ExifTag tag) + : base(tag) + { + } + + public ExifLong8Array(ExifTagValue tag) + : base(tag) + { + } + + private ExifLong8Array(ExifLong8Array value) + : base(value) + { + } + + public override ExifDataType DataType => ExifDataType.Long8; + + public override IExifValue DeepClone() => new ExifLong8Array(this); + } +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumber.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumber.cs index 9e206b23d..d16de4d22 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumber.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumber.cs @@ -21,6 +21,11 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif { get { + if (this.Value > uint.MaxValue) + { + return ExifDataType.Long8; + } + if (this.Value > ushort.MaxValue) { return ExifDataType.Long; @@ -41,6 +46,18 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif switch (value) { + case long longValue: + if (longValue >= 0) + { + this.Value = (ulong)longValue; + return true; + } + + return false; + case ulong ulongValue: + this.Value = ulongValue; + + return true; case int intValue: if (intValue >= uint.MinValue) { diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumberArray.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumberArray.cs index 2d3a93aed..15b29dcec 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumberArray.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumberArray.cs @@ -26,6 +26,11 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif for (int i = 0; i < this.Value.Length; i++) { + if (this.Value[i] > uint.MaxValue) + { + return ExifDataType.Long8; + } + if (this.Value[i] > ushort.MaxValue) { return ExifDataType.Long; @@ -45,6 +50,10 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif switch (value) { + case long val: + return this.SetSingle(val); + case ulong val: + return this.SetSingle(val); case int val: return this.SetSingle(val); case uint val: @@ -53,6 +62,10 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif return this.SetSingle(val); case ushort val: return this.SetSingle(val); + case long[] array: + return this.SetArray(array); + case ulong[] array: + return this.SetArray(array); case int[] array: return this.SetArray(array); case uint[] array: @@ -74,6 +87,30 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif return true; } + private bool SetArray(long[] values) + { + var numbers = new Number[values.Length]; + for (int i = 0; i < values.Length; i++) + { + numbers[i] = values[i]; + } + + this.Value = numbers; + return true; + } + + private bool SetArray(ulong[] values) + { + var numbers = new Number[values.Length]; + for (int i = 0; i < values.Length; i++) + { + numbers[i] = values[i]; + } + + this.Value = numbers; + return true; + } + private bool SetArray(int[] values) { var numbers = new Number[values.Length]; diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedLong8.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedLong8.cs new file mode 100644 index 000000000..8362dcf2c --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedLong8.cs @@ -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 + { + 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); + } +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedLong8Array.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedLong8Array.cs new file mode 100644 index 000000000..34ce20c8f --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedLong8Array.cs @@ -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 + { + 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); + } +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifValues.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifValues.cs index af1eee2dc..7e5b35f49 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifValues.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifValues.cs @@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif public static ExifValue Create(ExifTag tag) => (ExifValue)CreateValue((ExifTagValue)(ushort)tag); - public static ExifValue Create(ExifTagValue tag, ExifDataType dataType, uint numberOfComponents) => Create(tag, dataType, numberOfComponents != 1); + public static ExifValue Create(ExifTagValue tag, ExifDataType dataType, ulong numberOfComponents) => Create(tag, dataType, numberOfComponents != 1); public static ExifValue Create(ExifTagValue tag, ExifDataType dataType, bool isArray) { @@ -19,10 +19,12 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif case ExifDataType.DoubleFloat: return isArray ? (ExifValue)new ExifDoubleArray(tag) : new ExifDouble(tag); case ExifDataType.SingleFloat: return isArray ? (ExifValue)new ExifFloatArray(tag) : new ExifFloat(tag); case ExifDataType.Long: return isArray ? (ExifValue)new ExifLongArray(tag) : new ExifLong(tag); + case ExifDataType.Long8: return isArray ? (ExifValue)new ExifLong8Array(tag) : new ExifLong8(tag); case ExifDataType.Rational: return isArray ? (ExifValue)new ExifRationalArray(tag) : new ExifRational(tag); case ExifDataType.Short: return isArray ? (ExifValue)new ExifShortArray(tag) : new ExifShort(tag); case ExifDataType.SignedByte: return isArray ? (ExifValue)new ExifSignedByteArray(tag) : new ExifSignedByte(tag); case ExifDataType.SignedLong: return isArray ? (ExifValue)new ExifSignedLongArray(tag) : new ExifSignedLong(tag); + case ExifDataType.SignedLong8: return isArray ? (ExifValue)new ExifSignedLong8Array(tag) : new ExifSignedLong8(tag); case ExifDataType.SignedRational: return isArray ? (ExifValue)new ExifSignedRationalArray(tag) : new ExifSignedRational(tag); case ExifDataType.SignedShort: return isArray ? (ExifValue)new ExifSignedShortArray(tag) : new ExifSignedShort(tag); case ExifDataType.Ascii: return new ExifString(tag); diff --git a/src/ImageSharp/Primitives/Number.cs b/src/ImageSharp/Primitives/Number.cs index e33d2344a..690b72d79 100644 --- a/src/ImageSharp/Primitives/Number.cs +++ b/src/ImageSharp/Primitives/Number.cs @@ -14,19 +14,19 @@ namespace SixLabors.ImageSharp public struct Number : IEquatable, IComparable { [FieldOffset(0)] - private readonly int signedValue; + private readonly long signedValue; [FieldOffset(0)] - private readonly uint unsignedValue; + private readonly ulong unsignedValue; - [FieldOffset(4)] + [FieldOffset(8)] private readonly bool isSigned; /// /// Initializes a new instance of the struct. /// /// The value of the number. - public Number(int value) + public Number(long value) : this() { this.signedValue = value; @@ -37,30 +37,70 @@ namespace SixLabors.ImageSharp /// Initializes a new instance of the struct. /// /// The value of the number. - public Number(uint value) + public Number(ulong value) : this() { this.unsignedValue = value; this.isSigned = false; } + /// + /// Converts the specified to an instance of this type. + /// + /// The value. + public static implicit operator Number(long value) => new Number(value); + + /// + /// Converts the specified to an instance of this type. + /// + /// The value. + public static implicit operator Number(ulong value) => new Number(value); + /// /// Converts the specified to an instance of this type. /// /// The value. - public static implicit operator Number(int value) => new Number(value); + public static implicit operator Number(int value) => new Number((long)value); /// /// Converts the specified to an instance of this type. /// /// The value. - public static implicit operator Number(uint value) => new Number(value); + public static implicit operator Number(uint value) => new Number((ulong)value); + + /// + /// Converts the specified to an instance of this type. + /// + /// The value. + public static implicit operator Number(short value) => new Number((long)value); /// /// Converts the specified to an instance of this type. /// /// The value. - public static implicit operator Number(ushort value) => new Number((uint)value); + public static implicit operator Number(ushort value) => new Number((ulong)value); + + /// + /// Converts the specified to an instance of this type. + /// + /// The to convert. + public static explicit operator long(Number number) + { + return number.isSigned + ? number.signedValue + : (long)Numerics.Clamp(number.unsignedValue, 0, long.MaxValue); + } + + /// + /// Converts the specified to an instance of this type. + /// + /// The to convert. + public static explicit operator ulong(Number number) + { + return number.isSigned + ? (ulong)Numerics.Clamp(number.signedValue, 0, long.MaxValue) + : number.unsignedValue; + } /// /// Converts the specified to a . @@ -69,8 +109,8 @@ namespace SixLabors.ImageSharp public static explicit operator int(Number number) { return number.isSigned - ? number.signedValue - : (int)Numerics.Clamp(number.unsignedValue, 0, int.MaxValue); + ? (int)Numerics.Clamp(number.signedValue, int.MinValue, int.MaxValue) + : (int)Numerics.Clamp(number.unsignedValue, 0, (uint)int.MaxValue); } /// @@ -80,8 +120,19 @@ namespace SixLabors.ImageSharp public static explicit operator uint(Number number) { return number.isSigned - ? (uint)Numerics.Clamp(number.signedValue, 0, int.MaxValue) - : number.unsignedValue; + ? (uint)Numerics.Clamp(number.signedValue, uint.MinValue, uint.MaxValue) + : (uint)Numerics.Clamp(number.unsignedValue, uint.MinValue, uint.MaxValue); + } + + /// + /// Converts the specified to a . + /// + /// The to convert. + public static explicit operator short(Number number) + { + return number.isSigned + ? (short)Numerics.Clamp(number.signedValue, short.MinValue, short.MaxValue) + : (short)Numerics.Clamp(number.unsignedValue, 0, (ushort)short.MaxValue); } /// From 4b3ae005a6eca9783a8b238bbb72b6192d371b4c Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Sat, 11 Sep 2021 22:26:32 +0300 Subject: [PATCH 002/121] Implement support BigTiff format decoding --- .../Tiff/Compression/TiffBaseDecompressor.cs | 10 ++-- .../Formats/Tiff/Constants/TiffConstants.cs | 10 ++++ .../Formats/Tiff/Ifd/DirectoryReader.cs | 24 ++++---- .../Formats/Tiff/Ifd/EntryReader.cs | 58 +++++++++++++------ .../Formats/Tiff/TiffDecoderCore.cs | 5 ++ .../Formats/Tiff/TiffDecoderOptionsParser.cs | 13 +++-- 6 files changed, 81 insertions(+), 39 deletions(-) diff --git a/src/ImageSharp/Formats/Tiff/Compression/TiffBaseDecompressor.cs b/src/ImageSharp/Formats/Tiff/Compression/TiffBaseDecompressor.cs index 28459d0c5..f1faa6c67 100644 --- a/src/ImageSharp/Formats/Tiff/Compression/TiffBaseDecompressor.cs +++ b/src/ImageSharp/Formats/Tiff/Compression/TiffBaseDecompressor.cs @@ -35,17 +35,17 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression /// The number of bytes to read from the input stream. /// The height of the strip. /// The output buffer for uncompressed data. - public void Decompress(BufferedReadStream stream, uint stripOffset, uint stripByteCount, int stripHeight, Span buffer) + public void Decompress(BufferedReadStream stream, ulong stripOffset, ulong stripByteCount, int stripHeight, Span buffer) { - if (stripByteCount > int.MaxValue) + if (stripOffset > long.MaxValue || stripByteCount > long.MaxValue) { - TiffThrowHelper.ThrowImageFormatException("The StripByteCount value is too big."); + TiffThrowHelper.ThrowImageFormatException("The StripOffset or StripByteCount value is too big."); } - stream.Seek(stripOffset, SeekOrigin.Begin); + stream.Seek((long)stripOffset, SeekOrigin.Begin); this.Decompress(stream, (int)stripByteCount, stripHeight, buffer); - if (stripOffset + stripByteCount < stream.Position) + if ((long)stripOffset + (long)stripByteCount < stream.Position) { TiffThrowHelper.ThrowImageFormatException("Out of range when reading a strip."); } diff --git a/src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs b/src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs index b54545141..b5548c707 100644 --- a/src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs +++ b/src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs @@ -35,6 +35,16 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Constants /// public const ushort HeaderMagicNumber = 42; + /// + /// The big tiff header magic number + /// + public const ushort BigTiffHeaderMagicNumber = 43; + + /// + /// The big tiff bytesize of offsets value. + /// + public const ushort BigTiffBytesize = 8; + /// /// RowsPerStrip default value, which is effectively infinity. /// diff --git a/src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs b/src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs index 8b2c6bd3a..bd673cf3a 100644 --- a/src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs +++ b/src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs @@ -16,11 +16,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff { private readonly Stream stream; - private uint nextIfdOffset; + private ulong nextIfdOffset; // used for sequential read big values (actual for multiframe big files) // todo: different tags can link to the same data (stream offset) - investigate - private readonly SortedList lazyLoaders = new SortedList(new DuplicateKeyComparer()); + private readonly SortedList lazyLoaders = new SortedList(new DuplicateKeyComparer()); public DirectoryReader(Stream stream) => this.stream = stream; @@ -36,13 +36,17 @@ namespace SixLabors.ImageSharp.Formats.Tiff public IEnumerable Read() { this.ByteOrder = ReadByteOrder(this.stream); - this.nextIfdOffset = new HeaderReader(this.stream, this.ByteOrder).ReadFileHeader(); - return this.ReadIfds(); + var headerReader = new HeaderReader(this.stream, this.ByteOrder); + headerReader.ReadFileHeader(); + + this.nextIfdOffset = headerReader.FirstIfdOffset; + + return this.ReadIfds(headerReader.IsBigTiff); } private static ByteOrder ReadByteOrder(Stream stream) { - var headerBytes = new byte[2]; + byte[] headerBytes = new byte[2]; stream.Read(headerBytes, 0, 2); if (headerBytes[0] == TiffConstants.ByteOrderLittleEndian && headerBytes[1] == TiffConstants.ByteOrderLittleEndian) { @@ -56,13 +60,13 @@ namespace SixLabors.ImageSharp.Formats.Tiff throw TiffThrowHelper.ThrowInvalidHeader(); } - private IEnumerable ReadIfds() + private IEnumerable ReadIfds(bool isBigTiff) { var readers = new List(); - while (this.nextIfdOffset != 0 && this.nextIfdOffset < this.stream.Length) + while (this.nextIfdOffset != 0 && this.nextIfdOffset < (ulong)this.stream.Length) { - var reader = new EntryReader(this.stream, this.ByteOrder, this.nextIfdOffset, this.lazyLoaders); - reader.ReadTags(); + var reader = new EntryReader(this.stream, this.ByteOrder, this.lazyLoaders); + reader.ReadTags(isBigTiff, this.nextIfdOffset); this.nextIfdOffset = reader.NextIfdOffset; @@ -75,7 +79,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff loader(); } - var list = new List(); + var list = new List(readers.Count); foreach (EntryReader reader in readers) { var profile = new ExifProfile(reader.Values, reader.InvalidTags); diff --git a/src/ImageSharp/Formats/Tiff/Ifd/EntryReader.cs b/src/ImageSharp/Formats/Tiff/Ifd/EntryReader.cs index 123a64cc1..7884242ef 100644 --- a/src/ImageSharp/Formats/Tiff/Ifd/EntryReader.cs +++ b/src/ImageSharp/Formats/Tiff/Ifd/EntryReader.cs @@ -12,31 +12,38 @@ namespace SixLabors.ImageSharp.Formats.Tiff { internal class EntryReader : BaseExifReader { - private readonly uint startOffset; + private readonly SortedList lazyLoaders; - private readonly SortedList lazyLoaders; - - public EntryReader(Stream stream, ByteOrder byteOrder, uint ifdOffset, SortedList lazyLoaders) + public EntryReader(Stream stream, ByteOrder byteOrder, SortedList lazyLoaders) : base(stream) { this.IsBigEndian = byteOrder == ByteOrder.BigEndian; - this.startOffset = ifdOffset; this.lazyLoaders = lazyLoaders; } public List Values { get; } = new List(); - 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) => + protected override void RegisterExtLoader(ulong offset, Action reader) => this.lazyLoaders.Add(offset, reader); } @@ -46,20 +53,35 @@ namespace SixLabors.ImageSharp.Formats.Tiff : base(stream) => this.IsBigEndian = byteOrder == ByteOrder.BigEndian; - public uint FirstIfdOffset { get; private set; } + public bool IsBigTiff { get; private set; } + + public ulong FirstIfdOffset { get; private set; } - public uint ReadFileHeader() + 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; + + ushort bytesize = this.ReadUInt16(); + ushort reserve = this.ReadUInt16(); + if (bytesize == TiffConstants.BigTiffBytesize && reserve == 0) + { + this.FirstIfdOffset = this.ReadUInt64(); + return; + } } - this.FirstIfdOffset = this.ReadUInt32(); - return this.FirstIfdOffset; + TiffThrowHelper.ThrowInvalidHeader(); } - protected override void RegisterExtLoader(uint offset, Action reader) => throw new NotSupportedException(); + protected override void RegisterExtLoader(ulong offset, Action reader) => throw new NotSupportedException(); } } diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs index 55af87005..922c1f174 100644 --- a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs +++ b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs @@ -432,6 +432,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff TiffThrowHelper.ThrowImageFormatException("The TIFF image frame is missing the ImageWidth"); } + if (((ulong)width.Value) > int.MaxValue) + { + TiffThrowHelper.ThrowImageFormatException("Too big ImageWidth value"); + } + return (int)width.Value; } diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs index a8420fabb..a187d444a 100644 --- a/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs +++ b/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs @@ -24,12 +24,12 @@ namespace SixLabors.ImageSharp.Formats.Tiff /// The IFD entries container to read the image format information for current frame. public static void VerifyAndParse(this TiffDecoderCore options, ExifProfile exifProfile, TiffFrameMetadata frameMetadata) { - if (exifProfile.GetValue(ExifTag.TileOffsets)?.Value != null) + if (exifProfile.GetValueInternal(ExifTag.TileOffsets) is not null || exifProfile.GetValueInternal(ExifTag.TileByteCounts) is not null) { TiffThrowHelper.ThrowNotSupported("Tiled images are not supported."); } - if (exifProfile.GetValue(ExifTag.ExtraSamples)?.Value != null) + if (exifProfile.GetValueInternal(ExifTag.ExtraSamples) is not null) { TiffThrowHelper.ThrowNotSupported("ExtraSamples is not supported."); } @@ -95,12 +95,12 @@ namespace SixLabors.ImageSharp.Formats.Tiff private static void VerifyRequiredFieldsArePresent(ExifProfile exifProfile, TiffFrameMetadata frameMetadata) { - if (exifProfile.GetValue(ExifTag.StripOffsets) == null) + if (exifProfile.GetValueInternal(ExifTag.StripOffsets) is null) { TiffThrowHelper.ThrowImageFormatException("StripOffsets are missing and are required for decoding the TIFF image!"); } - if (exifProfile.GetValue(ExifTag.StripByteCounts) == null) + if (exifProfile.GetValueInternal(ExifTag.StripByteCounts) is null) { TiffThrowHelper.ThrowImageFormatException("StripByteCounts are missing and are required for decoding the TIFF image!"); } @@ -384,7 +384,8 @@ namespace SixLabors.ImageSharp.Formats.Tiff private static void ParseCompression(this TiffDecoderCore options, TiffCompression? compression, ExifProfile exifProfile) { - switch (compression) + // Default 1 (No compression) https://www.awaresystems.be/imaging/tiff/tifftags/compression.html + switch (compression ?? TiffCompression.None) { case TiffCompression.None: { @@ -441,7 +442,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff default: { - TiffThrowHelper.ThrowNotSupported($"The specified TIFF compression format {compression} is not supported"); + TiffThrowHelper.ThrowNotSupported($"The specified TIFF compression format '{compression}' is not supported"); break; } } From ae577bba8738a3c497915958de7948768fb63945 Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Sat, 11 Sep 2021 22:27:03 +0300 Subject: [PATCH 003/121] Add BigTiff decoder tests --- .../Formats/Tiff/BigTiffDecoderTests.cs | 35 +++ .../Formats/Tiff/TiffDecoderBaseTester.cs | 32 +++ .../Formats/Tiff/TiffDecoderTests.cs | 22 +- tests/ImageSharp.Tests/TestImages.cs | 15 ++ tests/Images/Input/Tiff/BigTiff/BigTIFF.tif | 3 + .../Images/Input/Tiff/BigTiff/BigTIFFLong.tif | 3 + .../Input/Tiff/BigTiff/BigTIFFLong8.tif | 3 + .../Input/Tiff/BigTiff/BigTIFFLong8Tiles.tif | 3 + .../Input/Tiff/BigTiff/BigTIFFMotorola.tif | 3 + .../BigTiff/BigTIFFMotorolaLongStrips.tif | 3 + .../Input/Tiff/BigTiff/BigTIFFSamples.html | 239 ++++++++++++++++++ .../Input/Tiff/BigTiff/BigTIFFSubIFD4.tif | 3 + .../Input/Tiff/BigTiff/BigTIFFSubIFD8.tif | 3 + tests/Images/Input/Tiff/BigTiff/Classic.tif | 3 + tests/Images/Input/Tiff/BigTiff/readme.md | 3 + 15 files changed, 353 insertions(+), 20 deletions(-) create mode 100644 tests/ImageSharp.Tests/Formats/Tiff/BigTiffDecoderTests.cs create mode 100644 tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderBaseTester.cs create mode 100644 tests/Images/Input/Tiff/BigTiff/BigTIFF.tif create mode 100644 tests/Images/Input/Tiff/BigTiff/BigTIFFLong.tif create mode 100644 tests/Images/Input/Tiff/BigTiff/BigTIFFLong8.tif create mode 100644 tests/Images/Input/Tiff/BigTiff/BigTIFFLong8Tiles.tif create mode 100644 tests/Images/Input/Tiff/BigTiff/BigTIFFMotorola.tif create mode 100644 tests/Images/Input/Tiff/BigTiff/BigTIFFMotorolaLongStrips.tif create mode 100644 tests/Images/Input/Tiff/BigTiff/BigTIFFSamples.html create mode 100644 tests/Images/Input/Tiff/BigTiff/BigTIFFSubIFD4.tif create mode 100644 tests/Images/Input/Tiff/BigTiff/BigTIFFSubIFD8.tif create mode 100644 tests/Images/Input/Tiff/BigTiff/Classic.tif create mode 100644 tests/Images/Input/Tiff/BigTiff/readme.md diff --git a/tests/ImageSharp.Tests/Formats/Tiff/BigTiffDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/BigTiffDecoderTests.cs new file mode 100644 index 000000000..fc507513b --- /dev/null +++ b/tests/ImageSharp.Tests/Formats/Tiff/BigTiffDecoderTests.cs @@ -0,0 +1,35 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +// ReSharper disable InconsistentNaming +using System; +using SixLabors.ImageSharp.PixelFormats; + +using Xunit; + +using static SixLabors.ImageSharp.Tests.TestImages.BigTiff; + +namespace SixLabors.ImageSharp.Tests.Formats.Tiff +{ + [Collection("RunSerial")] + [Trait("Format", "Tiff")] + [Trait("Format", "BigTiff")] + public class BigTiffDecoderTests : TiffDecoderBaseTester + { + [Theory] + [WithFile(BigTIFF, PixelTypes.Rgba32)] + [WithFile(BigTIFFLong, PixelTypes.Rgba32)] + [WithFile(BigTIFFLong8, PixelTypes.Rgba32)] + [WithFile(BigTIFFMotorola, PixelTypes.Rgba32)] + [WithFile(BigTIFFMotorolaLongStrips, PixelTypes.Rgba32)] + [WithFile(BigTIFFSubIFD4, PixelTypes.Rgba32)] + [WithFile(BigTIFFSubIFD8, PixelTypes.Rgba32)] + public void TiffDecoder_CanDecode(TestImageProvider provider) + where TPixel : unmanaged, IPixel => TestTiffDecoder(provider); + + [Theory] + [WithFile(BigTIFFLong8Tiles, PixelTypes.Rgba32)] + public void ThrowsNotSupported(TestImageProvider provider) + where TPixel : unmanaged, IPixel => Assert.Throws(() => provider.GetImage(TiffDecoder)); + } +} diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderBaseTester.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderBaseTester.cs new file mode 100644 index 000000000..ff70eaf8a --- /dev/null +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderBaseTester.cs @@ -0,0 +1,32 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +// ReSharper disable InconsistentNaming +using SixLabors.ImageSharp.Formats; +using SixLabors.ImageSharp.Formats.Tiff; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; +using SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs; + +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Formats.Tiff +{ + public abstract class TiffDecoderBaseTester + { + protected static TiffDecoder TiffDecoder => new TiffDecoder(); + + protected static MagickReferenceDecoder ReferenceDecoder => new MagickReferenceDecoder(); + + protected static void TestTiffDecoder(TestImageProvider provider, IImageDecoder referenceDecoder = null, bool useExactComparer = true, float compareTolerance = 0.001f) + where TPixel : unmanaged, IPixel + { + using Image image = provider.GetImage(TiffDecoder); + image.DebugSave(provider); + image.CompareToOriginal( + provider, + useExactComparer ? ImageComparer.Exact : ImageComparer.Tolerant(compareTolerance), + referenceDecoder ?? ReferenceDecoder); + } + } +} diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs index b64d22991..e49f45932 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs @@ -4,12 +4,9 @@ // ReSharper disable InconsistentNaming using System; using System.IO; -using SixLabors.ImageSharp.Formats; -using SixLabors.ImageSharp.Formats.Tiff; using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; -using SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs; using Xunit; @@ -19,20 +16,16 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff { [Collection("RunSerial")] [Trait("Format", "Tiff")] - public class TiffDecoderTests + public class TiffDecoderTests : TiffDecoderBaseTester { public static readonly string[] MultiframeTestImages = Multiframes; - private static TiffDecoder TiffDecoder => new TiffDecoder(); - - private static MagickReferenceDecoder ReferenceDecoder => new MagickReferenceDecoder(); - [Theory] [WithFile(RgbUncompressedTiled, PixelTypes.Rgba32)] [WithFile(MultiframeDifferentSize, PixelTypes.Rgba32)] [WithFile(MultiframeDifferentVariants, PixelTypes.Rgba32)] public void ThrowsNotSupported(TestImageProvider provider) - where TPixel : unmanaged, IPixel => Assert.Throws(() => provider.GetImage(TiffDecoder)); + where TPixel : unmanaged, IPixel => Assert.Throws(() => provider.GetImage(TiffDecoder)); [Theory] [InlineData(RgbUncompressed, 24, 256, 256, 300, 300, PixelResolutionUnit.PixelsPerInch)] @@ -397,16 +390,5 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff image.DebugSaveMultiFrame(provider); image.CompareToOriginalMultiFrame(provider, ImageComparer.Exact, ReferenceDecoder); } - - private static void TestTiffDecoder(TestImageProvider provider, IImageDecoder referenceDecoder = null, bool useExactComparer = true, float compareTolerance = 0.001f) - where TPixel : unmanaged, IPixel - { - using Image image = provider.GetImage(TiffDecoder); - image.DebugSave(provider); - image.CompareToOriginal( - provider, - useExactComparer ? ImageComparer.Exact : ImageComparer.Tolerant(compareTolerance), - referenceDecoder ?? ReferenceDecoder); - } } } diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index d1a6624af..9df6472a1 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -672,5 +672,20 @@ namespace SixLabors.ImageSharp.Tests public static readonly string[] Metadata = { SampleMetadata }; } + + public static class BigTiff + { + public const string BasePath = "Tiff/BigTiff/"; + + public const string BigTIFF = BasePath + "BigTIFF.tif"; + public const string BigTIFFLong = BasePath + "BigTIFFLong.tif"; + public const string BigTIFFLong8 = BasePath + "BigTIFFLong8.tif"; + public const string BigTIFFLong8Tiles = BasePath + "BigTIFFLong8Tiles.tif"; + public const string BigTIFFMotorola = BasePath + "BigTIFFMotorola.tif"; + public const string BigTIFFMotorolaLongStrips = BasePath + "BigTIFFMotorolaLongStrips.tif"; + + public const string BigTIFFSubIFD4 = BasePath + "BigTIFFSubIFD4.tif"; + public const string BigTIFFSubIFD8 = BasePath + "BigTIFFSubIFD8.tif"; + } } } diff --git a/tests/Images/Input/Tiff/BigTiff/BigTIFF.tif b/tests/Images/Input/Tiff/BigTiff/BigTIFF.tif new file mode 100644 index 000000000..b27834479 --- /dev/null +++ b/tests/Images/Input/Tiff/BigTiff/BigTIFF.tif @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ddb202145a9bce7670cc372ee578de5a53cd52cc8d5ae8a9ebdc9f9c4f4a7e81 +size 12480 diff --git a/tests/Images/Input/Tiff/BigTiff/BigTIFFLong.tif b/tests/Images/Input/Tiff/BigTiff/BigTIFFLong.tif new file mode 100644 index 000000000..b390c0a97 --- /dev/null +++ b/tests/Images/Input/Tiff/BigTiff/BigTIFFLong.tif @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:90178643a159ec50335e9314836df924233debeb100763af0f77cd1be3cf58ab +size 12480 diff --git a/tests/Images/Input/Tiff/BigTiff/BigTIFFLong8.tif b/tests/Images/Input/Tiff/BigTiff/BigTIFFLong8.tif new file mode 100644 index 000000000..e1815c750 --- /dev/null +++ b/tests/Images/Input/Tiff/BigTiff/BigTIFFLong8.tif @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b38e61ccb01e10e26fb10c335fc6fca9ad087b0fb0df833e54bb02d1246e20d5 +size 12480 diff --git a/tests/Images/Input/Tiff/BigTiff/BigTIFFLong8Tiles.tif b/tests/Images/Input/Tiff/BigTiff/BigTIFFLong8Tiles.tif new file mode 100644 index 000000000..c69218948 --- /dev/null +++ b/tests/Images/Input/Tiff/BigTiff/BigTIFFLong8Tiles.tif @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a2d92b0c430cefc390f13961e00950ee7246b013335594dd249ba823eb3c3fdb +size 12564 diff --git a/tests/Images/Input/Tiff/BigTiff/BigTIFFMotorola.tif b/tests/Images/Input/Tiff/BigTiff/BigTIFFMotorola.tif new file mode 100644 index 000000000..68c2b3a41 --- /dev/null +++ b/tests/Images/Input/Tiff/BigTiff/BigTIFFMotorola.tif @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ace8a27dbed9f918993615e545a12310b84ad94bc6af8e256258e69731f1c7ce +size 12480 diff --git a/tests/Images/Input/Tiff/BigTiff/BigTIFFMotorolaLongStrips.tif b/tests/Images/Input/Tiff/BigTiff/BigTIFFMotorolaLongStrips.tif new file mode 100644 index 000000000..cc62e0362 --- /dev/null +++ b/tests/Images/Input/Tiff/BigTiff/BigTIFFMotorolaLongStrips.tif @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2c5ebdc3774955d3b47644f57bd023e764a93ca2271118152ae920b34c1784bb +size 12480 diff --git a/tests/Images/Input/Tiff/BigTiff/BigTIFFSamples.html b/tests/Images/Input/Tiff/BigTiff/BigTIFFSamples.html new file mode 100644 index 000000000..c674e57b5 --- /dev/null +++ b/tests/Images/Input/Tiff/BigTiff/BigTIFFSamples.html @@ -0,0 +1,239 @@ + + + + +

+ These images were created by AWare Systems. +

+

Index

+

+ Classic.tif
+ BigTIFF.tif
+ BigTIFFMotorola.tif
+ BigTIFFLong.tif
+ BigTIFFLong8.tif
+ BigTIFFMotorolaLongStrips.tif
+ BigTIFFLong8Tiles.tif
+ BigTIFFSubIFD4.tif
+ BigTIFFSubIFD8.tif
+

+

Classic.tif

+

+ Classic.tif is a basic Classic TIFF file. All files in this package have the same actual image content, + so this TIFF file serves as a reference. +

+

+ Format: Classic TIFF
+ Byte Order: Intel
+ Ifd Offset: 12302
+     ImageWidth (1 Short): 64
+     ImageLength (1 Short): 64
+     BitsPerSample (3 Short): 8, 8, 8
+     PhotometricInterpretation (1 Short): RGB
+     StripOffsets (1 Short): 8
+     SamplesPerPixel (1 Short): 3
+     RowsPerStrip (1 Short): 64
+     StripByteCounts (1 Short): 12288
+

+

BigTIFF.tif

+

+ BigTIFF.tif ressembles Classic.tif as close as possible. Except that it's a BigTIFF, that is... +

+

+ Format: BigTIFF
+ Byte Order: Intel
+ Ifd Offset: 12304
+     ImageWidth (1 Short): 64
+     ImageLength (1 Short): 64
+     BitsPerSample (3 Short): 8, 8, 8
+     PhotometricInterpretation (1 Short): RGB
+     StripOffsets (1 Short): 16
+     SamplesPerPixel (1 Short): 3
+     RowsPerStrip (1 Short): 64
+     StripByteCounts (1 Short): 12288
+

+

BigTIFFMotorola.tif

+

+ BigTIFFMotorola.tif reverses the byte order. +

+

+ Format: BigTIFF
+ Byte Order: Motorola
+ Ifd Offset: 12304
+     ImageWidth (1 Short): 64
+     ImageLength (1 Short): 64
+     BitsPerSample (3 Short): 8, 8, 8
+     PhotometricInterpretation (1 Short): RGB
+     StripOffsets (1 Short): 16
+     SamplesPerPixel (1 Short): 3
+     RowsPerStrip (1 Short): 64
+     StripByteCounts (1 Short): 12288
+

+

BigTIFFLong.tif

+

+ All previous TIFFs specify DataType Short for StripOffsets and StripByteCounts tags. This BigTIFF instead specifies DataType Long, for these tags. +

+

+ Format: BigTIFF
+ Byte Order: Intel
+ Ifd Offset: 12304
+     ImageWidth (1 Short): 64
+     ImageLength (1 Short): 64
+     BitsPerSample (3 Short): 8, 8, 8
+     PhotometricInterpretation (1 Short): RGB
+     StripOffsets (1 Long): 16
+     SamplesPerPixel (1 Short): 3
+     RowsPerStrip (1 Short): 64
+     StripByteCounts (1 Long): 12288
+

+

BigTIFFLong8.tif

+

+ This next one specifies DataType Long8, for StripOffsets and StripByteCounts tags. +

+

+ Format: BigTIFF
+ Byte Order: Intel
+ Ifd Offset: 12304
+     ImageWidth (1 Short): 64
+     ImageLength (1 Short): 64
+     BitsPerSample (3 Short): 8, 8, 8
+     PhotometricInterpretation (1 Short): RGB
+     StripOffsets (1 Long8): 16
+     SamplesPerPixel (1 Short): 3
+     RowsPerStrip (1 Short): 64
+     StripByteCounts (1 Long8): 12288
+

+

BigTIFFMotorolaLongStrips.tif

+

+ This BigTIFF has Motorola byte order, plus, it's divided over two strips. StripOffsets and StripByteCounts tags have DataType Long, so their actual value fits inside the IFD. +

+

+ Format: BigTIFF
+ Byte Order: Motorola
+ Ifd Offset: 12304
+     ImageWidth (1 Short): 64
+     ImageLength (1 Short): 64
+     BitsPerSample (3 Short): 8, 8, 8
+     PhotometricInterpretation (1 Short): RGB
+     StripOffsets (2 Long): 16, 6160
+     SamplesPerPixel (1 Short): 3
+     RowsPerStrip (1 Short): 32
+     StripByteCounts (2 Long): 6144, 6144
+

+

BigTIFFLong8Tiles.tif

+

+ BigTIFFLong8Tiles.tif is a tiled BigTIFF. TileOffsets and TileByteCounts tags specify DataType Long8. +

+

+ Format: BigTIFF
+ Byte Order: Intel
+ Ifd Offset: 12368
+     ImageWidth (1 Short): 64
+     ImageLength (1 Short): 64
+     BitsPerSample (3 Short): 8, 8, 8
+     PhotometricInterpretation (1 Short): RGB
+     SamplesPerPixel (1 Short): 3
+     TileWidth (1 Short): 32
+     TileLength (1 Short): 32
+     TileOffsets (4 Long8): 16, 3088, 6160, 9232
+     TileByteCounts (4 Long8): 3072, 3072, 3072, 3072
+

+

BigTIFFSubIFD4.tif

+

+ This BigTIFF contains two pages, the second page showing almost the same image content as the first, except that the black square is white, and text color is black. + Both pages point to a downsample SubIFD, using SubIFDs DataType TIFF_IFD. +

+

+ Format: BigTIFF
+ Byte Order: Intel
+ Ifd Offset: 15572
+     ImageWidth (1 Short): 64
+     ImageLength (1 Short): 64
+     BitsPerSample (3 Short): 8, 8, 8
+     PhotometricInterpretation (1 Short): RGB
+     StripOffsets (1 Short): 3284
+     SamplesPerPixel (1 Short): 3
+     RowsPerStrip (1 Short): 64
+     StripByteCounts (1 Short): 12288
+     SubIFDs (1 IFD): 3088
+ SubIfd Offset: 3088
+     NewSubFileType (1 Long): 1
+     ImageWidth (1 Short): 32
+     ImageLength (1 Short): 32
+     BitsPerSample (3 Short): 8, 8, 8
+     PhotometricInterpretation (1 Short): RGB
+     StripOffsets (1 Short): 16
+     SamplesPerPixel (1 Short): 3
+     RowsPerStrip (1 Short): 32
+     StripByteCounts (1 Short): 3072
+ Ifd Offset: 31324
+     ImageWidth (1 Short): 64
+     ImageLength (1 Short): 64
+     BitsPerSample (3 Short): 8, 8, 8
+     PhotometricInterpretation (1 Short): RGB
+     StripOffsets (1 Short): 19036
+     SamplesPerPixel (1 Short): 3
+     RowsPerStrip (1 Short): 64
+     StripByteCounts (1 Short): 12288
+     SubIFDs (1 IFD): 18840
+ SubIfd Offset: 18840
+     NewSubFileType (1 Long): 1
+     ImageWidth (1 Short): 32
+     ImageLength (1 Short): 32
+     BitsPerSample (3 Short): 8, 8, 8
+     PhotometricInterpretation (1 Short): RGB
+     StripOffsets (1 Short): 15768
+     SamplesPerPixel (1 Short): 3
+     RowsPerStrip (1 Short): 32
+     StripByteCounts (1 Short): 3072
+

+

BigTIFFSubIFD8.tif

+

+ BigTIFFSubIFD4.tif is very much the same as BigTIFFSubIFD4.tif, except that the new DataType TIFF_IFD8 is used for the SubIFDs tag. +

+

+ Format: BigTIFF
+ Byte Order: Intel
+ Ifd Offset: 15572
+     ImageWidth (1 Short): 64
+     ImageLength (1 Short): 64
+     BitsPerSample (3 Short): 8, 8, 8
+     PhotometricInterpretation (1 Short): RGB
+     StripOffsets (1 Short): 3284
+     SamplesPerPixel (1 Short): 3
+     RowsPerStrip (1 Short): 64
+     StripByteCounts (1 Short): 12288
+     SubIFDs (1 IFD8): 3088
+ SubIfd Offset: 3088
+     NewSubFileType (1 Long): 1
+     ImageWidth (1 Short): 32
+     ImageLength (1 Short): 32
+     BitsPerSample (3 Short): 8, 8, 8
+     PhotometricInterpretation (1 Short): RGB
+     StripOffsets (1 Short): 16
+     SamplesPerPixel (1 Short): 3
+     RowsPerStrip (1 Short): 32
+     StripByteCounts (1 Short): 3072
+ Ifd Offset: 31324
+     ImageWidth (1 Short): 64
+     ImageLength (1 Short): 64
+     BitsPerSample (3 Short): 8, 8, 8
+     PhotometricInterpretation (1 Short): RGB
+     StripOffsets (1 Short): 19036
+     SamplesPerPixel (1 Short): 3
+     RowsPerStrip (1 Short): 64
+     StripByteCounts (1 Short): 12288
+     SubIFDs (1 IFD8): 18840
+ SubIfd Offset: 18840
+     NewSubFileType (1 Long): 1
+     ImageWidth (1 Short): 32
+     ImageLength (1 Short): 32
+     BitsPerSample (3 Short): 8, 8, 8
+     PhotometricInterpretation (1 Short): RGB
+     StripOffsets (1 Short): 15768
+     SamplesPerPixel (1 Short): 3
+     RowsPerStrip (1 Short): 32
+     StripByteCounts (1 Short): 3072
+

+ + diff --git a/tests/Images/Input/Tiff/BigTiff/BigTIFFSubIFD4.tif b/tests/Images/Input/Tiff/BigTiff/BigTIFFSubIFD4.tif new file mode 100644 index 000000000..cd7bdf0b5 --- /dev/null +++ b/tests/Images/Input/Tiff/BigTiff/BigTIFFSubIFD4.tif @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:85c8da46abc2284f0ddac10bd03a7c98ee51024840b7e43f41f1c6a09bc02e7e +size 31520 diff --git a/tests/Images/Input/Tiff/BigTiff/BigTIFFSubIFD8.tif b/tests/Images/Input/Tiff/BigTiff/BigTIFFSubIFD8.tif new file mode 100644 index 000000000..bb0b3bf18 --- /dev/null +++ b/tests/Images/Input/Tiff/BigTiff/BigTIFFSubIFD8.tif @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:93e5ac30f507bec7936746ad6e109631c09f9b2332081e986063219ad2452a4a +size 31520 diff --git a/tests/Images/Input/Tiff/BigTiff/Classic.tif b/tests/Images/Input/Tiff/BigTiff/Classic.tif new file mode 100644 index 000000000..1fa6be78b --- /dev/null +++ b/tests/Images/Input/Tiff/BigTiff/Classic.tif @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cfa7fcf6927be5de644beb238067479e8d834d0cbe2257b00302f5dde84a1c1a +size 12404 diff --git a/tests/Images/Input/Tiff/BigTiff/readme.md b/tests/Images/Input/Tiff/BigTiff/readme.md new file mode 100644 index 000000000..be5d28906 --- /dev/null +++ b/tests/Images/Input/Tiff/BigTiff/readme.md @@ -0,0 +1,3 @@ +BigTIFF samples. + +Downloaded from AWARE SYSTEMS: https://www.awaresystems.be/imaging/tiff/bigtiff.html \ No newline at end of file From c5c4f64c89e6a274dbbc00aa24a49d93c21ba3d3 Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Sat, 11 Sep 2021 22:28:54 +0300 Subject: [PATCH 004/121] format detector for BigTiff --- .../Formats/Tiff/TiffConfigurationModule.cs | 4 +- .../Formats/Tiff/TiffImageFormatDetector.cs | 61 +++++++++++++++++-- 2 files changed, 58 insertions(+), 7 deletions(-) diff --git a/src/ImageSharp/Formats/Tiff/TiffConfigurationModule.cs b/src/ImageSharp/Formats/Tiff/TiffConfigurationModule.cs index e96dba207..5dfda95e8 100644 --- a/src/ImageSharp/Formats/Tiff/TiffConfigurationModule.cs +++ b/src/ImageSharp/Formats/Tiff/TiffConfigurationModule.cs @@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff { configuration.ImageFormatsManager.SetEncoder(TiffFormat.Instance, new TiffEncoder()); configuration.ImageFormatsManager.SetDecoder(TiffFormat.Instance, new TiffDecoder()); - configuration.ImageFormatsManager.AddImageFormatDetector(new TiffImageFormatDetector()); + configuration.ImageFormatsManager.AddImageFormatDetector(new TiffImageFormatDetector(false)); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Formats/Tiff/TiffImageFormatDetector.cs b/src/ImageSharp/Formats/Tiff/TiffImageFormatDetector.cs index f7e6f7a99..297da2dd8 100644 --- a/src/ImageSharp/Formats/Tiff/TiffImageFormatDetector.cs +++ b/src/ImageSharp/Formats/Tiff/TiffImageFormatDetector.cs @@ -10,8 +10,16 @@ namespace SixLabors.ImageSharp.Formats.Tiff ///
public sealed class TiffImageFormatDetector : IImageFormatDetector { + private readonly bool isBigTiff; + + /// + /// Initializes a new instance of the class. + /// + /// if set to true [is big tiff]. + public TiffImageFormatDetector(bool isBigTiff) => this.isBigTiff = isBigTiff; + /// - public int HeaderSize => 4; + public int HeaderSize => this.isBigTiff ? 8 : 4; /// public IImageFormat DetectFormat(ReadOnlySpan header) @@ -26,9 +34,52 @@ namespace SixLabors.ImageSharp.Formats.Tiff private bool IsSupportedFileFormat(ReadOnlySpan header) { - return header.Length >= this.HeaderSize && - ((header[0] == 0x49 && header[1] == 0x49 && header[2] == 0x2A && header[3] == 0x00) || // Little-endian - (header[0] == 0x4D && header[1] == 0x4D && header[2] == 0x00 && header[3] == 0x2A)); // Big-endian + if (header.Length >= this.HeaderSize) + { + if (header[0] == 0x49 && header[1] == 0x49) + { + // Little-endian + if (!this.isBigTiff) + { + if (header[2] == 0x2A && header[3] == 0x00) + { + return true; + } + } + else + { + if (header[2] == 0x2B && header[3] == 0x00 && header[4] == 8 && header[5] == 0 && header[6] == 0 && header[7] == 0) + { + return true; + } + } + } + else if (header[0] == 0x4D && header[1] == 0x4D) + { + // Big-endian + if (header[2] == 0x00 && (header[3] == 0x2A || header[3] == 0x2B)) + { + return true; + } + + if (!this.isBigTiff) + { + if (header[2] == 0 && header[3] == 0x2A) + { + return true; + } + } + else + { + if (header[2] == 0 && header[3] == 0x2A && header[4] == 0 && header[5] == 8 && header[6] == 0 && header[7] == 0) + { + return true; + } + } + } + } + + return false; } } -} \ No newline at end of file +} From a6c038b52c0ed3256fc04a9f559c65722a769b98 Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Sun, 12 Sep 2021 11:07:37 +0300 Subject: [PATCH 005/121] Revert Number changes --- src/ImageSharp/Common/Helpers/Numerics.cs | 32 -------- .../Profiles/Exif/Values/ExifNumber.cs | 17 ----- .../Profiles/Exif/Values/ExifNumberArray.cs | 37 --------- src/ImageSharp/Primitives/Number.cs | 75 +++---------------- 4 files changed, 12 insertions(+), 149 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/Numerics.cs b/src/ImageSharp/Common/Helpers/Numerics.cs index 885443e86..ba5c588ca 100644 --- a/src/ImageSharp/Common/Helpers/Numerics.cs +++ b/src/ImageSharp/Common/Helpers/Numerics.cs @@ -226,38 +226,6 @@ namespace SixLabors.ImageSharp return value; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ulong Clamp(ulong value, ulong min, ulong max) - { - if (value > max) - { - return max; - } - - if (value < min) - { - return min; - } - - return value; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static long Clamp(long value, long min, long max) - { - if (value > max) - { - return max; - } - - if (value < min) - { - return min; - } - - return value; - } - /// /// Returns the value clamped to the inclusive range of min and max. /// diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumber.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumber.cs index d16de4d22..9e206b23d 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumber.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumber.cs @@ -21,11 +21,6 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif { get { - if (this.Value > uint.MaxValue) - { - return ExifDataType.Long8; - } - if (this.Value > ushort.MaxValue) { return ExifDataType.Long; @@ -46,18 +41,6 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif switch (value) { - case long longValue: - if (longValue >= 0) - { - this.Value = (ulong)longValue; - return true; - } - - return false; - case ulong ulongValue: - this.Value = ulongValue; - - return true; case int intValue: if (intValue >= uint.MinValue) { diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumberArray.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumberArray.cs index 15b29dcec..2d3a93aed 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumberArray.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumberArray.cs @@ -26,11 +26,6 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif for (int i = 0; i < this.Value.Length; i++) { - if (this.Value[i] > uint.MaxValue) - { - return ExifDataType.Long8; - } - if (this.Value[i] > ushort.MaxValue) { return ExifDataType.Long; @@ -50,10 +45,6 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif switch (value) { - case long val: - return this.SetSingle(val); - case ulong val: - return this.SetSingle(val); case int val: return this.SetSingle(val); case uint val: @@ -62,10 +53,6 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif return this.SetSingle(val); case ushort val: return this.SetSingle(val); - case long[] array: - return this.SetArray(array); - case ulong[] array: - return this.SetArray(array); case int[] array: return this.SetArray(array); case uint[] array: @@ -87,30 +74,6 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif return true; } - private bool SetArray(long[] values) - { - var numbers = new Number[values.Length]; - for (int i = 0; i < values.Length; i++) - { - numbers[i] = values[i]; - } - - this.Value = numbers; - return true; - } - - private bool SetArray(ulong[] values) - { - var numbers = new Number[values.Length]; - for (int i = 0; i < values.Length; i++) - { - numbers[i] = values[i]; - } - - this.Value = numbers; - return true; - } - private bool SetArray(int[] values) { var numbers = new Number[values.Length]; diff --git a/src/ImageSharp/Primitives/Number.cs b/src/ImageSharp/Primitives/Number.cs index 690b72d79..e33d2344a 100644 --- a/src/ImageSharp/Primitives/Number.cs +++ b/src/ImageSharp/Primitives/Number.cs @@ -14,19 +14,19 @@ namespace SixLabors.ImageSharp public struct Number : IEquatable, IComparable { [FieldOffset(0)] - private readonly long signedValue; + private readonly int signedValue; [FieldOffset(0)] - private readonly ulong unsignedValue; + private readonly uint unsignedValue; - [FieldOffset(8)] + [FieldOffset(4)] private readonly bool isSigned; /// /// Initializes a new instance of the struct. /// /// The value of the number. - public Number(long value) + public Number(int value) : this() { this.signedValue = value; @@ -37,70 +37,30 @@ namespace SixLabors.ImageSharp /// Initializes a new instance of the struct. ///
/// The value of the number. - public Number(ulong value) + public Number(uint value) : this() { this.unsignedValue = value; this.isSigned = false; } - /// - /// Converts the specified to an instance of this type. - /// - /// The value. - public static implicit operator Number(long value) => new Number(value); - - /// - /// Converts the specified to an instance of this type. - /// - /// The value. - public static implicit operator Number(ulong value) => new Number(value); - /// /// Converts the specified to an instance of this type. /// /// The value. - public static implicit operator Number(int value) => new Number((long)value); + public static implicit operator Number(int value) => new Number(value); /// /// Converts the specified to an instance of this type. /// /// The value. - public static implicit operator Number(uint value) => new Number((ulong)value); - - /// - /// Converts the specified to an instance of this type. - /// - /// The value. - public static implicit operator Number(short value) => new Number((long)value); + public static implicit operator Number(uint value) => new Number(value); /// /// Converts the specified to an instance of this type. /// /// The value. - public static implicit operator Number(ushort value) => new Number((ulong)value); - - /// - /// Converts the specified to an instance of this type. - /// - /// The to convert. - public static explicit operator long(Number number) - { - return number.isSigned - ? number.signedValue - : (long)Numerics.Clamp(number.unsignedValue, 0, long.MaxValue); - } - - /// - /// Converts the specified to an instance of this type. - /// - /// The to convert. - public static explicit operator ulong(Number number) - { - return number.isSigned - ? (ulong)Numerics.Clamp(number.signedValue, 0, long.MaxValue) - : number.unsignedValue; - } + public static implicit operator Number(ushort value) => new Number((uint)value); /// /// Converts the specified to a . @@ -109,8 +69,8 @@ namespace SixLabors.ImageSharp public static explicit operator int(Number number) { return number.isSigned - ? (int)Numerics.Clamp(number.signedValue, int.MinValue, int.MaxValue) - : (int)Numerics.Clamp(number.unsignedValue, 0, (uint)int.MaxValue); + ? number.signedValue + : (int)Numerics.Clamp(number.unsignedValue, 0, int.MaxValue); } /// @@ -120,19 +80,8 @@ namespace SixLabors.ImageSharp public static explicit operator uint(Number number) { return number.isSigned - ? (uint)Numerics.Clamp(number.signedValue, uint.MinValue, uint.MaxValue) - : (uint)Numerics.Clamp(number.unsignedValue, uint.MinValue, uint.MaxValue); - } - - /// - /// Converts the specified to a . - /// - /// The to convert. - public static explicit operator short(Number number) - { - return number.isSigned - ? (short)Numerics.Clamp(number.signedValue, short.MinValue, short.MaxValue) - : (short)Numerics.Clamp(number.unsignedValue, 0, (ushort)short.MaxValue); + ? (uint)Numerics.Clamp(number.signedValue, 0, int.MaxValue) + : number.unsignedValue; } /// From c6383861d22ca81fad55af57c9d58b1aa0af411c Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Sun, 12 Sep 2021 11:08:50 +0300 Subject: [PATCH 006/121] Correct read Long8 tags --- .../Formats/Tiff/TiffDecoderCore.cs | 18 +-- .../Metadata/Profiles/Exif/ExifReader.cs | 28 +++- .../Profiles/Exif/Values/ExifLong8Array.cs | 128 +++++++++++++++++- 3 files changed, 163 insertions(+), 11 deletions(-) diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs index 922c1f174..4ab920ff8 100644 --- a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs +++ b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs @@ -211,16 +211,16 @@ namespace SixLabors.ImageSharp.Formats.Tiff var frame = new ImageFrame(this.Configuration, width, height, imageFrameMetaData); int rowsPerStrip = tags.GetValue(ExifTag.RowsPerStrip) != null ? (int)tags.GetValue(ExifTag.RowsPerStrip).Value : TiffConstants.RowsPerStripInfinity; - Number[] stripOffsets = tags.GetValue(ExifTag.StripOffsets)?.Value; - Number[] stripByteCounts = tags.GetValue(ExifTag.StripByteCounts)?.Value; + ExifLong8Array stripOffsets = tags.GetValueInternal(ExifTag.StripOffsets) as ExifLong8Array; + ExifLong8Array stripByteCounts = tags.GetValueInternal(ExifTag.StripByteCounts) as ExifLong8Array; if (this.PlanarConfiguration == TiffPlanarConfiguration.Planar) { - this.DecodeStripsPlanar(frame, rowsPerStrip, stripOffsets, stripByteCounts, cancellationToken); + this.DecodeStripsPlanar(frame, rowsPerStrip, stripOffsets.Value, stripByteCounts.Value, cancellationToken); } else { - this.DecodeStripsChunky(frame, rowsPerStrip, stripOffsets, stripByteCounts, cancellationToken); + this.DecodeStripsChunky(frame, rowsPerStrip, stripOffsets.Value, stripByteCounts.Value, cancellationToken); } return frame; @@ -276,7 +276,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff /// An array of byte offsets to each strip in the image. /// An array of the size of each strip (in bytes). /// The token to monitor cancellation. - private void DecodeStripsPlanar(ImageFrame frame, int rowsPerStrip, Number[] stripOffsets, Number[] stripByteCounts, CancellationToken cancellationToken) + private void DecodeStripsPlanar(ImageFrame frame, int rowsPerStrip, ulong[] stripOffsets, ulong[] stripByteCounts, CancellationToken cancellationToken) where TPixel : unmanaged, IPixel { int stripsPerPixel = this.BitsPerSample.Channels; @@ -329,8 +329,8 @@ namespace SixLabors.ImageSharp.Formats.Tiff { decompressor.Decompress( this.inputStream, - (uint)stripOffsets[stripIndex], - (uint)stripByteCounts[stripIndex], + stripOffsets[stripIndex], + stripByteCounts[stripIndex], stripHeight, stripBuffers[planeIndex].GetSpan()); stripIndex += stripsPerPlane; @@ -357,7 +357,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff /// The strip offsets. /// The strip byte counts. /// The token to monitor cancellation. - private void DecodeStripsChunky(ImageFrame frame, int rowsPerStrip, Number[] stripOffsets, Number[] stripByteCounts, CancellationToken cancellationToken) + private void DecodeStripsChunky(ImageFrame frame, int rowsPerStrip, ulong[] stripOffsets, ulong[] stripByteCounts, CancellationToken cancellationToken) where TPixel : unmanaged, IPixel { // If the rowsPerStrip has the default value, which is effectively infinity. That is, the entire image is one strip. @@ -413,7 +413,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff break; } - decompressor.Decompress(this.inputStream, (uint)stripOffsets[stripIndex], (uint)stripByteCounts[stripIndex], stripHeight, stripBufferSpan); + decompressor.Decompress(this.inputStream, stripOffsets[stripIndex], stripByteCounts[stripIndex], stripHeight, stripBufferSpan); colorDecoder.Decode(stripBufferSpan, pixels, 0, top, frame.Width, stripHeight); } diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs index 5c26fde7b..b9628ad73 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs @@ -420,8 +420,34 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif // The StripOffsets, StripByteCounts, TileOffsets, and TileByteCounts tags are allowed to have the datatype TIFF_LONG8 in BigTIFF. // Old datatypes TIFF_LONG, and TIFF_SHORT where allowed in the TIFF 6.0 specification, are still valid in BigTIFF, too. + // Likewise, tags that point to other IFDs, like e.g. the SubIFDs tag, are now allowed to have the datatype TIFF_IFD8 in BigTIFF. + // Again, the old datatypes TIFF_IFD, and the hardly recommendable TIFF_LONG, are still valid, too. // https://www.awaresystems.be/imaging/tiff/bigtiff.html - ExifValue exifValue = exifValue = ExifValues.Create(tag) ?? ExifValues.Create(tag, dataType, numberOfComponents); + ExifValue exifValue = null; + switch (tag) + { + case ExifTagValue.StripOffsets: + exifValue = new ExifLong8Array(ExifTagValue.StripOffsets); + break; + case ExifTagValue.StripByteCounts: + exifValue = new ExifLong8Array(ExifTagValue.StripByteCounts); + break; + case ExifTagValue.TileOffsets: + exifValue = new ExifLong8Array(ExifTagValue.TileOffsets); + break; + case ExifTagValue.TileByteCounts: + exifValue = new ExifLong8Array(ExifTagValue.TileByteCounts); + break; + //case ExifTagValue.SubIFDOffset: + // exifValue = new ExifLong8Array(ExifTagValue.SubIFDOffset); + // break; + //case ExifTagValue.GPSIFDOffset: + // exifValue = new ExifLong8Array(ExifTagValue.GPSIFDOffset); + // break; + default: + exifValue = exifValue = ExifValues.Create(tag) ?? ExifValues.Create(tag, dataType, numberOfComponents); + break; + } if (exifValue is null) { diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong8Array.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong8Array.cs index 3cf59adac..17fe888f7 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong8Array.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong8Array.cs @@ -20,8 +20,134 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif { } - public override ExifDataType DataType => ExifDataType.Long8; + public override ExifDataType DataType + { + get + { + if (this.Value is null) + { + return ExifDataType.Long; + } + + for (int i = 0; i < this.Value.Length; i++) + { + if (this.Value[i] > 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)val); + case uint val: + return this.SetSingle((ulong)val); + case short val: + return this.SetSingle((ulong)val); + case ushort val: + return this.SetSingle((ulong)val); + case long[] array: + return this.SetArray(array); + case ulong[] array: + return this.SetArray(array); + case int[] array: + return this.SetArray(array); + case uint[] array: + return this.SetArray(array); + case short[] array: + return this.SetArray(array); + case ushort[] array: + 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]; + } + + 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)values[i]; + } + + 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)values[i]; + } + + 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; + } } } From 393659f3863ecc8351bf0a6ad2a95a5b29137517 Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Sun, 12 Sep 2021 11:35:46 +0300 Subject: [PATCH 007/121] Add IsBigTif flag property in metadata --- src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs | 3 +++ src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs | 4 ++-- .../Formats/Tiff/TiffDecoderMetadataCreator.cs | 13 ++++--------- src/ImageSharp/Formats/Tiff/TiffMetadata.cs | 8 ++++++++ 4 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs b/src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs index bd673cf3a..e8a087123 100644 --- a/src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs +++ b/src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs @@ -29,6 +29,8 @@ namespace SixLabors.ImageSharp.Formats.Tiff /// public ByteOrder ByteOrder { get; private set; } + public bool IsBigTiff { get; private set; } + /// /// Reads image file directories. /// @@ -40,6 +42,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff headerReader.ReadFileHeader(); this.nextIfdOffset = headerReader.FirstIfdOffset; + this.IsBigTiff = headerReader.IsBigTiff; return this.ReadIfds(headerReader.IsBigTiff); } diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs index 4ab920ff8..3aae61448 100644 --- a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs +++ b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs @@ -154,7 +154,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff frames.Add(frame); } - ImageMetadata metadata = TiffDecoderMetadataCreator.Create(frames, this.ignoreMetadata, reader.ByteOrder); + ImageMetadata metadata = TiffDecoderMetadataCreator.Create(frames, this.ignoreMetadata, reader.ByteOrder, reader.IsBigTiff); // TODO: Tiff frames can have different sizes ImageFrame root = frames[0]; @@ -180,7 +180,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff ExifProfile rootFrameExifProfile = directories.First(); var rootMetadata = TiffFrameMetadata.Parse(rootFrameExifProfile); - ImageMetadata metadata = TiffDecoderMetadataCreator.Create(reader.ByteOrder, rootFrameExifProfile); + ImageMetadata metadata = TiffDecoderMetadataCreator.Create(reader.ByteOrder, reader.IsBigTiff, rootFrameExifProfile); int width = GetImageWidth(rootFrameExifProfile); int height = GetImageHeight(rootFrameExifProfile); diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderMetadataCreator.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderMetadataCreator.cs index 6f8a81a82..ddaf6fa96 100644 --- a/src/ImageSharp/Formats/Tiff/TiffDecoderMetadataCreator.cs +++ b/src/ImageSharp/Formats/Tiff/TiffDecoderMetadataCreator.cs @@ -18,7 +18,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff /// internal static class TiffDecoderMetadataCreator { - public static ImageMetadata Create(List> frames, bool ignoreMetadata, ByteOrder byteOrder) + public static ImageMetadata Create(List> frames, bool ignoreMetadata, ByteOrder byteOrder, bool isBigTiff) where TPixel : unmanaged, IPixel { if (frames.Count < 1) @@ -26,13 +26,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff TiffThrowHelper.ThrowImageFormatException("Expected at least one frame."); } - var imageMetaData = new ImageMetadata(); - ExifProfile exifProfileRootFrame = frames[0].Metadata.ExifProfile; - - SetResolution(imageMetaData, exifProfileRootFrame); - - TiffMetadata tiffMetadata = imageMetaData.GetTiffMetadata(); - tiffMetadata.ByteOrder = byteOrder; + ImageMetadata imageMetaData = Create(byteOrder, isBigTiff, frames[0].Metadata.ExifProfile); if (!ignoreMetadata) { @@ -56,13 +50,14 @@ namespace SixLabors.ImageSharp.Formats.Tiff return imageMetaData; } - public static ImageMetadata Create(ByteOrder byteOrder, ExifProfile exifProfile) + public static ImageMetadata Create(ByteOrder byteOrder, bool isBigTiff, ExifProfile exifProfile) { var imageMetaData = new ImageMetadata(); SetResolution(imageMetaData, exifProfile); TiffMetadata tiffMetadata = imageMetaData.GetTiffMetadata(); tiffMetadata.ByteOrder = byteOrder; + tiffMetadata.IsBigTiff = isBigTiff; return imageMetaData; } diff --git a/src/ImageSharp/Formats/Tiff/TiffMetadata.cs b/src/ImageSharp/Formats/Tiff/TiffMetadata.cs index cf1ab3754..d537981db 100644 --- a/src/ImageSharp/Formats/Tiff/TiffMetadata.cs +++ b/src/ImageSharp/Formats/Tiff/TiffMetadata.cs @@ -26,6 +26,14 @@ namespace SixLabors.ImageSharp.Formats.Tiff /// public ByteOrder ByteOrder { get; set; } + /// + /// Gets or sets a value indicating whether this instance is BigTiff format. + /// + /// + /// true if this instance BigTiff format; otherwise, false. + /// + public bool IsBigTiff { get; set; } + /// public IDeepCloneable DeepClone() => new TiffMetadata(this); } From 6755286a8ee98363262d4a6edcae87f47af06a44 Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Sun, 12 Sep 2021 11:09:40 +0300 Subject: [PATCH 008/121] Add BigTiff into ConfigurationModule, add identify tests --- .../Formats/Tiff/TiffConfigurationModule.cs | 2 + .../Formats/Tiff/BigTiffDecoderTests.cs | 51 +++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/src/ImageSharp/Formats/Tiff/TiffConfigurationModule.cs b/src/ImageSharp/Formats/Tiff/TiffConfigurationModule.cs index 5dfda95e8..656483435 100644 --- a/src/ImageSharp/Formats/Tiff/TiffConfigurationModule.cs +++ b/src/ImageSharp/Formats/Tiff/TiffConfigurationModule.cs @@ -14,6 +14,8 @@ namespace SixLabors.ImageSharp.Formats.Tiff configuration.ImageFormatsManager.SetEncoder(TiffFormat.Instance, new TiffEncoder()); configuration.ImageFormatsManager.SetDecoder(TiffFormat.Instance, new TiffDecoder()); configuration.ImageFormatsManager.AddImageFormatDetector(new TiffImageFormatDetector(false)); + + configuration.ImageFormatsManager.AddImageFormatDetector(new TiffImageFormatDetector(true)); } } } diff --git a/tests/ImageSharp.Tests/Formats/Tiff/BigTiffDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/BigTiffDecoderTests.cs index fc507513b..7843ba4b9 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/BigTiffDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/BigTiffDecoderTests.cs @@ -3,6 +3,8 @@ // ReSharper disable InconsistentNaming using System; +using System.IO; +using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.PixelFormats; using Xunit; @@ -31,5 +33,54 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff [WithFile(BigTIFFLong8Tiles, PixelTypes.Rgba32)] public void ThrowsNotSupported(TestImageProvider provider) where TPixel : unmanaged, IPixel => Assert.Throws(() => provider.GetImage(TiffDecoder)); + + [Theory] + [InlineData(BigTIFF, 24, 64, 64, 96, 96, PixelResolutionUnit.PixelsPerInch)] + [InlineData(BigTIFFLong, 24, 64, 64, 96, 96, PixelResolutionUnit.PixelsPerInch)] + [InlineData(BigTIFFLong8, 24, 64, 64, 96, 96, PixelResolutionUnit.PixelsPerInch)] + [InlineData(BigTIFFMotorola, 24, 64, 64, 96, 96, PixelResolutionUnit.PixelsPerInch)] + [InlineData(BigTIFFMotorolaLongStrips, 24, 64, 64, 96, 96, PixelResolutionUnit.PixelsPerInch)] + [InlineData(BigTIFFSubIFD4, 24, 64, 64, 96, 96, PixelResolutionUnit.PixelsPerInch)] + [InlineData(BigTIFFSubIFD8, 24, 64, 64, 96, 96, PixelResolutionUnit.PixelsPerInch)] + public void Identify(string imagePath, int expectedPixelSize, int expectedWidth, int expectedHeight, double expectedHResolution, double expectedVResolution, PixelResolutionUnit expectedResolutionUnit) + { + var testFile = TestFile.Create(imagePath); + using (var stream = new MemoryStream(testFile.Bytes, false)) + { + IImageInfo info = Image.Identify(stream); + + Assert.Equal(expectedPixelSize, info.PixelType?.BitsPerPixel); + Assert.Equal(expectedWidth, info.Width); + Assert.Equal(expectedHeight, info.Height); + Assert.NotNull(info.Metadata); + Assert.Equal(expectedHResolution, info.Metadata.HorizontalResolution); + Assert.Equal(expectedVResolution, info.Metadata.VerticalResolution); + Assert.Equal(expectedResolutionUnit, info.Metadata.ResolutionUnits); + + ImageSharp.Formats.Tiff.TiffMetadata tiffmeta = info.Metadata.GetTiffMetadata(); + Assert.NotNull(tiffmeta); + Assert.True(tiffmeta.IsBigTiff); + } + } + + [Theory] + [InlineData(BigTIFFLong, ImageSharp.ByteOrder.LittleEndian)] + [InlineData(BigTIFFMotorola, ImageSharp.ByteOrder.BigEndian)] + public void ByteOrder(string imagePath, ByteOrder expectedByteOrder) + { + var testFile = TestFile.Create(imagePath); + using (var stream = new MemoryStream(testFile.Bytes, false)) + { + IImageInfo info = Image.Identify(stream); + + Assert.NotNull(info.Metadata); + Assert.Equal(expectedByteOrder, info.Metadata.GetTiffMetadata().ByteOrder); + + stream.Seek(0, SeekOrigin.Begin); + + using var img = Image.Load(stream); + Assert.Equal(expectedByteOrder, img.Metadata.GetTiffMetadata().ByteOrder); + } + } } } From a4a0d1c2e73ec6c60478e5b4c290995546b4383b Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Sun, 12 Sep 2021 12:05:31 +0300 Subject: [PATCH 009/121] Correct parse strip tags --- .../Formats/Tiff/TiffDecoderCore.cs | 25 ++++++++++++++++--- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs index 3aae61448..9822cf63b 100644 --- a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs +++ b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs @@ -41,6 +41,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff /// private ByteOrder byteOrder; + /// + /// Indicating whether is BigTiff format. + /// + private bool isBigTiff; + /// /// Initializes a new instance of the class. /// @@ -145,6 +150,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff IEnumerable directories = reader.Read(); this.byteOrder = reader.ByteOrder; + this.isBigTiff = reader.IsBigTiff; var frames = new List>(); foreach (ExifProfile ifd in directories) @@ -211,16 +217,27 @@ namespace SixLabors.ImageSharp.Formats.Tiff var frame = new ImageFrame(this.Configuration, width, height, imageFrameMetaData); int rowsPerStrip = tags.GetValue(ExifTag.RowsPerStrip) != null ? (int)tags.GetValue(ExifTag.RowsPerStrip).Value : TiffConstants.RowsPerStripInfinity; - ExifLong8Array stripOffsets = tags.GetValueInternal(ExifTag.StripOffsets) as ExifLong8Array; - ExifLong8Array stripByteCounts = tags.GetValueInternal(ExifTag.StripByteCounts) as ExifLong8Array; + + ulong[] stripOffsets; + ulong[] stripByteCounts; + if (this.isBigTiff) + { + stripOffsets = tags.GetValueInternal(ExifTag.StripOffsets)?.GetValue() as ulong[]; + stripByteCounts = tags.GetValueInternal(ExifTag.StripByteCounts)?.GetValue() as ulong[]; + } + else + { + stripOffsets = tags.GetValue(ExifTag.StripOffsets)?.Value.Select(s => (ulong)(uint)s).ToArray(); + stripByteCounts = tags.GetValue(ExifTag.StripByteCounts)?.Value.Select(s => (ulong)(uint)s).ToArray(); + } if (this.PlanarConfiguration == TiffPlanarConfiguration.Planar) { - this.DecodeStripsPlanar(frame, rowsPerStrip, stripOffsets.Value, stripByteCounts.Value, cancellationToken); + this.DecodeStripsPlanar(frame, rowsPerStrip, stripOffsets, stripByteCounts, cancellationToken); } else { - this.DecodeStripsChunky(frame, rowsPerStrip, stripOffsets.Value, stripByteCounts.Value, cancellationToken); + this.DecodeStripsChunky(frame, rowsPerStrip, stripOffsets, stripByteCounts, cancellationToken); } return frame; From d1c78f8d226c0359ed0dcfe8219d8e53364f4bd3 Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Sun, 12 Sep 2021 12:06:10 +0300 Subject: [PATCH 010/121] revert missed value --- src/ImageSharp/Metadata/Profiles/Exif/ExifDataTypes.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifDataTypes.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifDataTypes.cs index ee30c6b08..729efb390 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/ExifDataTypes.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifDataTypes.cs @@ -36,6 +36,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif return 4; case ExifDataType.DoubleFloat: case ExifDataType.Rational: + case ExifDataType.SignedRational: case ExifDataType.Long8: case ExifDataType.SignedLong8: case ExifDataType.Ifd8: From 1ed2a9becf73022f96f9434800852cf7462de4d0 Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Sun, 12 Sep 2021 12:06:37 +0300 Subject: [PATCH 011/121] build fixes --- src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs | 12 ++++++------ .../Metadata/Profiles/Exif/Values/ExifLong8Array.cs | 1 - 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs index b9628ad73..2eaae2664 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs @@ -438,12 +438,12 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif case ExifTagValue.TileByteCounts: exifValue = new ExifLong8Array(ExifTagValue.TileByteCounts); break; - //case ExifTagValue.SubIFDOffset: - // exifValue = new ExifLong8Array(ExifTagValue.SubIFDOffset); - // break; - //case ExifTagValue.GPSIFDOffset: - // exifValue = new ExifLong8Array(ExifTagValue.GPSIFDOffset); - // break; + ////case ExifTagValue.SubIFDOffset: + //// exifValue = new ExifLong8Array(ExifTagValue.SubIFDOffset); + //// break; + ////case ExifTagValue.GPSIFDOffset: + //// exifValue = new ExifLong8Array(ExifTagValue.GPSIFDOffset); + //// break; default: exifValue = exifValue = ExifValues.Create(tag) ?? ExifValues.Create(tag, dataType, numberOfComponents); break; diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong8Array.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong8Array.cs index 17fe888f7..055a50104 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong8Array.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong8Array.cs @@ -77,7 +77,6 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif public override IExifValue DeepClone() => new ExifLong8Array(this); - private bool SetSingle(ulong value) { this.Value = new[] { value }; From 9b042a753634dcad4b5dc92cba49583ef54806fa Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Sun, 12 Sep 2021 20:25:01 +0300 Subject: [PATCH 012/121] FormatDetector fixes --- .../Formats/Tiff/TiffImageFormatDetector.cs | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/ImageSharp/Formats/Tiff/TiffImageFormatDetector.cs b/src/ImageSharp/Formats/Tiff/TiffImageFormatDetector.cs index 297da2dd8..5755b306a 100644 --- a/src/ImageSharp/Formats/Tiff/TiffImageFormatDetector.cs +++ b/src/ImageSharp/Formats/Tiff/TiffImageFormatDetector.cs @@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff /// /// Initializes a new instance of the class. /// - /// if set to true [is big tiff]. + /// if set to true is BigTiff. public TiffImageFormatDetector(bool isBigTiff) => this.isBigTiff = isBigTiff; /// @@ -39,7 +39,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff if (header[0] == 0x49 && header[1] == 0x49) { // Little-endian - if (!this.isBigTiff) + if (this.isBigTiff is false) { if (header[2] == 0x2A && header[3] == 0x00) { @@ -48,7 +48,8 @@ namespace SixLabors.ImageSharp.Formats.Tiff } else { - if (header[2] == 0x2B && header[3] == 0x00 && header[4] == 8 && header[5] == 0 && header[6] == 0 && header[7] == 0) + if (header[2] == 0x2B && header[3] == 0x00 + && header[4] == 8 && header[5] == 0 && header[6] == 0 && header[7] == 0) { return true; } @@ -57,12 +58,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff else if (header[0] == 0x4D && header[1] == 0x4D) { // Big-endian - if (header[2] == 0x00 && (header[3] == 0x2A || header[3] == 0x2B)) - { - return true; - } - - if (!this.isBigTiff) + if (this.isBigTiff is false) { if (header[2] == 0 && header[3] == 0x2A) { @@ -71,7 +67,8 @@ namespace SixLabors.ImageSharp.Formats.Tiff } else { - if (header[2] == 0 && header[3] == 0x2A && header[4] == 0 && header[5] == 8 && header[6] == 0 && header[7] == 0) + if (header[2] == 0 && header[3] == 0x2B + && header[4] == 0 && header[5] == 8 && header[6] == 0 && header[7] == 0) { return true; } From f370df714101c18cddd67ee6e05304635cf6bd4a Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Fri, 17 Sep 2021 07:54:05 +0300 Subject: [PATCH 013/121] Update src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Günther Foidl --- src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs index 2eaae2664..9f53bf64c 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs @@ -459,7 +459,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif if (size > 8) { ulong newOffset = this.ConvertToUInt64(this.offsetBuffer8); - if (newOffset > ulong.MaxValue || (newOffset + size) > (ulong)this.data.Length) + if (newOffset > ulong.MaxValue || newOffset > (ulong)(this.data.Length - size)) { this.AddInvalidTag(new UnkownExifTag(tag)); return; From 4bb6c7715dddf6ca1ac272890b859ceb0ed42e4e Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Fri, 17 Sep 2021 07:54:29 +0300 Subject: [PATCH 014/121] Update src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Günther Foidl --- src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs b/src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs index e8a087123..f6bc33079 100644 --- a/src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs +++ b/src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs @@ -49,8 +49,8 @@ namespace SixLabors.ImageSharp.Formats.Tiff private static ByteOrder ReadByteOrder(Stream stream) { - byte[] headerBytes = new byte[2]; - stream.Read(headerBytes, 0, 2); + Span headerBytes = stackalloc byte[2]; + stream.Read(headerBytes); if (headerBytes[0] == TiffConstants.ByteOrderLittleEndian && headerBytes[1] == TiffConstants.ByteOrderLittleEndian) { return ByteOrder.LittleEndian; From 789dc78864c27ec6b79b9143cd9765a0bc04ec7b Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Fri, 17 Sep 2021 08:03:18 +0300 Subject: [PATCH 015/121] build fix --- src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs index 9f53bf64c..a63a40d66 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs @@ -459,7 +459,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif if (size > 8) { ulong newOffset = this.ConvertToUInt64(this.offsetBuffer8); - if (newOffset > ulong.MaxValue || newOffset > (ulong)(this.data.Length - size)) + if (newOffset > ulong.MaxValue || newOffset > ((ulong)this.data.Length - size)) { this.AddInvalidTag(new UnkownExifTag(tag)); return; From ebb277a7942e0c18069bb103294661ec6c774d4d Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Fri, 17 Sep 2021 10:34:29 +0300 Subject: [PATCH 016/121] try improve reading ext values --- .../Formats/Tiff/Ifd/DirectoryReader.cs | 25 ++++---- .../Formats/Tiff/Ifd/EntryReader.cs | 10 +--- .../Metadata/Profiles/Exif/ExifReader.cs | 57 +++++++++---------- 3 files changed, 41 insertions(+), 51 deletions(-) diff --git a/src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs b/src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs index f6bc33079..3c70ee591 100644 --- a/src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs +++ b/src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs @@ -18,10 +18,6 @@ namespace SixLabors.ImageSharp.Formats.Tiff private ulong nextIfdOffset; - // used for sequential read big values (actual for multiframe big files) - // todo: different tags can link to the same data (stream offset) - investigate - private readonly SortedList lazyLoaders = new SortedList(new DuplicateKeyComparer()); - public DirectoryReader(Stream stream) => this.stream = stream; /// @@ -68,23 +64,28 @@ namespace SixLabors.ImageSharp.Formats.Tiff var readers = new List(); while (this.nextIfdOffset != 0 && this.nextIfdOffset < (ulong)this.stream.Length) { - var reader = new EntryReader(this.stream, this.ByteOrder, this.lazyLoaders); + var reader = new EntryReader(this.stream, this.ByteOrder); reader.ReadTags(isBigTiff, this.nextIfdOffset); - this.nextIfdOffset = reader.NextIfdOffset; + if (reader.ExtTags.Count > 0) + { + reader.ExtTags.Sort((t1, t2) => t1.offset.CompareTo(t2.offset)); - readers.Add(reader); - } + if (reader.ExtTags[0].offset < reader.NextIfdOffset) + { + // this means that most likely all elements are placed before next IFD + reader.ReadExtValues(); + } + } - // Sequential reading big values. - foreach (Action loader in this.lazyLoaders.Values) - { - loader(); + this.nextIfdOffset = reader.NextIfdOffset; + readers.Add(reader); } var list = new List(readers.Count); foreach (EntryReader reader in readers) { + reader.ReadExtValues(); var profile = new ExifProfile(reader.Values, reader.InvalidTags); list.Add(profile); } diff --git a/src/ImageSharp/Formats/Tiff/Ifd/EntryReader.cs b/src/ImageSharp/Formats/Tiff/Ifd/EntryReader.cs index 7884242ef..5a83febf8 100644 --- a/src/ImageSharp/Formats/Tiff/Ifd/EntryReader.cs +++ b/src/ImageSharp/Formats/Tiff/Ifd/EntryReader.cs @@ -12,13 +12,10 @@ namespace SixLabors.ImageSharp.Formats.Tiff { internal class EntryReader : BaseExifReader { - private readonly SortedList lazyLoaders; - - public EntryReader(Stream stream, ByteOrder byteOrder, SortedList lazyLoaders) + public EntryReader(Stream stream, ByteOrder byteOrder) : base(stream) { this.IsBigEndian = byteOrder == ByteOrder.BigEndian; - this.lazyLoaders = lazyLoaders; } public List Values { get; } = new List(); @@ -43,8 +40,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff } } - protected override void RegisterExtLoader(ulong offset, Action reader) => - this.lazyLoaders.Add(offset, reader); + public void ReadExtValues() => this.ReadExtValues(this.Values); } internal class HeaderReader : BaseExifReader @@ -81,7 +77,5 @@ namespace SixLabors.ImageSharp.Formats.Tiff TiffThrowHelper.ThrowInvalidHeader(); } - - protected override void RegisterExtLoader(ulong offset, Action reader) => throw new NotSupportedException(); } } diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs index a63a40d66..0cac35197 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs @@ -14,8 +14,6 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif { internal class ExifReader : BaseExifReader { - private readonly List loaders = new List(); - public ExifReader(byte[] exifData) : base(new MemoryStream(exifData ?? throw new ArgumentNullException(nameof(exifData)))) { @@ -41,22 +39,16 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif uint ifdOffset = this.ReadUInt32(); this.ReadValues(values, ifdOffset); + this.ReadExtValues(values); uint thumbnailOffset = this.ReadUInt32(); this.GetThumbnail(thumbnailOffset); this.ReadSubIfd(values); - foreach (Action loader in this.loaders) - { - loader(); - } - return values; } - protected override void RegisterExtLoader(ulong offset, Action loader) => this.loaders.Add(loader); - private void GetThumbnail(uint offset) { if (offset == 0) @@ -121,7 +113,17 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif public bool IsBigEndian { get; protected set; } - protected abstract void RegisterExtLoader(ulong offset, Action loader); + public List<(ulong offset, ExifDataType dataType, ulong numberOfComponents, ExifValue exif)> ExtTags { get; } = new (); + + protected void ReadExtValues(List values) + { + foreach ((ulong offset, ExifDataType dataType, ulong numberOfComponents, ExifValue exif) tag in this.ExtTags) + { + this.ReadExtValue(values, tag); + } + + this.ExtTags.Clear(); + } /// /// Reads the values to the values collection. @@ -173,6 +175,18 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif } } + protected void ReadExtValue(IList values, (ulong offset, ExifDataType dataType, ulong numberOfComponents, ExifValue exif) tag) + { + ulong size = tag.numberOfComponents * ExifDataTypes.GetSize(tag.dataType); + byte[] dataBuffer = new byte[size]; + this.Seek(tag.offset); + if (this.TryReadSpan(dataBuffer)) + { + object value = this.ConvertValue(tag.dataType, dataBuffer, tag.numberOfComponents); + this.Add(values, tag.exif, value); + } + } + protected void ReadSubIfd64(List values) { if (this.exifOffset != 0) @@ -375,21 +389,11 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif return; } - this.RegisterExtLoader(newOffset, () => - { - byte[] dataBuffer = new byte[size]; - this.Seek(newOffset); - if (this.TryReadSpan(dataBuffer)) - { - object value = this.ConvertValue(dataType, dataBuffer, numberOfComponents); - this.Add(values, exifValue, value); - } - }); + this.ExtTags.Add((newOffset, dataType, numberOfComponents, exifValue)); } else { object value = this.ConvertValue(dataType, this.offsetBuffer, numberOfComponents); - this.Add(values, exifValue, value); } } @@ -465,16 +469,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif return; } - this.RegisterExtLoader(newOffset, () => - { - byte[] dataBuffer = new byte[size]; - this.Seek(newOffset); - if (this.TryReadSpan(dataBuffer)) - { - object value = this.ConvertValue(dataType, dataBuffer, numberOfComponents); - this.Add(values, exifValue, value); - } - }); + this.ExtTags.Add((newOffset, dataType, numberOfComponents, exifValue)); } else { From 7fe80cfd9c229f743649523fa2a297009c28d1c5 Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Sat, 18 Sep 2021 18:41:32 +0300 Subject: [PATCH 017/121] Implement reading SubIfds (Code 330 (hex 0x014A)), ExifReader improvements --- .../Formats/Tiff/Ifd/DirectoryReader.cs | 2 +- .../Metadata/Profiles/Exif/ExifReader.cs | 110 ++++++++++-------- .../Profiles/Exif/Tags/ExifTag.LongArray.cs | 5 + .../Profiles/Exif/Values/ExifNumberArray.cs | 10 +- .../Profiles/Exif/Values/ExifValues.cs | 1 + .../Formats/Tiff/BigTiffDecoderTests.cs | 28 +++++ .../Profiles/Exif/ExifProfileTests.cs | 6 +- 7 files changed, 105 insertions(+), 57 deletions(-) diff --git a/src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs b/src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs index 3c70ee591..1e298028d 100644 --- a/src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs +++ b/src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs @@ -71,9 +71,9 @@ namespace SixLabors.ImageSharp.Formats.Tiff { reader.ExtTags.Sort((t1, t2) => t1.offset.CompareTo(t2.offset)); + // this means that most likely all elements are placed before next IFD if (reader.ExtTags[0].offset < reader.NextIfdOffset) { - // this means that most likely all elements are placed before next IFD reader.ReadExtValues(); } } diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs index 0cac35197..eea42af28 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs @@ -39,13 +39,14 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif uint ifdOffset = this.ReadUInt32(); this.ReadValues(values, ifdOffset); - this.ReadExtValues(values); uint thumbnailOffset = this.ReadUInt32(); this.GetThumbnail(thumbnailOffset); this.ReadSubIfd(values); + this.ReadExtValues(values); + return values; } @@ -78,8 +79,6 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif /// internal abstract class BaseExifReader { - private readonly byte[] offsetBuffer = new byte[4]; - private readonly byte[] offsetBuffer8 = new byte[8]; private readonly byte[] buf8 = new byte[8]; private readonly byte[] buf4 = new byte[4]; private readonly byte[] buf2 = new byte[2]; @@ -87,9 +86,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif private readonly Stream data; private List invalidTags; - private uint exifOffset; - - private uint gpsOffset; + private List subIfds; protected BaseExifReader(Stream stream) => this.data = stream ?? throw new ArgumentNullException(nameof(stream)); @@ -140,22 +137,23 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif this.Seek(offset); int count = this.ReadUInt16(); + Span offsetBuffer = new byte[4]; for (int i = 0; i < count; i++) { - this.ReadValue(values); + this.ReadValue(values, offsetBuffer); } } protected void ReadSubIfd(List values) { - if (this.exifOffset != 0) + if (this.subIfds is null) { - this.ReadValues(values, this.exifOffset); + return; } - if (this.gpsOffset != 0) + foreach (ulong subIfdOffset in this.subIfds) { - this.ReadValues(values, this.gpsOffset); + this.ReadValues(values, (uint)subIfdOffset); } } @@ -169,9 +167,10 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif this.Seek(offset); ulong count = this.ReadUInt64(); + Span offsetBuffer = new byte[8]; for (ulong i = 0; i < count; i++) { - this.ReadValue64(values); + this.ReadValue64(values, offsetBuffer); } } @@ -182,21 +181,21 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif this.Seek(tag.offset); if (this.TryReadSpan(dataBuffer)) { - object value = this.ConvertValue(tag.dataType, dataBuffer, tag.numberOfComponents); + object value = this.ConvertValue(tag.dataType, dataBuffer, tag.numberOfComponents > 1 || tag.exif.IsArray); this.Add(values, tag.exif, value); } } protected void ReadSubIfd64(List values) { - if (this.exifOffset != 0) + if (this.subIfds is null) { - this.ReadValues64(values, this.exifOffset); + return; } - if (this.gpsOffset != 0) + foreach (ulong subIfdOffset in this.subIfds) { - this.ReadValues64(values, this.gpsOffset); + this.ReadValues64(values, subIfdOffset); } } @@ -231,7 +230,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif return Encoding.UTF8.GetString(buffer); } - private object ConvertValue(ExifDataType dataType, ReadOnlySpan buffer, ulong numberOfComponents) + private object ConvertValue(ExifDataType dataType, ReadOnlySpan buffer, bool isArray) { if (buffer.Length == 0) { @@ -245,102 +244,104 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif case ExifDataType.Ascii: return this.ConvertToString(buffer); case ExifDataType.Byte: - if (numberOfComponents == 1) + if (!isArray) { return this.ConvertToByte(buffer); } return buffer.ToArray(); case ExifDataType.DoubleFloat: - if (numberOfComponents == 1) + if (!isArray) { return this.ConvertToDouble(buffer); } return ToArray(dataType, buffer, this.ConvertToDouble); case ExifDataType.Long: - if (numberOfComponents == 1) + case ExifDataType.Ifd: + if (!isArray) { return this.ConvertToUInt32(buffer); } return ToArray(dataType, buffer, this.ConvertToUInt32); case ExifDataType.Rational: - if (numberOfComponents == 1) + if (!isArray) { return this.ToRational(buffer); } return ToArray(dataType, buffer, this.ToRational); case ExifDataType.Short: - if (numberOfComponents == 1) + if (!isArray) { return this.ConvertToShort(buffer); } return ToArray(dataType, buffer, this.ConvertToShort); case ExifDataType.SignedByte: - if (numberOfComponents == 1) + if (!isArray) { return this.ConvertToSignedByte(buffer); } return ToArray(dataType, buffer, this.ConvertToSignedByte); case ExifDataType.SignedLong: - if (numberOfComponents == 1) + if (!isArray) { return this.ConvertToInt32(buffer); } return ToArray(dataType, buffer, this.ConvertToInt32); case ExifDataType.SignedRational: - if (numberOfComponents == 1) + if (!isArray) { return this.ToSignedRational(buffer); } return ToArray(dataType, buffer, this.ToSignedRational); case ExifDataType.SignedShort: - if (numberOfComponents == 1) + if (!isArray) { return this.ConvertToSignedShort(buffer); } return ToArray(dataType, buffer, this.ConvertToSignedShort); case ExifDataType.SingleFloat: - if (numberOfComponents == 1) + if (!isArray) { return this.ConvertToSingle(buffer); } return ToArray(dataType, buffer, this.ConvertToSingle); case ExifDataType.Long8: - if (numberOfComponents == 1) + case ExifDataType.Ifd8: + if (!isArray) { return this.ConvertToUInt64(buffer); } return ToArray(dataType, buffer, this.ConvertToUInt64); case ExifDataType.SignedLong8: - if (numberOfComponents == 1) + if (!isArray) { return this.ConvertToInt64(buffer); } return ToArray(dataType, buffer, this.ConvertToUInt64); case ExifDataType.Undefined: - if (numberOfComponents == 1) + if (!isArray) { return this.ConvertToByte(buffer); } return buffer.ToArray(); default: - throw new NotSupportedException(); + throw new NotSupportedException($"Data type {dataType} is not supported."); } } - private void ReadValue(List values) + private void ReadValue(List values, Span offsetBuffer) { // 2 | 2 | 4 | 4 // tag | type | count | value offset @@ -354,7 +355,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif uint numberOfComponents = this.ReadUInt32(); - this.TryReadSpan(this.offsetBuffer); + this.TryReadSpan(offsetBuffer); // Ensure that the data type is valid if (dataType == ExifDataType.Unknown) @@ -380,7 +381,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif uint size = numberOfComponents * ExifDataTypes.GetSize(dataType); if (size > 4) { - uint newOffset = this.ConvertToUInt32(this.offsetBuffer); + uint newOffset = this.ConvertToUInt32(offsetBuffer); // Ensure that the new index does not overrun the data. if (newOffset > int.MaxValue || (newOffset + size) > this.data.Length) @@ -393,12 +394,12 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif } else { - object value = this.ConvertValue(dataType, this.offsetBuffer, numberOfComponents); + object value = this.ConvertValue(dataType, offsetBuffer.Slice(0, (int)size), numberOfComponents > 1 || exifValue.IsArray); this.Add(values, exifValue, value); } } - private void ReadValue64(List values) + private void ReadValue64(List values, Span offsetBuffer) { if ((this.data.Length - this.data.Position) < 20) { @@ -410,7 +411,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif ulong numberOfComponents = this.ReadUInt64(); - this.TryReadSpan(this.offsetBuffer8); + this.TryReadSpan(offsetBuffer); if (dataType == ExifDataType.Unknown) { @@ -442,12 +443,15 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif case ExifTagValue.TileByteCounts: exifValue = new ExifLong8Array(ExifTagValue.TileByteCounts); break; - ////case ExifTagValue.SubIFDOffset: - //// exifValue = new ExifLong8Array(ExifTagValue.SubIFDOffset); - //// break; - ////case ExifTagValue.GPSIFDOffset: - //// exifValue = new ExifLong8Array(ExifTagValue.GPSIFDOffset); - //// break; + case ExifTagValue.SubIFDOffset: + exifValue = new ExifLong8(ExifTagValue.SubIFDOffset); + break; + case ExifTagValue.GPSIFDOffset: + exifValue = new ExifLong8(ExifTagValue.GPSIFDOffset); + break; + case ExifTagValue.SubIFDs: + exifValue = new ExifLong8Array(ExifTagValue.SubIFDs); + break; default: exifValue = exifValue = ExifValues.Create(tag) ?? ExifValues.Create(tag, dataType, numberOfComponents); break; @@ -462,7 +466,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif ulong size = numberOfComponents * ExifDataTypes.GetSize(dataType); if (size > 8) { - ulong newOffset = this.ConvertToUInt64(this.offsetBuffer8); + ulong newOffset = this.ConvertToUInt64(offsetBuffer); if (newOffset > ulong.MaxValue || newOffset > ((ulong)this.data.Length - size)) { this.AddInvalidTag(new UnkownExifTag(tag)); @@ -473,7 +477,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif } else { - object value = this.ConvertValue(dataType, ((Span)this.offsetBuffer8).Slice(0, (int)size), numberOfComponents); + object value = this.ConvertValue(dataType, offsetBuffer.Slice(0, (int)size), numberOfComponents > 1 || exifValue.IsArray); this.Add(values, exifValue, value); } } @@ -497,11 +501,18 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif if (exif.Tag == ExifTag.SubIFDOffset) { - this.exifOffset = (uint)value; + this.AddSubIfd(value); } else if (exif.Tag == ExifTag.GPSIFDOffset) { - this.gpsOffset = (uint)value; + this.AddSubIfd(value); + } + else if (exif.Tag == ExifTag.SubIFDs) + { + foreach (object val in (Array)value) + { + this.AddSubIfd(val); + } } else { @@ -512,6 +523,9 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif private void AddInvalidTag(ExifTag tag) => (this.invalidTags ??= new List()).Add(tag); + private void AddSubIfd(object val) + => (this.subIfds ??= new List()).Add(Convert.ToUInt64(val)); + private void Seek(ulong pos) => this.data.Seek((long)pos, SeekOrigin.Begin); diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.LongArray.cs b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.LongArray.cs index ac4b0a1bf..390599b73 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.LongArray.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.LongArray.cs @@ -65,5 +65,10 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif /// Gets the TimeZoneOffset exif tag. /// public static ExifTag TimeZoneOffset { get; } = new ExifTag(ExifTagValue.TimeZoneOffset); + + /// + /// Gets the offset to child IFDs exif tag. + /// + public static ExifTag SubIFDs { get; } = new ExifTag(ExifTagValue.SubIFDs); } } diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumberArray.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumberArray.cs index 2d3a93aed..9e9e0e737 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumberArray.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumberArray.cs @@ -49,18 +49,18 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif return this.SetSingle(val); case uint val: return this.SetSingle(val); - case short val: - return this.SetSingle(val); case ushort val: return this.SetSingle(val); - case int[] array: - return this.SetArray(array); + case short val: + return this.SetSingle(val); case uint[] array: return this.SetArray(array); - case short[] array: + case int[] array: return this.SetArray(array); case ushort[] array: return this.SetArray(array); + case short[] array: + return this.SetArray(array); } return false; diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifValues.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifValues.cs index 7e5b35f49..33fb90cc0 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifValues.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifValues.cs @@ -92,6 +92,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif case ExifTagValue.StripRowCounts: return new ExifLongArray(ExifTag.StripRowCounts); case ExifTagValue.IntergraphRegisters: return new ExifLongArray(ExifTag.IntergraphRegisters); case ExifTagValue.TimeZoneOffset: return new ExifLongArray(ExifTag.TimeZoneOffset); + case ExifTagValue.SubIFDs: return new ExifLongArray(ExifTag.SubIFDs); case ExifTagValue.ImageWidth: return new ExifNumber(ExifTag.ImageWidth); case ExifTagValue.ImageLength: return new ExifNumber(ExifTag.ImageLength); diff --git a/tests/ImageSharp.Tests/Formats/Tiff/BigTiffDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/BigTiffDecoderTests.cs index 7843ba4b9..d59e276cf 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/BigTiffDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/BigTiffDecoderTests.cs @@ -3,8 +3,10 @@ // ReSharper disable InconsistentNaming using System; +using System.Linq; using System.IO; using SixLabors.ImageSharp.Metadata; +using SixLabors.ImageSharp.Metadata.Profiles.Exif; using SixLabors.ImageSharp.PixelFormats; using Xunit; @@ -26,6 +28,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff [WithFile(BigTIFFMotorolaLongStrips, PixelTypes.Rgba32)] [WithFile(BigTIFFSubIFD4, PixelTypes.Rgba32)] [WithFile(BigTIFFSubIFD8, PixelTypes.Rgba32)] + [WithFile(Indexed4_Deflate, PixelTypes.Rgba32)] + [WithFile(Indexed8_LZW, PixelTypes.Rgba32)] + [WithFile(RLE, PixelTypes.Rgba32)] public void TiffDecoder_CanDecode(TestImageProvider provider) where TPixel : unmanaged, IPixel => TestTiffDecoder(provider); @@ -42,6 +47,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff [InlineData(BigTIFFMotorolaLongStrips, 24, 64, 64, 96, 96, PixelResolutionUnit.PixelsPerInch)] [InlineData(BigTIFFSubIFD4, 24, 64, 64, 96, 96, PixelResolutionUnit.PixelsPerInch)] [InlineData(BigTIFFSubIFD8, 24, 64, 64, 96, 96, PixelResolutionUnit.PixelsPerInch)] + [InlineData(Indexed4_Deflate, 24, 64, 64, 96, 96, PixelResolutionUnit.PixelsPerInch)] + [InlineData(Indexed8_LZW, 8, 64, 64, 96, 96, PixelResolutionUnit.PixelsPerInch)] + [InlineData(RLE, 1, 32, 32, 96, 96, PixelResolutionUnit.PixelsPerInch)] public void Identify(string imagePath, int expectedPixelSize, int expectedWidth, int expectedHeight, double expectedHResolution, double expectedVResolution, PixelResolutionUnit expectedResolutionUnit) { var testFile = TestFile.Create(imagePath); @@ -82,5 +90,25 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff Assert.Equal(expectedByteOrder, img.Metadata.GetTiffMetadata().ByteOrder); } } + + [Theory] + [WithFile(BigTIFFSubIFD8, PixelTypes.Rgba32)] + public void TiffDecoder_SubIfd8(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using Image image = provider.GetImage(TiffDecoder); + + ExifProfile meta = image.Frames.RootFrame.Metadata.ExifProfile; + + Assert.Equal(0, meta.InvalidTags.Count); + Assert.Equal(15, meta.Values.Count); + Assert.Equal(64, (int)meta.GetValue(ExifTag.ImageWidth).Value); + Assert.Equal(64, (int)meta.GetValue(ExifTag.ImageLength).Value); + Assert.Equal(64, (int)meta.GetValue(ExifTag.RowsPerStrip).Value); + + Assert.Equal(2, meta.Values.Count(v => (ushort)v.Tag == (ushort)ExifTagValue.ImageWidth)); + Assert.Equal(2, meta.Values.Count(v => (ushort)v.Tag == (ushort)ExifTagValue.StripOffsets)); + Assert.Equal(2, meta.Values.Count(v => (ushort)v.Tag == (ushort)ExifTagValue.StripByteCounts)); + } } } diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs index 1f23838ab..4b8551042 100644 --- a/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs +++ b/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs @@ -168,8 +168,8 @@ namespace SixLabors.ImageSharp.Tests.Metadata.Profiles.Exif 2 x due to use of non-standard padding tag 0xEA1C listed in EXIF Tool. We can read those values but adhere strictly to the 2.3.1 specification when writing. (TODO: Support 2.3.2) https://exiftool.org/TagNames/EXIF.html */ - [InlineData(TestImageWriteFormat.Jpeg, 16)] - [InlineData(TestImageWriteFormat.Png, 16)] + [InlineData(TestImageWriteFormat.Jpeg, 18)] + [InlineData(TestImageWriteFormat.Png, 18)] public void SetValue(TestImageWriteFormat imageFormat, int expectedProfileValueCount) { Image image = TestFile.Create(TestImages.Jpeg.Baseline.Floorplan).CreateRgba32Image(); @@ -519,7 +519,7 @@ namespace SixLabors.ImageSharp.Tests.Metadata.Profiles.Exif // todo: duplicate tags Assert.Equal(2, profile.Values.Count(v => (ushort)v.Tag == 59932)); - Assert.Equal(16, profile.Values.Count); + Assert.Equal(18, profile.Values.Count); foreach (IExifValue value in profile.Values) { From 42eab9500e03a4aceb49ce5a72070b4eabe28ace Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Sat, 18 Sep 2021 18:42:14 +0300 Subject: [PATCH 018/121] Add test files --- tests/ImageSharp.Tests/TestImages.cs | 22 +++++++++++-------- .../Tiff/BigTiff/BigTIFF_Indexed4_Deflate.tif | 3 +++ .../Tiff/BigTiff/BigTIFF_Indexed8_LZW.tif | 3 +++ .../Images/Input/Tiff/BigTiff/BigTIFF_RLE.tif | 3 +++ 4 files changed, 22 insertions(+), 9 deletions(-) create mode 100644 tests/Images/Input/Tiff/BigTiff/BigTIFF_Indexed4_Deflate.tif create mode 100644 tests/Images/Input/Tiff/BigTiff/BigTIFF_Indexed8_LZW.tif create mode 100644 tests/Images/Input/Tiff/BigTiff/BigTIFF_RLE.tif diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 9df6472a1..eccc3b089 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -675,17 +675,21 @@ namespace SixLabors.ImageSharp.Tests public static class BigTiff { - public const string BasePath = "Tiff/BigTiff/"; + public const string Base = "Tiff/BigTiff/"; - public const string BigTIFF = BasePath + "BigTIFF.tif"; - public const string BigTIFFLong = BasePath + "BigTIFFLong.tif"; - public const string BigTIFFLong8 = BasePath + "BigTIFFLong8.tif"; - public const string BigTIFFLong8Tiles = BasePath + "BigTIFFLong8Tiles.tif"; - public const string BigTIFFMotorola = BasePath + "BigTIFFMotorola.tif"; - public const string BigTIFFMotorolaLongStrips = BasePath + "BigTIFFMotorolaLongStrips.tif"; + public const string BigTIFF = Base + "BigTIFF.tif"; + public const string BigTIFFLong = Base + "BigTIFFLong.tif"; + public const string BigTIFFLong8 = Base + "BigTIFFLong8.tif"; + public const string BigTIFFLong8Tiles = Base + "BigTIFFLong8Tiles.tif"; + public const string BigTIFFMotorola = Base + "BigTIFFMotorola.tif"; + public const string BigTIFFMotorolaLongStrips = Base + "BigTIFFMotorolaLongStrips.tif"; - public const string BigTIFFSubIFD4 = BasePath + "BigTIFFSubIFD4.tif"; - public const string BigTIFFSubIFD8 = BasePath + "BigTIFFSubIFD8.tif"; + public const string BigTIFFSubIFD4 = Base + "BigTIFFSubIFD4.tif"; + public const string BigTIFFSubIFD8 = Base + "BigTIFFSubIFD8.tif"; + + public const string Indexed4_Deflate = Base + "BigTIFF_Indexed4_Deflate.tif"; + public const string Indexed8_LZW = Base + "BigTIFF_Indexed8_LZW.tif"; + public const string RLE = Base + "BigTIFF_RLE.tif"; } } } diff --git a/tests/Images/Input/Tiff/BigTiff/BigTIFF_Indexed4_Deflate.tif b/tests/Images/Input/Tiff/BigTiff/BigTIFF_Indexed4_Deflate.tif new file mode 100644 index 000000000..bc736790a --- /dev/null +++ b/tests/Images/Input/Tiff/BigTiff/BigTIFF_Indexed4_Deflate.tif @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:38ba3717b284d7914243609576d0f9b75d732692bf05e2e1ec8b119feb1409fd +size 687 diff --git a/tests/Images/Input/Tiff/BigTiff/BigTIFF_Indexed8_LZW.tif b/tests/Images/Input/Tiff/BigTiff/BigTIFF_Indexed8_LZW.tif new file mode 100644 index 000000000..edff7c40a --- /dev/null +++ b/tests/Images/Input/Tiff/BigTiff/BigTIFF_Indexed8_LZW.tif @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ca404b3ec5560b82169855f0ae69e64c6bc7286117b95fc0e0d505e5e356fa0e +size 2548 diff --git a/tests/Images/Input/Tiff/BigTiff/BigTIFF_RLE.tif b/tests/Images/Input/Tiff/BigTiff/BigTIFF_RLE.tif new file mode 100644 index 000000000..d15188c17 --- /dev/null +++ b/tests/Images/Input/Tiff/BigTiff/BigTIFF_RLE.tif @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:038a298bcace02810054af650f490b6858863c8755e41b786605aa807b43350a +size 509 From 7918ecc5af551cf98d8bc3635125af02b867ee11 Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Sat, 18 Sep 2021 19:28:40 +0300 Subject: [PATCH 019/121] temporary disable SubIFDs tag reading --- src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs | 8 ++++---- .../Formats/Tiff/BigTiffDecoderTests.cs | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs index eea42af28..eb15f9a49 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs @@ -509,10 +509,10 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif } else if (exif.Tag == ExifTag.SubIFDs) { - foreach (object val in (Array)value) - { - this.AddSubIfd(val); - } + ////foreach (object val in (Array)value) + ////{ + //// this.AddSubIfd(val); + ////} } else { diff --git a/tests/ImageSharp.Tests/Formats/Tiff/BigTiffDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/BigTiffDecoderTests.cs index d59e276cf..ae15eac5c 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/BigTiffDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/BigTiffDecoderTests.cs @@ -47,7 +47,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff [InlineData(BigTIFFMotorolaLongStrips, 24, 64, 64, 96, 96, PixelResolutionUnit.PixelsPerInch)] [InlineData(BigTIFFSubIFD4, 24, 64, 64, 96, 96, PixelResolutionUnit.PixelsPerInch)] [InlineData(BigTIFFSubIFD8, 24, 64, 64, 96, 96, PixelResolutionUnit.PixelsPerInch)] - [InlineData(Indexed4_Deflate, 24, 64, 64, 96, 96, PixelResolutionUnit.PixelsPerInch)] + [InlineData(Indexed4_Deflate, 4, 64, 64, 96, 96, PixelResolutionUnit.PixelsPerInch)] [InlineData(Indexed8_LZW, 8, 64, 64, 96, 96, PixelResolutionUnit.PixelsPerInch)] [InlineData(RLE, 1, 32, 32, 96, 96, PixelResolutionUnit.PixelsPerInch)] public void Identify(string imagePath, int expectedPixelSize, int expectedWidth, int expectedHeight, double expectedHResolution, double expectedVResolution, PixelResolutionUnit expectedResolutionUnit) @@ -101,14 +101,14 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff ExifProfile meta = image.Frames.RootFrame.Metadata.ExifProfile; Assert.Equal(0, meta.InvalidTags.Count); - Assert.Equal(15, meta.Values.Count); + Assert.Equal(6, meta.Values.Count); Assert.Equal(64, (int)meta.GetValue(ExifTag.ImageWidth).Value); Assert.Equal(64, (int)meta.GetValue(ExifTag.ImageLength).Value); Assert.Equal(64, (int)meta.GetValue(ExifTag.RowsPerStrip).Value); - Assert.Equal(2, meta.Values.Count(v => (ushort)v.Tag == (ushort)ExifTagValue.ImageWidth)); - Assert.Equal(2, meta.Values.Count(v => (ushort)v.Tag == (ushort)ExifTagValue.StripOffsets)); - Assert.Equal(2, meta.Values.Count(v => (ushort)v.Tag == (ushort)ExifTagValue.StripByteCounts)); + Assert.Equal(1, meta.Values.Count(v => (ushort)v.Tag == (ushort)ExifTagValue.ImageWidth)); + Assert.Equal(1, meta.Values.Count(v => (ushort)v.Tag == (ushort)ExifTagValue.StripOffsets)); + Assert.Equal(1, meta.Values.Count(v => (ushort)v.Tag == (ushort)ExifTagValue.StripByteCounts)); } } } From e55a63ac64cc3d7df14768f80c67c64c2a925549 Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Sat, 18 Sep 2021 20:28:29 +0300 Subject: [PATCH 020/121] Revert some changes --- src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs | 4 ++-- .../Metadata/Profiles/Exif/Values/ExifNumberArray.cs | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs index eb15f9a49..2aa2fa27d 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs @@ -394,7 +394,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif } else { - object value = this.ConvertValue(dataType, offsetBuffer.Slice(0, (int)size), numberOfComponents > 1 || exifValue.IsArray); + object value = this.ConvertValue(dataType, offsetBuffer.Slice(0, (int)size), numberOfComponents > 1); this.Add(values, exifValue, value); } } @@ -477,7 +477,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif } else { - object value = this.ConvertValue(dataType, offsetBuffer.Slice(0, (int)size), numberOfComponents > 1 || exifValue.IsArray); + object value = this.ConvertValue(dataType, offsetBuffer.Slice(0, (int)size), numberOfComponents > 1); this.Add(values, exifValue, value); } } diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumberArray.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumberArray.cs index 9e9e0e737..2d3a93aed 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumberArray.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumberArray.cs @@ -49,18 +49,18 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif return this.SetSingle(val); case uint val: return this.SetSingle(val); - case ushort val: - return this.SetSingle(val); case short val: return this.SetSingle(val); - case uint[] array: - return this.SetArray(array); + case ushort val: + return this.SetSingle(val); case int[] array: return this.SetArray(array); - case ushort[] array: + case uint[] array: return this.SetArray(array); case short[] array: return this.SetArray(array); + case ushort[] array: + return this.SetArray(array); } return false; From f170a73d3cb5ae444697031c6cba5f6662223c0b Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Sat, 18 Sep 2021 21:54:16 +0300 Subject: [PATCH 021/121] correct reading --- src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs index 2aa2fa27d..7a102b3b2 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs @@ -365,9 +365,9 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif // Issue #132: ExifDataType == Undefined is treated like a byte array. // If numberOfComponents == 0 this value can only be handled as an inline value and must fallback to 4 (bytes) - if (dataType == ExifDataType.Undefined && numberOfComponents == 0) + if (numberOfComponents == 0) { - numberOfComponents = 4; + numberOfComponents = 4 / ExifDataTypes.GetSize(dataType); } ExifValue exifValue = ExifValues.Create(tag) ?? ExifValues.Create(tag, dataType, numberOfComponents); @@ -418,9 +418,9 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif return; } - if (dataType == ExifDataType.Undefined && numberOfComponents == 0) + if (numberOfComponents == 0) { - numberOfComponents = 8; + numberOfComponents = 8 / ExifDataTypes.GetSize(dataType); } // The StripOffsets, StripByteCounts, TileOffsets, and TileByteCounts tags are allowed to have the datatype TIFF_LONG8 in BigTIFF. From 82d9b974cad9d0e627564a9420ece815a5f76bfc Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Sat, 18 Sep 2021 22:13:49 +0300 Subject: [PATCH 022/121] memory reduce big values reading --- .../Metadata/Profiles/Exif/ExifReader.cs | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs index 7a102b3b2..bae2d6c81 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs @@ -114,9 +114,22 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif protected void ReadExtValues(List values) { + ulong maxSize = 0; foreach ((ulong offset, ExifDataType dataType, ulong numberOfComponents, ExifValue exif) tag in this.ExtTags) { - this.ReadExtValue(values, tag); + ulong size = tag.numberOfComponents * ExifDataTypes.GetSize(tag.dataType); + if (size > maxSize) + { + maxSize = size; + } + } + + Span buf = new byte[maxSize]; + foreach ((ulong offset, ExifDataType dataType, ulong numberOfComponents, ExifValue exif) tag in this.ExtTags) + { + ulong size = tag.numberOfComponents * ExifDataTypes.GetSize(tag.dataType); + + this.ReadExtValue(values, tag, buf.Slice(0, (int)size)); } this.ExtTags.Clear(); @@ -174,14 +187,12 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif } } - protected void ReadExtValue(IList values, (ulong offset, ExifDataType dataType, ulong numberOfComponents, ExifValue exif) tag) + protected void ReadExtValue(IList values, (ulong offset, ExifDataType dataType, ulong numberOfComponents, ExifValue exif) tag, Span buffer) { - ulong size = tag.numberOfComponents * ExifDataTypes.GetSize(tag.dataType); - byte[] dataBuffer = new byte[size]; this.Seek(tag.offset); - if (this.TryReadSpan(dataBuffer)) + if (this.TryReadSpan(buffer)) { - object value = this.ConvertValue(tag.dataType, dataBuffer, tag.numberOfComponents > 1 || tag.exif.IsArray); + object value = this.ConvertValue(tag.dataType, buffer, tag.numberOfComponents > 1); this.Add(values, tag.exif, value); } } @@ -453,7 +464,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif exifValue = new ExifLong8Array(ExifTagValue.SubIFDs); break; default: - exifValue = exifValue = ExifValues.Create(tag) ?? ExifValues.Create(tag, dataType, numberOfComponents); + exifValue = ExifValues.Create(tag) ?? ExifValues.Create(tag, dataType, numberOfComponents); break; } From 8b7aaba6151bc3e794bade8f66146098285e3428 Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Sat, 18 Sep 2021 22:41:34 +0300 Subject: [PATCH 023/121] report problem files --- .../Formats/Tiff/BigTiffDecoderTests.cs | 11 +++++++++-- tests/ImageSharp.Tests/TestImages.cs | 3 ++- .../{BigTIFF_RLE.tif => BigTIFF_MinInBlack_RLE.tif} | 0 .../Input/Tiff/BigTiff/BigTIFF_MinInWhite_RLE.tif | 3 +++ 4 files changed, 14 insertions(+), 3 deletions(-) rename tests/Images/Input/Tiff/BigTiff/{BigTIFF_RLE.tif => BigTIFF_MinInBlack_RLE.tif} (100%) create mode 100644 tests/Images/Input/Tiff/BigTiff/BigTIFF_MinInWhite_RLE.tif diff --git a/tests/ImageSharp.Tests/Formats/Tiff/BigTiffDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/BigTiffDecoderTests.cs index ae15eac5c..e95844707 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/BigTiffDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/BigTiffDecoderTests.cs @@ -12,6 +12,7 @@ using SixLabors.ImageSharp.PixelFormats; using Xunit; using static SixLabors.ImageSharp.Tests.TestImages.BigTiff; +using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; namespace SixLabors.ImageSharp.Tests.Formats.Tiff { @@ -30,7 +31,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff [WithFile(BigTIFFSubIFD8, PixelTypes.Rgba32)] [WithFile(Indexed4_Deflate, PixelTypes.Rgba32)] [WithFile(Indexed8_LZW, PixelTypes.Rgba32)] - [WithFile(RLE, PixelTypes.Rgba32)] public void TiffDecoder_CanDecode(TestImageProvider provider) where TPixel : unmanaged, IPixel => TestTiffDecoder(provider); @@ -39,6 +39,12 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff public void ThrowsNotSupported(TestImageProvider provider) where TPixel : unmanaged, IPixel => Assert.Throws(() => provider.GetImage(TiffDecoder)); + [Theory] + [WithFile(MinInWhite_RLE, PixelTypes.Rgba32)] + [WithFile(MinInBlack_RLE, PixelTypes.Rgba32)] + public void ProblemFiles(TestImageProvider provider) + where TPixel : unmanaged, IPixel => Assert.Throws(() => TestTiffDecoder(provider)); + [Theory] [InlineData(BigTIFF, 24, 64, 64, 96, 96, PixelResolutionUnit.PixelsPerInch)] [InlineData(BigTIFFLong, 24, 64, 64, 96, 96, PixelResolutionUnit.PixelsPerInch)] @@ -49,7 +55,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff [InlineData(BigTIFFSubIFD8, 24, 64, 64, 96, 96, PixelResolutionUnit.PixelsPerInch)] [InlineData(Indexed4_Deflate, 4, 64, 64, 96, 96, PixelResolutionUnit.PixelsPerInch)] [InlineData(Indexed8_LZW, 8, 64, 64, 96, 96, PixelResolutionUnit.PixelsPerInch)] - [InlineData(RLE, 1, 32, 32, 96, 96, PixelResolutionUnit.PixelsPerInch)] + [InlineData(MinInWhite_RLE, 1, 32, 32, 96, 96, PixelResolutionUnit.PixelsPerInch)] + [InlineData(MinInBlack_RLE, 1, 32, 32, 96, 96, PixelResolutionUnit.PixelsPerInch)] public void Identify(string imagePath, int expectedPixelSize, int expectedWidth, int expectedHeight, double expectedHResolution, double expectedVResolution, PixelResolutionUnit expectedResolutionUnit) { var testFile = TestFile.Create(imagePath); diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index eccc3b089..e6342e660 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -689,7 +689,8 @@ namespace SixLabors.ImageSharp.Tests public const string Indexed4_Deflate = Base + "BigTIFF_Indexed4_Deflate.tif"; public const string Indexed8_LZW = Base + "BigTIFF_Indexed8_LZW.tif"; - public const string RLE = Base + "BigTIFF_RLE.tif"; + public const string MinInWhite_RLE = Base + "BigTIFF_MinInWhite_RLE.tif"; + public const string MinInBlack_RLE = Base + "BigTIFF_MinInBlack_RLE.tif"; } } } diff --git a/tests/Images/Input/Tiff/BigTiff/BigTIFF_RLE.tif b/tests/Images/Input/Tiff/BigTiff/BigTIFF_MinInBlack_RLE.tif similarity index 100% rename from tests/Images/Input/Tiff/BigTiff/BigTIFF_RLE.tif rename to tests/Images/Input/Tiff/BigTiff/BigTIFF_MinInBlack_RLE.tif diff --git a/tests/Images/Input/Tiff/BigTiff/BigTIFF_MinInWhite_RLE.tif b/tests/Images/Input/Tiff/BigTiff/BigTIFF_MinInWhite_RLE.tif new file mode 100644 index 000000000..d15188c17 --- /dev/null +++ b/tests/Images/Input/Tiff/BigTiff/BigTIFF_MinInWhite_RLE.tif @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:038a298bcace02810054af650f490b6858863c8755e41b786605aa807b43350a +size 509 From d1e778f097175d96716d3021579d41a0325489fa Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Sun, 19 Sep 2021 10:43:47 +0300 Subject: [PATCH 024/121] renaming, add fax3 test file --- .../Formats/Tiff/BigTiffDecoderTests.cs | 10 ++++++---- tests/ImageSharp.Tests/TestImages.cs | 5 +++-- .../Input/Tiff/BigTiff/BigTIFF_MinIsBlack_Fax3.tiff | 3 +++ ...F_MinInBlack_RLE.tif => BigTIFF_MinIsBlack_RLE.tif} | 0 ...F_MinInWhite_RLE.tif => BigTIFF_MinIsWhite_RLE.tif} | 0 5 files changed, 12 insertions(+), 6 deletions(-) create mode 100644 tests/Images/Input/Tiff/BigTiff/BigTIFF_MinIsBlack_Fax3.tiff rename tests/Images/Input/Tiff/BigTiff/{BigTIFF_MinInBlack_RLE.tif => BigTIFF_MinIsBlack_RLE.tif} (100%) rename tests/Images/Input/Tiff/BigTiff/{BigTIFF_MinInWhite_RLE.tif => BigTIFF_MinIsWhite_RLE.tif} (100%) diff --git a/tests/ImageSharp.Tests/Formats/Tiff/BigTiffDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/BigTiffDecoderTests.cs index e95844707..a6f08cbc9 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/BigTiffDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/BigTiffDecoderTests.cs @@ -31,6 +31,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff [WithFile(BigTIFFSubIFD8, PixelTypes.Rgba32)] [WithFile(Indexed4_Deflate, PixelTypes.Rgba32)] [WithFile(Indexed8_LZW, PixelTypes.Rgba32)] + [WithFile(MinIsBlack_Fax3, PixelTypes.Rgba32)] public void TiffDecoder_CanDecode(TestImageProvider provider) where TPixel : unmanaged, IPixel => TestTiffDecoder(provider); @@ -40,8 +41,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff where TPixel : unmanaged, IPixel => Assert.Throws(() => provider.GetImage(TiffDecoder)); [Theory] - [WithFile(MinInWhite_RLE, PixelTypes.Rgba32)] - [WithFile(MinInBlack_RLE, PixelTypes.Rgba32)] + [WithFile(MinIsWhite_RLE, PixelTypes.Rgba32)] + [WithFile(MinIsBlack_RLE, PixelTypes.Rgba32)] public void ProblemFiles(TestImageProvider provider) where TPixel : unmanaged, IPixel => Assert.Throws(() => TestTiffDecoder(provider)); @@ -55,8 +56,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff [InlineData(BigTIFFSubIFD8, 24, 64, 64, 96, 96, PixelResolutionUnit.PixelsPerInch)] [InlineData(Indexed4_Deflate, 4, 64, 64, 96, 96, PixelResolutionUnit.PixelsPerInch)] [InlineData(Indexed8_LZW, 8, 64, 64, 96, 96, PixelResolutionUnit.PixelsPerInch)] - [InlineData(MinInWhite_RLE, 1, 32, 32, 96, 96, PixelResolutionUnit.PixelsPerInch)] - [InlineData(MinInBlack_RLE, 1, 32, 32, 96, 96, PixelResolutionUnit.PixelsPerInch)] + [InlineData(MinIsWhite_RLE, 1, 32, 32, 96, 96, PixelResolutionUnit.PixelsPerInch)] + [InlineData(MinIsBlack_RLE, 1, 32, 32, 96, 96, PixelResolutionUnit.PixelsPerInch)] + [InlineData(MinIsBlack_Fax3, 1, 32, 32, 96, 96, PixelResolutionUnit.PixelsPerInch)] public void Identify(string imagePath, int expectedPixelSize, int expectedWidth, int expectedHeight, double expectedHResolution, double expectedVResolution, PixelResolutionUnit expectedResolutionUnit) { var testFile = TestFile.Create(imagePath); diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index e6342e660..7292d232d 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -689,8 +689,9 @@ namespace SixLabors.ImageSharp.Tests public const string Indexed4_Deflate = Base + "BigTIFF_Indexed4_Deflate.tif"; public const string Indexed8_LZW = Base + "BigTIFF_Indexed8_LZW.tif"; - public const string MinInWhite_RLE = Base + "BigTIFF_MinInWhite_RLE.tif"; - public const string MinInBlack_RLE = Base + "BigTIFF_MinInBlack_RLE.tif"; + public const string MinIsWhite_RLE = Base + "BigTIFF_MinIsWhite_RLE.tif"; + public const string MinIsBlack_RLE = Base + "BigTIFF_MinIsBlack_RLE.tif"; + public const string MinIsBlack_Fax3 = Base + "BigTIFF_MinIsBlack_Fax3.tif"; } } } diff --git a/tests/Images/Input/Tiff/BigTiff/BigTIFF_MinIsBlack_Fax3.tiff b/tests/Images/Input/Tiff/BigTiff/BigTIFF_MinIsBlack_Fax3.tiff new file mode 100644 index 000000000..952f4fab9 --- /dev/null +++ b/tests/Images/Input/Tiff/BigTiff/BigTIFF_MinIsBlack_Fax3.tiff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3853a4850a023bce431bc224145f47e095e9910cddce9ba5fcaf496c9d385e04 +size 564 diff --git a/tests/Images/Input/Tiff/BigTiff/BigTIFF_MinInBlack_RLE.tif b/tests/Images/Input/Tiff/BigTiff/BigTIFF_MinIsBlack_RLE.tif similarity index 100% rename from tests/Images/Input/Tiff/BigTiff/BigTIFF_MinInBlack_RLE.tif rename to tests/Images/Input/Tiff/BigTiff/BigTIFF_MinIsBlack_RLE.tif diff --git a/tests/Images/Input/Tiff/BigTiff/BigTIFF_MinInWhite_RLE.tif b/tests/Images/Input/Tiff/BigTiff/BigTIFF_MinIsWhite_RLE.tif similarity index 100% rename from tests/Images/Input/Tiff/BigTiff/BigTIFF_MinInWhite_RLE.tif rename to tests/Images/Input/Tiff/BigTiff/BigTIFF_MinIsWhite_RLE.tif From e13122cab1997f4aa91cc30844d81694eaf352a6 Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Sun, 19 Sep 2021 10:54:18 +0300 Subject: [PATCH 025/121] workaround for inconsistent covariance of value-typed arrays --- .../Profiles/Exif/Values/ExifLong8Array.cs | 37 +++++++++++++++---- .../Profiles/Exif/Values/ExifNumberArray.cs | 20 ++++++++-- 2 files changed, 45 insertions(+), 12 deletions(-) diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong8Array.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong8Array.cs index 055a50104..d012f646b 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong8Array.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong8Array.cs @@ -51,25 +51,46 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif switch (value) { case int val: - return this.SetSingle((ulong)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)val); + return this.SetSingle((ulong)Numerics.Clamp(val, 0, short.MaxValue)); + case ushort val: return this.SetSingle((ulong)val); + case long[] array: + { + if (value.GetType().Equals(typeof(ulong[]))) + { + return this.SetArray((ulong[])value); + } + return this.SetArray(array); - case ulong[] array: - return this.SetArray(array); + } + case int[] array: + { + if (value.GetType().Equals(typeof(uint[]))) + { + return this.SetArray((uint[])value); + } + return this.SetArray(array); - case uint[] array: - return this.SetArray(array); + } + case short[] array: + { + if (value.GetType().Equals(typeof(ushort[]))) + { + return this.SetArray((ushort[])value); + } + return this.SetArray(array); - case ushort[] array: - return this.SetArray(array); + } } return false; diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumberArray.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumberArray.cs index 2d3a93aed..4b7433d7d 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumberArray.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumberArray.cs @@ -54,13 +54,25 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif case ushort val: return this.SetSingle(val); case int[] array: + { + // workaround for inconsistent covariance of value-typed arrays + if (value.GetType().Equals(typeof(uint[]))) + { + return this.SetArray((uint[])value); + } + return this.SetArray(array); - case uint[] array: - return this.SetArray(array); + } + case short[] array: + { + if (value.GetType().Equals(typeof(ushort[]))) + { + return this.SetArray((ushort[])value); + } + return this.SetArray(array); - case ushort[] array: - return this.SetArray(array); + } } return false; From 1ff115638229073531e72e95e95f3c28088bd44a Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Sun, 19 Sep 2021 11:06:46 +0300 Subject: [PATCH 026/121] renaming --- .../Formats/Tiff/Ifd/DirectoryReader.cs | 10 +++---- .../Formats/Tiff/Ifd/EntryReader.cs | 3 +- .../Metadata/Profiles/Exif/ExifReader.cs | 28 +++++++++---------- 3 files changed, 20 insertions(+), 21 deletions(-) diff --git a/src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs b/src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs index 1e298028d..3aed89bc5 100644 --- a/src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs +++ b/src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs @@ -67,14 +67,14 @@ namespace SixLabors.ImageSharp.Formats.Tiff var reader = new EntryReader(this.stream, this.ByteOrder); reader.ReadTags(isBigTiff, this.nextIfdOffset); - if (reader.ExtTags.Count > 0) + if (reader.BigValues.Count > 0) { - reader.ExtTags.Sort((t1, t2) => t1.offset.CompareTo(t2.offset)); + reader.BigValues.Sort((t1, t2) => t1.offset.CompareTo(t2.offset)); // this means that most likely all elements are placed before next IFD - if (reader.ExtTags[0].offset < reader.NextIfdOffset) + if (reader.BigValues[0].offset < reader.NextIfdOffset) { - reader.ReadExtValues(); + reader.ReadBigValues(); } } @@ -85,7 +85,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff var list = new List(readers.Count); foreach (EntryReader reader in readers) { - reader.ReadExtValues(); + reader.ReadBigValues(); var profile = new ExifProfile(reader.Values, reader.InvalidTags); list.Add(profile); } diff --git a/src/ImageSharp/Formats/Tiff/Ifd/EntryReader.cs b/src/ImageSharp/Formats/Tiff/Ifd/EntryReader.cs index 5a83febf8..98cc1deb3 100644 --- a/src/ImageSharp/Formats/Tiff/Ifd/EntryReader.cs +++ b/src/ImageSharp/Formats/Tiff/Ifd/EntryReader.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Apache License, Version 2.0. -using System; using System.Collections.Generic; using System.IO; @@ -40,7 +39,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff } } - public void ReadExtValues() => this.ReadExtValues(this.Values); + public void ReadBigValues() => this.ReadBigValues(this.Values); } internal class HeaderReader : BaseExifReader diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs index bae2d6c81..feca52871 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs @@ -45,7 +45,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif this.ReadSubIfd(values); - this.ReadExtValues(values); + this.ReadBigValues(values); return values; } @@ -110,14 +110,14 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif public bool IsBigEndian { get; protected set; } - public List<(ulong offset, ExifDataType dataType, ulong numberOfComponents, ExifValue exif)> ExtTags { get; } = new (); + public List<(ulong offset, ExifDataType dataType, ulong numberOfComponents, ExifValue exif)> BigValues { get; } = new (); - protected void ReadExtValues(List values) + protected void ReadBigValues(List values) { ulong maxSize = 0; - foreach ((ulong offset, ExifDataType dataType, ulong numberOfComponents, ExifValue exif) tag in this.ExtTags) + foreach ((ulong offset, ExifDataType dataType, ulong numberOfComponents, ExifValue exif) in this.BigValues) { - ulong size = tag.numberOfComponents * ExifDataTypes.GetSize(tag.dataType); + ulong size = numberOfComponents * ExifDataTypes.GetSize(dataType); if (size > maxSize) { maxSize = size; @@ -125,14 +125,14 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif } Span buf = new byte[maxSize]; - foreach ((ulong offset, ExifDataType dataType, ulong numberOfComponents, ExifValue exif) tag in this.ExtTags) + foreach ((ulong offset, ExifDataType dataType, ulong numberOfComponents, ExifValue exif) tag in this.BigValues) { ulong size = tag.numberOfComponents * ExifDataTypes.GetSize(tag.dataType); - this.ReadExtValue(values, tag, buf.Slice(0, (int)size)); + this.ReadBigValue(values, tag, buf.Slice(0, (int)size)); } - this.ExtTags.Clear(); + this.BigValues.Clear(); } /// @@ -187,12 +187,12 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif } } - protected void ReadExtValue(IList values, (ulong offset, ExifDataType dataType, ulong numberOfComponents, ExifValue exif) tag, Span buffer) + protected void ReadBigValue(IList values, (ulong offset, ExifDataType dataType, ulong numberOfComponents, ExifValue exif) tag, Span buffer) { this.Seek(tag.offset); if (this.TryReadSpan(buffer)) { - object value = this.ConvertValue(tag.dataType, buffer, tag.numberOfComponents > 1); + object value = this.ConvertValue(tag.dataType, buffer, tag.numberOfComponents > 1 || tag.exif.IsArray); this.Add(values, tag.exif, value); } } @@ -401,11 +401,11 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif return; } - this.ExtTags.Add((newOffset, dataType, numberOfComponents, exifValue)); + this.BigValues.Add((newOffset, dataType, numberOfComponents, exifValue)); } else { - object value = this.ConvertValue(dataType, offsetBuffer.Slice(0, (int)size), numberOfComponents > 1); + object value = this.ConvertValue(dataType, offsetBuffer.Slice(0, (int)size), numberOfComponents > 1 || exifValue.IsArray); this.Add(values, exifValue, value); } } @@ -484,11 +484,11 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif return; } - this.ExtTags.Add((newOffset, dataType, numberOfComponents, exifValue)); + this.BigValues.Add((newOffset, dataType, numberOfComponents, exifValue)); } else { - object value = this.ConvertValue(dataType, offsetBuffer.Slice(0, (int)size), numberOfComponents > 1); + object value = this.ConvertValue(dataType, offsetBuffer.Slice(0, (int)size), numberOfComponents > 1 || exifValue.IsArray); this.Add(values, exifValue, value); } } From 46b6214c8cbe81bc9195762eab81145edd240ed1 Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Sun, 19 Sep 2021 11:15:03 +0300 Subject: [PATCH 027/121] rename --- .../{BigTIFF_MinIsBlack_Fax3.tiff => BigTIFF_MinIsBlack_Fax3.tif} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/Images/Input/Tiff/BigTiff/{BigTIFF_MinIsBlack_Fax3.tiff => BigTIFF_MinIsBlack_Fax3.tif} (100%) diff --git a/tests/Images/Input/Tiff/BigTiff/BigTIFF_MinIsBlack_Fax3.tiff b/tests/Images/Input/Tiff/BigTiff/BigTIFF_MinIsBlack_Fax3.tif similarity index 100% rename from tests/Images/Input/Tiff/BigTiff/BigTIFF_MinIsBlack_Fax3.tiff rename to tests/Images/Input/Tiff/BigTiff/BigTIFF_MinIsBlack_Fax3.tif From 75db00274fe4aba7d91c0fcd62f4321c99672759 Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Sun, 19 Sep 2021 11:29:53 +0300 Subject: [PATCH 028/121] remove obsolete code --- .../Formats/Tiff/Ifd/DirectoryReader.cs | 16 ---------------- .../Metadata/Profiles/Exif/ExifReader.cs | 5 +---- 2 files changed, 1 insertion(+), 20 deletions(-) diff --git a/src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs b/src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs index 3aed89bc5..6421db8d8 100644 --- a/src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs +++ b/src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs @@ -92,21 +92,5 @@ namespace SixLabors.ImageSharp.Formats.Tiff return list; } - - /// - /// used for possibility add a duplicate offsets (but tags don't duplicate). - /// - /// The type of the key. - private class DuplicateKeyComparer : IComparer - where TKey : IComparable - { - public int Compare(TKey x, TKey y) - { - int result = x.CompareTo(y); - - // Handle equality as being greater. - return (result == 0) ? 1 : result; - } - } } } diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs index feca52871..9abaf1432 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs @@ -172,10 +172,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif protected void ReadValues64(List values, ulong offset) { - if (offset > (ulong)this.data.Length) - { - return; - } + DebugGuard.MustBeLessThanOrEqualTo(offset, (ulong)this.data.Length, "By spec UInt64.MaxValue is supported, but .Net Stream.Length can Int64.MaxValue."); this.Seek(offset); ulong count = this.ReadUInt64(); From df0bc4c2227ec019859b42bd655ba7fc4c105693 Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Sun, 19 Sep 2021 11:30:09 +0300 Subject: [PATCH 029/121] problem test file --- tests/ImageSharp.Tests/Formats/Tiff/BigTiffDecoderTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ImageSharp.Tests/Formats/Tiff/BigTiffDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/BigTiffDecoderTests.cs index a6f08cbc9..c00336b25 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/BigTiffDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/BigTiffDecoderTests.cs @@ -31,7 +31,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff [WithFile(BigTIFFSubIFD8, PixelTypes.Rgba32)] [WithFile(Indexed4_Deflate, PixelTypes.Rgba32)] [WithFile(Indexed8_LZW, PixelTypes.Rgba32)] - [WithFile(MinIsBlack_Fax3, PixelTypes.Rgba32)] public void TiffDecoder_CanDecode(TestImageProvider provider) where TPixel : unmanaged, IPixel => TestTiffDecoder(provider); @@ -43,6 +42,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff [Theory] [WithFile(MinIsWhite_RLE, PixelTypes.Rgba32)] [WithFile(MinIsBlack_RLE, PixelTypes.Rgba32)] + [WithFile(MinIsBlack_Fax3, PixelTypes.Rgba32)] public void ProblemFiles(TestImageProvider provider) where TPixel : unmanaged, IPixel => Assert.Throws(() => TestTiffDecoder(provider)); From 82f64912ea5ffb6e66c075fd8ed67abea7e7a613 Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Sun, 19 Sep 2021 15:05:49 +0300 Subject: [PATCH 030/121] improve strip offset and strip byte counts parsing --- .../Formats/Tiff/TiffDecoderCore.cs | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs index 9822cf63b..6692b7991 100644 --- a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs +++ b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Apache License, Version 2.0. +using System; using System.Buffers; using System.Collections.Generic; using System.Linq; @@ -218,18 +219,8 @@ namespace SixLabors.ImageSharp.Formats.Tiff int rowsPerStrip = tags.GetValue(ExifTag.RowsPerStrip) != null ? (int)tags.GetValue(ExifTag.RowsPerStrip).Value : TiffConstants.RowsPerStripInfinity; - ulong[] stripOffsets; - ulong[] stripByteCounts; - if (this.isBigTiff) - { - stripOffsets = tags.GetValueInternal(ExifTag.StripOffsets)?.GetValue() as ulong[]; - stripByteCounts = tags.GetValueInternal(ExifTag.StripByteCounts)?.GetValue() as ulong[]; - } - else - { - stripOffsets = tags.GetValue(ExifTag.StripOffsets)?.Value.Select(s => (ulong)(uint)s).ToArray(); - stripByteCounts = tags.GetValue(ExifTag.StripByteCounts)?.Value.Select(s => (ulong)(uint)s).ToArray(); - } + var stripOffsets = (Array)tags.GetValueInternal(ExifTag.StripOffsets)?.GetValue(); + var stripByteCounts = (Array)tags.GetValueInternal(ExifTag.StripByteCounts)?.GetValue(); if (this.PlanarConfiguration == TiffPlanarConfiguration.Planar) { @@ -293,7 +284,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff /// An array of byte offsets to each strip in the image. /// An array of the size of each strip (in bytes). /// The token to monitor cancellation. - private void DecodeStripsPlanar(ImageFrame frame, int rowsPerStrip, ulong[] stripOffsets, ulong[] stripByteCounts, CancellationToken cancellationToken) + private void DecodeStripsPlanar(ImageFrame frame, int rowsPerStrip, Array stripOffsets, Array stripByteCounts, CancellationToken cancellationToken) where TPixel : unmanaged, IPixel { int stripsPerPixel = this.BitsPerSample.Channels; @@ -344,10 +335,12 @@ namespace SixLabors.ImageSharp.Formats.Tiff int stripIndex = i; for (int planeIndex = 0; planeIndex < stripsPerPixel; planeIndex++) { + ulong offset = stripOffsets.GetValue(stripIndex) switch { ulong val => val, Number val => (uint)val }; + ulong count = stripByteCounts.GetValue(stripIndex) switch { ulong val => val, Number val => (uint)val }; decompressor.Decompress( this.inputStream, - stripOffsets[stripIndex], - stripByteCounts[stripIndex], + offset, + count, stripHeight, stripBuffers[planeIndex].GetSpan()); stripIndex += stripsPerPlane; @@ -374,7 +367,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff /// The strip offsets. /// The strip byte counts. /// The token to monitor cancellation. - private void DecodeStripsChunky(ImageFrame frame, int rowsPerStrip, ulong[] stripOffsets, ulong[] stripByteCounts, CancellationToken cancellationToken) + private void DecodeStripsChunky(ImageFrame frame, int rowsPerStrip, Array stripOffsets, Array stripByteCounts, CancellationToken cancellationToken) where TPixel : unmanaged, IPixel { // If the rowsPerStrip has the default value, which is effectively infinity. That is, the entire image is one strip. @@ -387,7 +380,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff int bitsPerPixel = this.BitsPerPixel; using IMemoryOwner stripBuffer = this.memoryAllocator.Allocate(uncompressedStripSize, AllocationOptions.Clean); - System.Span stripBufferSpan = stripBuffer.GetSpan(); + Span stripBufferSpan = stripBuffer.GetSpan(); Buffer2D pixels = frame.PixelBuffer; using TiffBaseDecompressor decompressor = TiffDecompressorsFactory.Create( @@ -430,7 +423,14 @@ namespace SixLabors.ImageSharp.Formats.Tiff break; } - decompressor.Decompress(this.inputStream, stripOffsets[stripIndex], stripByteCounts[stripIndex], stripHeight, stripBufferSpan); + ulong offset = stripOffsets.GetValue(stripIndex) switch { ulong val => val, Number val => (uint)val }; + ulong count = stripByteCounts.GetValue(stripIndex) switch { ulong val => val, Number val => (uint)val }; + decompressor.Decompress( + this.inputStream, + offset, + count, + stripHeight, + stripBufferSpan); colorDecoder.Decode(stripBufferSpan, pixels, 0, top, frame.Width, stripHeight); } From 04884d56a99da4bf4b2be84d4ada0e85a01f4915 Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Sun, 19 Sep 2021 22:13:23 +0300 Subject: [PATCH 031/121] add 1-bit test files, renaming --- .../Formats/Tiff/BigTiffDecoderTests.cs | 25 +++++++++++++------ tests/ImageSharp.Tests/TestImages.cs | 8 +++--- .../Input/Tiff/BigTiff/BigTIFF_MinIsBlack.tif | 3 +++ .../Tiff/BigTiff/BigTIFF_MinIsBlack_Fax3.tif | 3 --- .../Input/Tiff/BigTiff/BigTIFF_MinIsWhite.tif | 3 +++ 5 files changed, 28 insertions(+), 14 deletions(-) create mode 100644 tests/Images/Input/Tiff/BigTiff/BigTIFF_MinIsBlack.tif delete mode 100644 tests/Images/Input/Tiff/BigTiff/BigTIFF_MinIsBlack_Fax3.tif create mode 100644 tests/Images/Input/Tiff/BigTiff/BigTIFF_MinIsWhite.tif diff --git a/tests/ImageSharp.Tests/Formats/Tiff/BigTiffDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/BigTiffDecoderTests.cs index c00336b25..131310086 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/BigTiffDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/BigTiffDecoderTests.cs @@ -31,6 +31,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff [WithFile(BigTIFFSubIFD8, PixelTypes.Rgba32)] [WithFile(Indexed4_Deflate, PixelTypes.Rgba32)] [WithFile(Indexed8_LZW, PixelTypes.Rgba32)] + [WithFile(MinIsBlack, PixelTypes.Rgba32)] + [WithFile(MinIsWhite, PixelTypes.Rgba32)] public void TiffDecoder_CanDecode(TestImageProvider provider) where TPixel : unmanaged, IPixel => TestTiffDecoder(provider); @@ -40,11 +42,19 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff where TPixel : unmanaged, IPixel => Assert.Throws(() => provider.GetImage(TiffDecoder)); [Theory] - [WithFile(MinIsWhite_RLE, PixelTypes.Rgba32)] - [WithFile(MinIsBlack_RLE, PixelTypes.Rgba32)] - [WithFile(MinIsBlack_Fax3, PixelTypes.Rgba32)] - public void ProblemFiles(TestImageProvider provider) - where TPixel : unmanaged, IPixel => Assert.Throws(() => TestTiffDecoder(provider)); + [WithFile(Damaged_MinIsWhite_RLE, PixelTypes.Rgba32)] + [WithFile(Damaged_MinIsBlack_RLE, PixelTypes.Rgba32)] + public void DamagedFiles(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + Assert.Throws(() => TestTiffDecoder(provider)); + + using Image image = provider.GetImage(TiffDecoder); + ExifProfile exif = image.Frames.RootFrame.Metadata.ExifProfile; + + // PhotometricInterpretation is required tag: https://www.awaresystems.be/imaging/tiff/tifftags/photometricinterpretation.html + Assert.Null(exif.GetValueInternal(ExifTag.PhotometricInterpretation)); + } [Theory] [InlineData(BigTIFF, 24, 64, 64, 96, 96, PixelResolutionUnit.PixelsPerInch)] @@ -56,9 +66,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff [InlineData(BigTIFFSubIFD8, 24, 64, 64, 96, 96, PixelResolutionUnit.PixelsPerInch)] [InlineData(Indexed4_Deflate, 4, 64, 64, 96, 96, PixelResolutionUnit.PixelsPerInch)] [InlineData(Indexed8_LZW, 8, 64, 64, 96, 96, PixelResolutionUnit.PixelsPerInch)] - [InlineData(MinIsWhite_RLE, 1, 32, 32, 96, 96, PixelResolutionUnit.PixelsPerInch)] - [InlineData(MinIsBlack_RLE, 1, 32, 32, 96, 96, PixelResolutionUnit.PixelsPerInch)] - [InlineData(MinIsBlack_Fax3, 1, 32, 32, 96, 96, PixelResolutionUnit.PixelsPerInch)] + [InlineData(MinIsWhite, 1, 32, 32, 96, 96, PixelResolutionUnit.PixelsPerInch)] + [InlineData(MinIsBlack, 1, 32, 32, 96, 96, PixelResolutionUnit.PixelsPerInch)] public void Identify(string imagePath, int expectedPixelSize, int expectedWidth, int expectedHeight, double expectedHResolution, double expectedVResolution, PixelResolutionUnit expectedResolutionUnit) { var testFile = TestFile.Create(imagePath); diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 7292d232d..b0e67d669 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -689,9 +689,11 @@ namespace SixLabors.ImageSharp.Tests public const string Indexed4_Deflate = Base + "BigTIFF_Indexed4_Deflate.tif"; public const string Indexed8_LZW = Base + "BigTIFF_Indexed8_LZW.tif"; - public const string MinIsWhite_RLE = Base + "BigTIFF_MinIsWhite_RLE.tif"; - public const string MinIsBlack_RLE = Base + "BigTIFF_MinIsBlack_RLE.tif"; - public const string MinIsBlack_Fax3 = Base + "BigTIFF_MinIsBlack_Fax3.tif"; + public const string MinIsBlack = Base + "BigTIFF_MinIsBlack.tif"; + public const string MinIsWhite = Base + "BigTIFF_MinIsWhite.tif"; + + public const string Damaged_MinIsWhite_RLE = Base + "BigTIFF_MinIsWhite_RLE.tif"; + public const string Damaged_MinIsBlack_RLE = Base + "BigTIFF_MinIsBlack_RLE.tif"; } } } diff --git a/tests/Images/Input/Tiff/BigTiff/BigTIFF_MinIsBlack.tif b/tests/Images/Input/Tiff/BigTiff/BigTIFF_MinIsBlack.tif new file mode 100644 index 000000000..491b4092e --- /dev/null +++ b/tests/Images/Input/Tiff/BigTiff/BigTIFF_MinIsBlack.tif @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ac0471c1600f6e5fb47037dab07172aff524abc866a40c9ec54279bd49cbef77 +size 517 diff --git a/tests/Images/Input/Tiff/BigTiff/BigTIFF_MinIsBlack_Fax3.tif b/tests/Images/Input/Tiff/BigTiff/BigTIFF_MinIsBlack_Fax3.tif deleted file mode 100644 index 952f4fab9..000000000 --- a/tests/Images/Input/Tiff/BigTiff/BigTIFF_MinIsBlack_Fax3.tif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3853a4850a023bce431bc224145f47e095e9910cddce9ba5fcaf496c9d385e04 -size 564 diff --git a/tests/Images/Input/Tiff/BigTiff/BigTIFF_MinIsWhite.tif b/tests/Images/Input/Tiff/BigTiff/BigTIFF_MinIsWhite.tif new file mode 100644 index 000000000..fb26e58a4 --- /dev/null +++ b/tests/Images/Input/Tiff/BigTiff/BigTIFF_MinIsWhite.tif @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a95b0b46bf4f75babb86d9ec74694e6d684087504be214df48a6c8a54338834c +size 517 From 7f1376ffff31c6c0d6d4e8add19e2cfd2fb731e5 Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Sat, 2 Oct 2021 10:29:05 +0300 Subject: [PATCH 032/121] Update src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong8Array.cs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Günther Foidl --- .../Metadata/Profiles/Exif/Values/ExifLong8Array.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong8Array.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong8Array.cs index d012f646b..d76deba07 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong8Array.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong8Array.cs @@ -107,10 +107,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif private bool SetArray(long[] values) { var numbers = new ulong[values.Length]; - for (int i = 0; i < values.Length; i++) - { - numbers[i] = (ulong)values[i]; - } + this.Value = Unsafe.As(ref values); this.Value = numbers; return true; From f95102e340e34cfb5f22fec4c436db8b1321fc4f Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Sat, 2 Oct 2021 10:30:38 +0300 Subject: [PATCH 033/121] Update src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumberArray.cs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Günther Foidl --- src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumberArray.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumberArray.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumberArray.cs index 4b7433d7d..39d1ff049 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumberArray.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumberArray.cs @@ -56,7 +56,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif case int[] array: { // workaround for inconsistent covariance of value-typed arrays - if (value.GetType().Equals(typeof(uint[]))) + if (value.GetType() == typeof(uint[])) { return this.SetArray((uint[])value); } From 22d67f9210e74e9a7d762b49c21d3692ce99e427 Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Sat, 2 Oct 2021 10:30:49 +0300 Subject: [PATCH 034/121] Update src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumberArray.cs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Günther Foidl --- src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumberArray.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumberArray.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumberArray.cs index 39d1ff049..c65e0b460 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumberArray.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumberArray.cs @@ -66,7 +66,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif case short[] array: { - if (value.GetType().Equals(typeof(ushort[]))) + if (value.GetType() == typeof(ushort[])) { return this.SetArray((ushort[])value); } From f0ef4f9d510c516688a982e94453d87ece5b0f19 Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Sat, 2 Oct 2021 10:31:46 +0300 Subject: [PATCH 035/121] Update src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Günther Foidl --- src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs index 9abaf1432..f36f2cbae 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs @@ -150,7 +150,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif this.Seek(offset); int count = this.ReadUInt16(); - Span offsetBuffer = new byte[4]; + Span offsetBuffer = stackalloc byte[4]; for (int i = 0; i < count; i++) { this.ReadValue(values, offsetBuffer); From 02c891134c946ee2326da3c57ffff221c7b19b11 Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Sat, 2 Oct 2021 10:31:54 +0300 Subject: [PATCH 036/121] Update src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Günther Foidl --- src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs index f36f2cbae..d9fe29e82 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs @@ -177,7 +177,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif this.Seek(offset); ulong count = this.ReadUInt64(); - Span offsetBuffer = new byte[8]; + Span offsetBuffer = stackalloc byte[8]; for (ulong i = 0; i < count; i++) { this.ReadValue64(values, offsetBuffer); From d670edcccf25f1778ed61730d2d888153b45c714 Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Sat, 2 Oct 2021 10:59:46 +0300 Subject: [PATCH 037/121] build fixes, minor improves --- .../Profiles/Exif/Values/ExifLong8Array.cs | 15 +++++++-------- .../Profiles/Exif/Values/ExifNumberArray.cs | 4 ++-- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong8Array.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong8Array.cs index d76deba07..618135e92 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong8Array.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong8Array.cs @@ -1,6 +1,8 @@ // 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 @@ -29,9 +31,9 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif return ExifDataType.Long; } - for (int i = 0; i < this.Value.Length; i++) + foreach (ulong value in this.Value) { - if (this.Value[i] > uint.MaxValue) + if (value > uint.MaxValue) { return ExifDataType.Long8; } @@ -64,7 +66,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif case long[] array: { - if (value.GetType().Equals(typeof(ulong[]))) + if (value.GetType() == typeof(ulong[])) { return this.SetArray((ulong[])value); } @@ -74,7 +76,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif case int[] array: { - if (value.GetType().Equals(typeof(uint[]))) + if (value.GetType() == typeof(uint[])) { return this.SetArray((uint[])value); } @@ -84,7 +86,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif case short[] array: { - if (value.GetType().Equals(typeof(ushort[]))) + if (value.GetType() == typeof(ushort[])) { return this.SetArray((ushort[])value); } @@ -106,10 +108,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif private bool SetArray(long[] values) { - var numbers = new ulong[values.Length]; this.Value = Unsafe.As(ref values); - - this.Value = numbers; return true; } diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumberArray.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumberArray.cs index c65e0b460..2d006c538 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumberArray.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumberArray.cs @@ -24,9 +24,9 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif return ExifDataType.Short; } - for (int i = 0; i < this.Value.Length; i++) + foreach (Number value in this.Value) { - if (this.Value[i] > ushort.MaxValue) + if (value > ushort.MaxValue) { return ExifDataType.Long; } From eb8b6f25862da4f405f9f0081d07e0ac2cd6f595 Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Sat, 2 Oct 2021 11:22:57 +0300 Subject: [PATCH 038/121] build fixes --- .../Formats/Tiff/TiffDecoderCore.cs | 32 ++++++++++++++++--- .../Formats/Tiff/TiffThrowHelper.cs | 2 +- .../Profiles/Exif/Values/ExifLong8Array.cs | 2 +- 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs index 6692b7991..9f0a4b514 100644 --- a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs +++ b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs @@ -335,8 +335,20 @@ namespace SixLabors.ImageSharp.Formats.Tiff int stripIndex = i; for (int planeIndex = 0; planeIndex < stripsPerPixel; planeIndex++) { - ulong offset = stripOffsets.GetValue(stripIndex) switch { ulong val => val, Number val => (uint)val }; - ulong count = stripByteCounts.GetValue(stripIndex) switch { ulong val => val, Number val => (uint)val }; + ulong offset = stripOffsets.GetValue(stripIndex) switch + { + ulong val => val, + Number val => (uint)val, + _ => throw TiffThrowHelper.ThrowImageFormatException("Expected Number or Long8 array") + }; + + ulong count = stripByteCounts.GetValue(stripIndex) switch + { + ulong val => val, + Number val => (uint)val, + _ => throw TiffThrowHelper.ThrowImageFormatException("Expected Number or Long8 array") + }; + decompressor.Decompress( this.inputStream, offset, @@ -423,8 +435,20 @@ namespace SixLabors.ImageSharp.Formats.Tiff break; } - ulong offset = stripOffsets.GetValue(stripIndex) switch { ulong val => val, Number val => (uint)val }; - ulong count = stripByteCounts.GetValue(stripIndex) switch { ulong val => val, Number val => (uint)val }; + ulong offset = stripOffsets.GetValue(stripIndex) switch + { + ulong val => val, + Number val => (uint)val, + _ => throw TiffThrowHelper.ThrowImageFormatException("Expected Number or Long8 array") + }; + + ulong count = stripByteCounts.GetValue(stripIndex) switch + { + ulong val => val, + Number val => (uint)val, + _ => throw TiffThrowHelper.ThrowImageFormatException("Expected Number or Long8 array") + }; + decompressor.Decompress( this.inputStream, offset, diff --git a/src/ImageSharp/Formats/Tiff/TiffThrowHelper.cs b/src/ImageSharp/Formats/Tiff/TiffThrowHelper.cs index 3c541a786..8223c445a 100644 --- a/src/ImageSharp/Formats/Tiff/TiffThrowHelper.cs +++ b/src/ImageSharp/Formats/Tiff/TiffThrowHelper.cs @@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff /// /// The error message for the exception. [MethodImpl(MethodImplOptions.NoInlining)] - public static void ThrowImageFormatException(string errorMessage) => throw new ImageFormatException(errorMessage); + public static Exception ThrowImageFormatException(string errorMessage) => throw new ImageFormatException(errorMessage); [MethodImpl(InliningOptions.ColdPath)] public static Exception NotSupportedDecompressor(string compressionType) => throw new NotSupportedException($"Not supported decoder compression method: {compressionType}"); diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong8Array.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong8Array.cs index 618135e92..d75e68565 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong8Array.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong8Array.cs @@ -31,7 +31,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif return ExifDataType.Long; } - foreach (ulong value in this.Value) + foreach (ulong value in this.Value) { if (value > uint.MaxValue) { From dfcb74305b7a04e328ca7241d57105d4ba9f91a0 Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Sat, 2 Oct 2021 19:51:06 +0300 Subject: [PATCH 039/121] Add long8 tests --- .../Profiles/Exif/Values/ExifLong8.cs | 13 +++ .../Profiles/Exif/Values/ExifLong8Array.cs | 3 + .../Formats/Tiff/BigTiffDecoderTests.cs | 7 +- .../Formats/Tiff/BigTiffMetadataTests.cs | 90 +++++++++++++++++++ 4 files changed, 108 insertions(+), 5 deletions(-) create mode 100644 tests/ImageSharp.Tests/Formats/Tiff/BigTiffMetadataTests.cs diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong8.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong8.cs index 47da962f3..a4a1dd3df 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong8.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong8.cs @@ -35,6 +35,18 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif 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) { @@ -44,6 +56,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif return false; default: + return false; } } diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong8Array.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong8Array.cs index d75e68565..3d14709a4 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong8Array.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong8Array.cs @@ -64,6 +64,9 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif 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[])) diff --git a/tests/ImageSharp.Tests/Formats/Tiff/BigTiffDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/BigTiffDecoderTests.cs index 131310086..24fce1d0d 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/BigTiffDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/BigTiffDecoderTests.cs @@ -3,22 +3,19 @@ // ReSharper disable InconsistentNaming using System; -using System.Linq; using System.IO; +using System.Linq; using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.Metadata.Profiles.Exif; using SixLabors.ImageSharp.PixelFormats; - +using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; using Xunit; - using static SixLabors.ImageSharp.Tests.TestImages.BigTiff; -using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; namespace SixLabors.ImageSharp.Tests.Formats.Tiff { [Collection("RunSerial")] [Trait("Format", "Tiff")] - [Trait("Format", "BigTiff")] public class BigTiffDecoderTests : TiffDecoderBaseTester { [Theory] diff --git a/tests/ImageSharp.Tests/Formats/Tiff/BigTiffMetadataTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/BigTiffMetadataTests.cs new file mode 100644 index 000000000..91cfa1efa --- /dev/null +++ b/tests/ImageSharp.Tests/Formats/Tiff/BigTiffMetadataTests.cs @@ -0,0 +1,90 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.Formats.Tiff; +using SixLabors.ImageSharp.Metadata.Profiles.Exif; + +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Formats.Tiff +{ + [Trait("Format", "Tiff")] + public class BigTiffMetadataTests + { + private static TiffDecoder TiffDecoder => new TiffDecoder(); + + [Fact] + public void ExifLong8() + { + var long8 = new ExifLong8(ExifTagValue.StripByteCounts); + + Assert.True(long8.TrySetValue(0)); + Assert.Equal(0UL, long8.GetValue()); + + Assert.True(long8.TrySetValue(100u)); + Assert.Equal(100UL, long8.GetValue()); + + Assert.True(long8.TrySetValue(ulong.MaxValue)); + Assert.Equal(ulong.MaxValue, long8.GetValue()); + + Assert.False(long8.TrySetValue(-65)); + Assert.Equal(ulong.MaxValue, long8.GetValue()); + } + + [Fact] + public void ExifSignedLong8() + { + var long8 = new ExifSignedLong8(ExifTagValue.ImageID); + + Assert.False(long8.TrySetValue(0)); + + Assert.True(long8.TrySetValue(0L)); + Assert.Equal(0L, long8.GetValue()); + + Assert.True(long8.TrySetValue(-100L)); + Assert.Equal(-100L, long8.GetValue()); + + Assert.True(long8.TrySetValue(100L)); + Assert.Equal(100L, long8.GetValue()); + } + + [Fact] + public void ExifLong8Array() + { + var long8 = new ExifLong8Array(ExifTagValue.StripOffsets); + + Assert.True(long8.TrySetValue((short)-123)); + Assert.Equal(new[] { 0UL }, long8.GetValue()); + + Assert.True(long8.TrySetValue((ushort)123)); + Assert.Equal(new[] { 123UL }, long8.GetValue()); + + Assert.True(long8.TrySetValue((short)123)); + Assert.Equal(new[] { 123UL }, long8.GetValue()); + + Assert.True(long8.TrySetValue(123)); + Assert.Equal(new[] { 123UL }, long8.GetValue()); + + Assert.True(long8.TrySetValue(123L)); + Assert.Equal(new[] { 123UL }, long8.GetValue()); + + Assert.True(long8.TrySetValue(123UL)); + Assert.Equal(new[] { 123UL }, long8.GetValue()); + + Assert.True(long8.TrySetValue(new[] { 1, 2, 3, 4 })); + Assert.Equal(new[] { 1UL, 2UL, 3UL, 4UL }, long8.GetValue()); + } + + [Fact] + public void ExifSignedLong8Array() + { + var long8 = new ExifSignedLong8Array(ExifTagValue.StripOffsets); + + Assert.True(long8.TrySetValue(new[] { 0L })); + Assert.Equal(new[] { 0L }, long8.GetValue()); + + Assert.True(long8.TrySetValue(new[] { -1L, 2L, -3L, 4L })); + Assert.Equal(new[] { -1L, 2L, -3L, 4L }, long8.GetValue()); + } + } +} From 7185a24baf78ca39ab38be437adfaaf19701bda5 Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Sat, 2 Oct 2021 20:15:06 +0300 Subject: [PATCH 040/121] minor --- .../Profiles/Exif/Values/ExifLong8Array.cs | 14 ++++++-------- .../Profiles/Exif/Values/ExifNumberArray.cs | 14 ++++++-------- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong8Array.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong8Array.cs index 3d14709a4..366eb8d12 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong8Array.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong8Array.cs @@ -26,16 +26,14 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif { get { - if (this.Value is null) + if (this.Value is not null) { - return ExifDataType.Long; - } - - foreach (ulong value in this.Value) - { - if (value > uint.MaxValue) + foreach (ulong value in this.Value) { - return ExifDataType.Long8; + if (value > uint.MaxValue) + { + return ExifDataType.Long8; + } } } diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumberArray.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumberArray.cs index 2d006c538..bf9c2cf9a 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumberArray.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumberArray.cs @@ -19,16 +19,14 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif { get { - if (this.Value is null) + if (this.Value is not null) { - return ExifDataType.Short; - } - - foreach (Number value in this.Value) - { - if (value > ushort.MaxValue) + foreach (Number value in this.Value) { - return ExifDataType.Long; + if (value > ushort.MaxValue) + { + return ExifDataType.Long; + } } } From 775f43e754f88c337ffbfe690c229d09d83b98a8 Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Sat, 2 Oct 2021 20:33:14 +0300 Subject: [PATCH 041/121] Add Number tests --- .../Profiles/Exif/Values/ExifValuesTests.cs | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/Exif/Values/ExifValuesTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/Exif/Values/ExifValuesTests.cs index 3358b1f97..3871ac61c 100644 --- a/tests/ImageSharp.Tests/Metadata/Profiles/Exif/Values/ExifValuesTests.cs +++ b/tests/ImageSharp.Tests/Metadata/Profiles/Exif/Values/ExifValuesTests.cs @@ -394,6 +394,32 @@ namespace SixLabors.ImageSharp.Tests.Metadata.Profiles.Exif.Values Assert.Equal(expected, typed.Value); } + [Fact] + public void NumberTests() + { + Number value1 = ushort.MaxValue; + Number value2 = ushort.MaxValue; + Assert.True(value1 == value2); + + value2 = short.MaxValue; + Assert.True(value1 != value2); + + value2 = -2; + Assert.True(value1 > value2); + + value1 = -6; + Assert.True(value1 <= value2); + + value2 = -2; + Assert.True(value1 >= value2); + + Assert.True(value1.Equals(value2)); + Assert.True(value1.GetHashCode() == value2.GetHashCode()); + + value1 = 1; + Assert.False(value1.Equals(value2)); + } + [Theory] [MemberData(nameof(NumberTags))] public void ExifNumberTests(ExifTag tag) @@ -422,6 +448,15 @@ namespace SixLabors.ImageSharp.Tests.Metadata.Profiles.Exif.Values var typed = (ExifNumberArray)value; Assert.Equal(expected, typed.Value); + + Assert.True(value.TrySetValue(int.MaxValue)); + Assert.Equal(new[] { int.MaxValue }, value.GetValue()); + + Assert.True(value.TrySetValue(new[] { 1u, 2u, 5u })); + Assert.Equal(new[] { 1u, 2u, 5u }, value.GetValue()); + + Assert.True(value.TrySetValue(new[] { (short)1, (short)2, (short)5 })); + Assert.Equal(new[] { (short)1, (short)2, (short)5 }, value.GetValue()); } [Theory] From 02d83c9bd240062d67e94ee3b4d99971d22c2274 Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Sat, 2 Oct 2021 20:38:53 +0300 Subject: [PATCH 042/121] minor --- .../Metadata/Profiles/Exif/ExifReader.cs | 30 ++++++++++--------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs index d9fe29e82..6107bd766 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs @@ -114,6 +114,11 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif protected void ReadBigValues(List values) { + if (this.BigValues.Count == 0) + { + return; + } + ulong maxSize = 0; foreach ((ulong offset, ExifDataType dataType, ulong numberOfComponents, ExifValue exif) in this.BigValues) { @@ -159,14 +164,12 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif protected void ReadSubIfd(List values) { - if (this.subIfds is null) - { - return; - } - - foreach (ulong subIfdOffset in this.subIfds) + if (this.subIfds is not null) { - this.ReadValues(values, (uint)subIfdOffset); + foreach (ulong subIfdOffset in this.subIfds) + { + this.ReadValues(values, (uint)subIfdOffset); + } } } @@ -196,14 +199,12 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif protected void ReadSubIfd64(List values) { - if (this.subIfds is null) - { - return; - } - - foreach (ulong subIfdOffset in this.subIfds) + if (this.subIfds is not null) { - this.ReadValues64(values, subIfdOffset); + foreach (ulong subIfdOffset in this.subIfds) + { + this.ReadValues64(values, subIfdOffset); + } } } @@ -517,6 +518,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif } else if (exif.Tag == ExifTag.SubIFDs) { + //// didn't find any useful data in SubIFDs ////foreach (object val in (Array)value) ////{ //// this.AddSubIfd(val); From 2c06edc07561ebee678747f6546571624a6f9f99 Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Sat, 2 Oct 2021 20:51:54 +0300 Subject: [PATCH 043/121] test fixes --- .../Metadata/Profiles/Exif/Values/ExifValuesTests.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/Exif/Values/ExifValuesTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/Exif/Values/ExifValuesTests.cs index 3871ac61c..341beca5c 100644 --- a/tests/ImageSharp.Tests/Metadata/Profiles/Exif/Values/ExifValuesTests.cs +++ b/tests/ImageSharp.Tests/Metadata/Profiles/Exif/Values/ExifValuesTests.cs @@ -404,13 +404,15 @@ namespace SixLabors.ImageSharp.Tests.Metadata.Profiles.Exif.Values value2 = short.MaxValue; Assert.True(value1 != value2); + value1 = -1; value2 = -2; Assert.True(value1 > value2); value1 = -6; Assert.True(value1 <= value2); - value2 = -2; + value1 = 10; + value2 = 10; Assert.True(value1 >= value2); Assert.True(value1.Equals(value2)); @@ -450,13 +452,13 @@ namespace SixLabors.ImageSharp.Tests.Metadata.Profiles.Exif.Values Assert.Equal(expected, typed.Value); Assert.True(value.TrySetValue(int.MaxValue)); - Assert.Equal(new[] { int.MaxValue }, value.GetValue()); + Assert.Equal(new[] { (Number)int.MaxValue }, value.GetValue()); Assert.True(value.TrySetValue(new[] { 1u, 2u, 5u })); - Assert.Equal(new[] { 1u, 2u, 5u }, value.GetValue()); + Assert.Equal(new[] { (Number)1u, (Number)2u, (Number)5u }, value.GetValue()); Assert.True(value.TrySetValue(new[] { (short)1, (short)2, (short)5 })); - Assert.Equal(new[] { (short)1, (short)2, (short)5 }, value.GetValue()); + Assert.Equal(new[] { (Number)(short)1, (Number)(short)2, (Number)(short)5 }, value.GetValue()); } [Theory] From e277a0dce68bb0f8212a134e012ac16be286e855 Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Fri, 15 Oct 2021 10:46:25 +0300 Subject: [PATCH 044/121] Use MemoryAllocator --- .../Formats/Tiff/Ifd/DirectoryReader.cs | 11 +++- .../Formats/Tiff/Ifd/EntryReader.cs | 9 ++-- .../Formats/Tiff/TiffDecoderCore.cs | 4 +- .../Metadata/Profiles/Exif/ExifReader.cs | 52 +++++++++++++++---- 4 files changed, 56 insertions(+), 20 deletions(-) diff --git a/src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs b/src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs index 6421db8d8..121341b46 100644 --- a/src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs +++ b/src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs @@ -5,6 +5,7 @@ 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 @@ -16,9 +17,15 @@ namespace SixLabors.ImageSharp.Formats.Tiff { private readonly Stream stream; + private readonly MemoryAllocator allocator; + private ulong nextIfdOffset; - public DirectoryReader(Stream stream) => this.stream = stream; + public DirectoryReader(Stream stream, MemoryAllocator allocator) + { + this.stream = stream; + this.allocator = allocator; + } /// /// Gets the byte order. @@ -64,7 +71,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff var readers = new List(); while (this.nextIfdOffset != 0 && this.nextIfdOffset < (ulong)this.stream.Length) { - var reader = new EntryReader(this.stream, this.ByteOrder); + var reader = new EntryReader(this.stream, this.ByteOrder, this.allocator); reader.ReadTags(isBigTiff, this.nextIfdOffset); if (reader.BigValues.Count > 0) diff --git a/src/ImageSharp/Formats/Tiff/Ifd/EntryReader.cs b/src/ImageSharp/Formats/Tiff/Ifd/EntryReader.cs index 98cc1deb3..ef614b0e2 100644 --- a/src/ImageSharp/Formats/Tiff/Ifd/EntryReader.cs +++ b/src/ImageSharp/Formats/Tiff/Ifd/EntryReader.cs @@ -5,17 +5,16 @@ 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 { - public EntryReader(Stream stream, ByteOrder byteOrder) - : base(stream) - { + public EntryReader(Stream stream, ByteOrder byteOrder, MemoryAllocator allocator) + : base(stream, allocator) => this.IsBigEndian = byteOrder == ByteOrder.BigEndian; - } public List Values { get; } = new List(); @@ -45,7 +44,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff internal class HeaderReader : BaseExifReader { public HeaderReader(Stream stream, ByteOrder byteOrder) - : base(stream) => + : base(stream, null) => this.IsBigEndian = byteOrder == ByteOrder.BigEndian; public bool IsBigTiff { get; private set; } diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs index 9f0a4b514..98adc5183 100644 --- a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs +++ b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs @@ -147,7 +147,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff where TPixel : unmanaged, IPixel { this.inputStream = stream; - var reader = new DirectoryReader(stream); + var reader = new DirectoryReader(stream, this.Configuration.MemoryAllocator); IEnumerable directories = reader.Read(); this.byteOrder = reader.ByteOrder; @@ -181,7 +181,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff public IImageInfo Identify(BufferedReadStream stream, CancellationToken cancellationToken) { this.inputStream = stream; - var reader = new DirectoryReader(stream); + var reader = new DirectoryReader(stream, this.Configuration.MemoryAllocator); IEnumerable directories = reader.Read(); ExifProfile rootFrameExifProfile = directories.First(); diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs index 6107bd766..0633d3715 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers; using System.Buffers.Binary; using System.Collections.Generic; using System.Collections.ObjectModel; @@ -9,13 +10,19 @@ using System.Diagnostics; using System.IO; using System.Runtime.CompilerServices; using System.Text; +using SixLabors.ImageSharp.Memory; namespace SixLabors.ImageSharp.Metadata.Profiles.Exif { internal class ExifReader : BaseExifReader { public ExifReader(byte[] exifData) - : base(new MemoryStream(exifData ?? throw new ArgumentNullException(nameof(exifData)))) + : this(exifData, null) + { + } + + public ExifReader(byte[] exifData, MemoryAllocator allocator) + : base(new MemoryStream(exifData ?? throw new ArgumentNullException(nameof(exifData))), allocator) { } @@ -83,13 +90,17 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif private readonly byte[] buf4 = new byte[4]; private readonly byte[] buf2 = new byte[2]; + private readonly MemoryAllocator allocator; private readonly Stream data; private List invalidTags; private List subIfds; - protected BaseExifReader(Stream stream) => + protected BaseExifReader(Stream stream, MemoryAllocator allocator) + { this.data = stream ?? throw new ArgumentNullException(nameof(stream)); + this.allocator = allocator; + } private delegate TDataType ConverterMethod(ReadOnlySpan data); @@ -110,7 +121,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif public bool IsBigEndian { get; protected set; } - public List<(ulong offset, ExifDataType dataType, ulong numberOfComponents, ExifValue exif)> BigValues { get; } = new (); + public List<(ulong offset, ExifDataType dataType, ulong numberOfComponents, ExifValue exif)> BigValues { get; } = new(); protected void ReadBigValues(List values) { @@ -119,22 +130,41 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif return; } - ulong maxSize = 0; + int maxSize = 0; foreach ((ulong offset, ExifDataType dataType, ulong numberOfComponents, ExifValue exif) in this.BigValues) { ulong size = numberOfComponents * ExifDataTypes.GetSize(dataType); - if (size > maxSize) + if (size > int.MaxValue) + { + ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThanOrEqualTo(size, int.MaxValue, nameof(size)); + } + + if ((int)size > maxSize) { - maxSize = size; + maxSize = (int)size; } } - Span buf = new byte[maxSize]; - foreach ((ulong offset, ExifDataType dataType, ulong numberOfComponents, ExifValue exif) tag in this.BigValues) + if (this.allocator != null) { - ulong size = tag.numberOfComponents * ExifDataTypes.GetSize(tag.dataType); - - this.ReadBigValue(values, tag, buf.Slice(0, (int)size)); + // tiff, bigTiff + using IMemoryOwner memory = this.allocator.Allocate(maxSize); + Span buf = memory.GetSpan(); + foreach ((ulong offset, ExifDataType dataType, ulong numberOfComponents, ExifValue exif) tag in this.BigValues) + { + ulong size = tag.numberOfComponents * ExifDataTypes.GetSize(tag.dataType); + this.ReadBigValue(values, tag, buf.Slice(0, (int)size)); + } + } + else + { + // embedded exif + Span buf = maxSize <= 256 ? stackalloc byte[maxSize] : new byte[maxSize]; + foreach ((ulong offset, ExifDataType dataType, ulong numberOfComponents, ExifValue exif) tag in this.BigValues) + { + ulong size = tag.numberOfComponents * ExifDataTypes.GetSize(tag.dataType); + this.ReadBigValue(values, tag, buf.Slice(0, (int)size)); + } } this.BigValues.Clear(); From d4784cb683be9bfa072f89b38cd4cfd58ed1d473 Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Fri, 15 Oct 2021 11:22:13 +0300 Subject: [PATCH 045/121] correct casings --- .../Metadata/Profiles/Exif/ExifReader.cs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs index 0633d3715..fbc3b5c8b 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs @@ -121,7 +121,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif public bool IsBigEndian { get; protected set; } - public List<(ulong offset, ExifDataType dataType, ulong numberOfComponents, ExifValue exif)> BigValues { get; } = new(); + public List<(ulong Offset, ExifDataType DataType, ulong NumberOfComponents, ExifValue Exif)> BigValues { get; } = new(); protected void ReadBigValues(List values) { @@ -150,9 +150,9 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif // tiff, bigTiff using IMemoryOwner memory = this.allocator.Allocate(maxSize); Span buf = memory.GetSpan(); - foreach ((ulong offset, ExifDataType dataType, ulong numberOfComponents, ExifValue exif) tag in this.BigValues) + foreach ((ulong Offset, ExifDataType DataType, ulong NumberOfComponents, ExifValue Exif) tag in this.BigValues) { - ulong size = tag.numberOfComponents * ExifDataTypes.GetSize(tag.dataType); + ulong size = tag.NumberOfComponents * ExifDataTypes.GetSize(tag.DataType); this.ReadBigValue(values, tag, buf.Slice(0, (int)size)); } } @@ -160,9 +160,9 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif { // embedded exif Span buf = maxSize <= 256 ? stackalloc byte[maxSize] : new byte[maxSize]; - foreach ((ulong offset, ExifDataType dataType, ulong numberOfComponents, ExifValue exif) tag in this.BigValues) + foreach ((ulong Offset, ExifDataType DataType, ulong NumberOfComponents, ExifValue Exif) tag in this.BigValues) { - ulong size = tag.numberOfComponents * ExifDataTypes.GetSize(tag.dataType); + ulong size = tag.NumberOfComponents * ExifDataTypes.GetSize(tag.DataType); this.ReadBigValue(values, tag, buf.Slice(0, (int)size)); } } @@ -217,13 +217,13 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif } } - protected void ReadBigValue(IList values, (ulong offset, ExifDataType dataType, ulong numberOfComponents, ExifValue exif) tag, Span buffer) + protected void ReadBigValue(IList values, (ulong Offset, ExifDataType DataType, ulong NumberOfComponents, ExifValue Exif) tag, Span buffer) { - this.Seek(tag.offset); + this.Seek(tag.Offset); if (this.TryReadSpan(buffer)) { - object value = this.ConvertValue(tag.dataType, buffer, tag.numberOfComponents > 1 || tag.exif.IsArray); - this.Add(values, tag.exif, value); + object value = this.ConvertValue(tag.DataType, buffer, tag.NumberOfComponents > 1 || tag.Exif.IsArray); + this.Add(values, tag.Exif, value); } } From c6478426a3520fd894bd416f7637e4b51137fe35 Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Fri, 15 Oct 2021 14:19:52 +0300 Subject: [PATCH 046/121] Update src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs --- src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs index fbc3b5c8b..1a39d723a 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs @@ -159,7 +159,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif else { // embedded exif - Span buf = maxSize <= 256 ? stackalloc byte[maxSize] : new byte[maxSize]; + Span buf = maxSize <= 256 ? stackalloc byte[256] : new byte[maxSize]; foreach ((ulong Offset, ExifDataType DataType, ulong NumberOfComponents, ExifValue Exif) tag in this.BigValues) { ulong size = tag.NumberOfComponents * ExifDataTypes.GetSize(tag.DataType); From c8974ab4f45096e4ed8c0a63edaa9e1b2bf480bd Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Fri, 15 Oct 2021 14:34:39 +0300 Subject: [PATCH 047/121] build fixes --- src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs b/src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs index 121341b46..02035265d 100644 --- a/src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs +++ b/src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs @@ -76,10 +76,10 @@ namespace SixLabors.ImageSharp.Formats.Tiff if (reader.BigValues.Count > 0) { - reader.BigValues.Sort((t1, t2) => t1.offset.CompareTo(t2.offset)); + reader.BigValues.Sort((t1, t2) => t1.Offset.CompareTo(t2.Offset)); // this means that most likely all elements are placed before next IFD - if (reader.BigValues[0].offset < reader.NextIfdOffset) + if (reader.BigValues[0].Offset < reader.NextIfdOffset) { reader.ReadBigValues(); } From 4f10036f144b22ca4015c88f7ca028e55726bc98 Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Wed, 27 Oct 2021 08:55:49 +0300 Subject: [PATCH 048/121] skipping SubIfd64 (disable SubIfd64 related code) --- .../Formats/Tiff/Ifd/EntryReader.cs | 2 +- .../Metadata/Profiles/Exif/ExifReader.cs | 38 +++++++++---------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/ImageSharp/Formats/Tiff/Ifd/EntryReader.cs b/src/ImageSharp/Formats/Tiff/Ifd/EntryReader.cs index ee7315a7b..58b042e84 100644 --- a/src/ImageSharp/Formats/Tiff/Ifd/EntryReader.cs +++ b/src/ImageSharp/Formats/Tiff/Ifd/EntryReader.cs @@ -33,7 +33,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff this.ReadValues64(this.Values, ifdOffset); this.NextIfdOffset = this.ReadUInt64(); - this.ReadSubIfd64(this.Values); + //// this.ReadSubIfd64(this.Values); } } diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs index 1a39d723a..bb8e6b9f3 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs @@ -227,16 +227,16 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif } } - protected void ReadSubIfd64(List values) - { - if (this.subIfds is not null) - { - foreach (ulong subIfdOffset in this.subIfds) - { - this.ReadValues64(values, subIfdOffset); - } - } - } + ////protected void ReadSubIfd64(List values) + ////{ + //// if (this.subIfds is not null) + //// { + //// foreach (ulong subIfdOffset in this.subIfds) + //// { + //// this.ReadValues64(values, subIfdOffset); + //// } + //// } + ////} private static TDataType[] ToArray(ExifDataType dataType, ReadOnlySpan data, ConverterMethod converter) { @@ -482,15 +482,15 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif case ExifTagValue.TileByteCounts: exifValue = new ExifLong8Array(ExifTagValue.TileByteCounts); break; - case ExifTagValue.SubIFDOffset: - exifValue = new ExifLong8(ExifTagValue.SubIFDOffset); - break; - case ExifTagValue.GPSIFDOffset: - exifValue = new ExifLong8(ExifTagValue.GPSIFDOffset); - break; - case ExifTagValue.SubIFDs: - exifValue = new ExifLong8Array(ExifTagValue.SubIFDs); - break; + ////case ExifTagValue.SubIFDOffset: + //// exifValue = new ExifLong8(ExifTagValue.SubIFDOffset); + //// break; + ////case ExifTagValue.GPSIFDOffset: + //// exifValue = new ExifLong8(ExifTagValue.GPSIFDOffset); + //// break; + ////case ExifTagValue.SubIFDs: + //// exifValue = new ExifLong8Array(ExifTagValue.SubIFDs); + //// break; default: exifValue = ExifValues.Create(tag) ?? ExifValues.Create(tag, dataType, numberOfComponents); break; From e66145e2d6ea89acd5eb4b6a9431ae0e65789fab Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Wed, 27 Oct 2021 09:59:40 +0300 Subject: [PATCH 049/121] webp test fix --- .../ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs index e20ad5136..3ee20cbd1 100644 --- a/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs +++ b/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs @@ -187,7 +187,7 @@ namespace SixLabors.ImageSharp.Tests.Metadata.Profiles.Exif https://exiftool.org/TagNames/EXIF.html */ [InlineData(TestImageWriteFormat.Jpeg, 18)] [InlineData(TestImageWriteFormat.Png, 18)] - [InlineData(TestImageWriteFormat.WebpLossless, 16)] + [InlineData(TestImageWriteFormat.WebpLossless, 18)] public void SetValue(TestImageWriteFormat imageFormat, int expectedProfileValueCount) { Image image = TestFile.Create(TestImages.Jpeg.Baseline.Floorplan).CreateRgba32Image(); From 831501bc3254ed9f4e7018c8aecc41cbcbb187be Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Wed, 27 Oct 2021 10:31:54 +0300 Subject: [PATCH 050/121] comment unused code --- .../Metadata/Profiles/Exif/ExifReader.cs | 37 +++++++++---------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs index bb8e6b9f3..651ebe422 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs @@ -134,10 +134,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif foreach ((ulong offset, ExifDataType dataType, ulong numberOfComponents, ExifValue exif) in this.BigValues) { ulong size = numberOfComponents * ExifDataTypes.GetSize(dataType); - if (size > int.MaxValue) - { - ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThanOrEqualTo(size, int.MaxValue, nameof(size)); - } + DebugGuard.MustBeLessThanOrEqualTo(size, int.MaxValue, nameof(size)); if ((int)size > maxSize) { @@ -361,13 +358,13 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif } return ToArray(dataType, buffer, this.ConvertToUInt64); - case ExifDataType.SignedLong8: - if (!isArray) - { - return this.ConvertToInt64(buffer); - } + ////case ExifDataType.SignedLong8: + //// if (!isArray) + //// { + //// return this.ConvertToInt64(buffer); + //// } - return ToArray(dataType, buffer, this.ConvertToUInt64); + //// return ToArray(dataType, buffer, this.ConvertToUInt64); case ExifDataType.Undefined: if (!isArray) { @@ -596,17 +593,17 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif ? this.ConvertToShort(this.buf2) : default; - private long ConvertToInt64(ReadOnlySpan buffer) - { - if (buffer.Length < 8) - { - return default; - } + ////private long ConvertToInt64(ReadOnlySpan buffer) + ////{ + //// if (buffer.Length < 8) + //// { + //// return default; + //// } - return this.IsBigEndian - ? BinaryPrimitives.ReadInt64BigEndian(buffer) - : BinaryPrimitives.ReadInt64LittleEndian(buffer); - } + //// return this.IsBigEndian + //// ? BinaryPrimitives.ReadInt64BigEndian(buffer) + //// : BinaryPrimitives.ReadInt64LittleEndian(buffer); + ////} private ulong ConvertToUInt64(ReadOnlySpan buffer) { From 6e25e2f87e41551e0bb8934fc65cfcfca3e2976e Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Wed, 27 Oct 2021 11:26:56 +0300 Subject: [PATCH 051/121] improve coverage --- .../Tiff/Compression/TiffBaseDecompressor.cs | 6 ++--- .../Formats/Tiff/TiffDecoderCore.cs | 5 +--- .../Profiles/Exif/Values/ExifLong8Array.cs | 17 +++++++------- .../Formats/Tiff/BigTiffMetadataTests.cs | 23 +++++++++++++++---- 4 files changed, 31 insertions(+), 20 deletions(-) diff --git a/src/ImageSharp/Formats/Tiff/Compression/TiffBaseDecompressor.cs b/src/ImageSharp/Formats/Tiff/Compression/TiffBaseDecompressor.cs index d5de4937f..986d585d3 100644 --- a/src/ImageSharp/Formats/Tiff/Compression/TiffBaseDecompressor.cs +++ b/src/ImageSharp/Formats/Tiff/Compression/TiffBaseDecompressor.cs @@ -36,10 +36,8 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression /// The output buffer for uncompressed data. public void Decompress(BufferedReadStream stream, ulong stripOffset, ulong stripByteCount, int stripHeight, Span buffer) { - if (stripOffset > long.MaxValue || stripByteCount > long.MaxValue) - { - TiffThrowHelper.ThrowImageFormatException("The StripOffset or StripByteCount value is too big."); - } + DebugGuard.MustBeLessThanOrEqualTo(stripOffset, (ulong)long.MaxValue, nameof(stripOffset)); + DebugGuard.MustBeLessThanOrEqualTo(stripByteCount, (ulong)long.MaxValue, nameof(stripByteCount)); stream.Seek((long)stripOffset, SeekOrigin.Begin); this.Decompress(stream, (int)stripByteCount, stripHeight, buffer); diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs index 98adc5183..419fbc31c 100644 --- a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs +++ b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs @@ -473,10 +473,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff TiffThrowHelper.ThrowImageFormatException("The TIFF image frame is missing the ImageWidth"); } - if (((ulong)width.Value) > int.MaxValue) - { - TiffThrowHelper.ThrowImageFormatException("Too big ImageWidth value"); - } + DebugGuard.MustBeLessThanOrEqualTo((ulong)width.Value, (ulong)int.MaxValue, nameof(ExifTag.ImageWidth)); return (int)width.Value; } diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong8Array.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong8Array.cs index 366eb8d12..eced4e3de 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong8Array.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong8Array.cs @@ -7,11 +7,6 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif { internal sealed class ExifLong8Array : ExifArrayValue { - public ExifLong8Array(ExifTag tag) - : base(tag) - { - } - public ExifLong8Array(ExifTagValue tag) : base(tag) { @@ -109,7 +104,13 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif private bool SetArray(long[] values) { - this.Value = Unsafe.As(ref 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; } @@ -124,7 +125,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif var numbers = new ulong[values.Length]; for (int i = 0; i < values.Length; i++) { - numbers[i] = (ulong)values[i]; + numbers[i] = (ulong)Numerics.Clamp(values[i], 0, int.MaxValue); } this.Value = numbers; @@ -148,7 +149,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif var numbers = new ulong[values.Length]; for (int i = 0; i < values.Length; i++) { - numbers[i] = (ulong)values[i]; + numbers[i] = (ulong)Numerics.Clamp(values[i], 0, short.MaxValue); } this.Value = numbers; diff --git a/tests/ImageSharp.Tests/Formats/Tiff/BigTiffMetadataTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/BigTiffMetadataTests.cs index 91cfa1efa..8e90aeea1 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/BigTiffMetadataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/BigTiffMetadataTests.cs @@ -43,9 +43,11 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff Assert.True(long8.TrySetValue(-100L)); Assert.Equal(-100L, long8.GetValue()); + Assert.Equal(ExifDataType.SignedLong8, long8.DataType); - Assert.True(long8.TrySetValue(100L)); - Assert.Equal(100L, long8.GetValue()); + Assert.True(long8.TrySetValue(long.MaxValue)); + Assert.Equal(long.MaxValue, long8.GetValue()); + Assert.Equal(ExifDataType.SignedLong8, long8.DataType); } [Fact] @@ -65,14 +67,25 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff Assert.True(long8.TrySetValue(123)); Assert.Equal(new[] { 123UL }, long8.GetValue()); + Assert.True(long8.TrySetValue(123u)); + Assert.Equal(new[] { 123UL }, long8.GetValue()); + Assert.True(long8.TrySetValue(123L)); Assert.Equal(new[] { 123UL }, long8.GetValue()); Assert.True(long8.TrySetValue(123UL)); Assert.Equal(new[] { 123UL }, long8.GetValue()); + Assert.True(long8.TrySetValue(new short[] { -1, 2, -3, 4 })); + Assert.Equal(new ulong[] { 0, 2UL, 0, 4UL }, long8.GetValue()); + Assert.True(long8.TrySetValue(new[] { 1, 2, 3, 4 })); Assert.Equal(new[] { 1UL, 2UL, 3UL, 4UL }, long8.GetValue()); + Assert.Equal(ExifDataType.Long, long8.DataType); + + Assert.True(long8.TrySetValue(new[] { 1, 2, 3, 4, long.MaxValue })); + Assert.Equal(new[] { 1UL, 2UL, 3UL, 4UL, (ulong)long.MaxValue }, long8.GetValue()); + Assert.Equal(ExifDataType.Long8, long8.DataType); } [Fact] @@ -82,9 +95,11 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff Assert.True(long8.TrySetValue(new[] { 0L })); Assert.Equal(new[] { 0L }, long8.GetValue()); + Assert.Equal(ExifDataType.SignedLong8, long8.DataType); - Assert.True(long8.TrySetValue(new[] { -1L, 2L, -3L, 4L })); - Assert.Equal(new[] { -1L, 2L, -3L, 4L }, long8.GetValue()); + Assert.True(long8.TrySetValue(new[] { -1L, 2L, long.MinValue, 4L })); + Assert.Equal(new[] { -1L, 2L, long.MinValue, 4L }, long8.GetValue()); + Assert.Equal(ExifDataType.SignedLong8, long8.DataType); } } } From 0e3fada06abef8ed1314ba61540d2e4f0211c99c Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Wed, 27 Oct 2021 15:55:51 +0300 Subject: [PATCH 052/121] rework number/ulong arrays --- .../Formats/Tiff/TiffDecoderCore.cs | 85 ++++++++++--------- 1 file changed, 47 insertions(+), 38 deletions(-) diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs index 419fbc31c..177a93d24 100644 --- a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs +++ b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs @@ -219,21 +219,57 @@ namespace SixLabors.ImageSharp.Formats.Tiff int rowsPerStrip = tags.GetValue(ExifTag.RowsPerStrip) != null ? (int)tags.GetValue(ExifTag.RowsPerStrip).Value : TiffConstants.RowsPerStripInfinity; - var stripOffsets = (Array)tags.GetValueInternal(ExifTag.StripOffsets)?.GetValue(); - var stripByteCounts = (Array)tags.GetValueInternal(ExifTag.StripByteCounts)?.GetValue(); + var stripOffsetsArray = (Array)tags.GetValueInternal(ExifTag.StripOffsets).GetValue(); + var stripByteCountsArray = (Array)tags.GetValueInternal(ExifTag.StripByteCounts).GetValue(); + + IMemoryOwner stripOffsetsMemory = this.ConvertNumbers(stripOffsetsArray, out Span stripOffsets); + IMemoryOwner stripByteCountsMemory = this.ConvertNumbers(stripByteCountsArray, out Span stripByteCounts); if (this.PlanarConfiguration == TiffPlanarConfiguration.Planar) { - this.DecodeStripsPlanar(frame, rowsPerStrip, stripOffsets, stripByteCounts, cancellationToken); + this.DecodeStripsPlanar( + frame, + rowsPerStrip, + stripOffsets, + stripByteCounts, + cancellationToken); } else { - this.DecodeStripsChunky(frame, rowsPerStrip, stripOffsets, stripByteCounts, cancellationToken); + this.DecodeStripsChunky( + frame, + rowsPerStrip, + stripOffsets, + stripByteCounts, + cancellationToken); } + stripOffsetsMemory?.Dispose(); + stripByteCountsMemory?.Dispose(); return frame; } + private IMemoryOwner ConvertNumbers(Array array, out Span span) + { + if (array is Number[] numbers) + { + IMemoryOwner memory = this.memoryAllocator.Allocate(numbers.Length); + span = memory.GetSpan(); + for (int i = 0; i < numbers.Length; i++) + { + span[i] = (uint)numbers[i]; + } + + return memory; + } + else + { + DebugGuard.IsTrue(array is ulong[], $"Expected {nameof(UInt64)} array."); + span = (ulong[])array; + return null; + } + } + /// /// Calculates the size (in bytes) for a pixel buffer using the determined color format. /// @@ -284,7 +320,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff /// An array of byte offsets to each strip in the image. /// An array of the size of each strip (in bytes). /// The token to monitor cancellation. - private void DecodeStripsPlanar(ImageFrame frame, int rowsPerStrip, Array stripOffsets, Array stripByteCounts, CancellationToken cancellationToken) + private void DecodeStripsPlanar(ImageFrame frame, int rowsPerStrip, Span stripOffsets, Span stripByteCounts, CancellationToken cancellationToken) where TPixel : unmanaged, IPixel { int stripsPerPixel = this.BitsPerSample.Channels; @@ -335,26 +371,13 @@ namespace SixLabors.ImageSharp.Formats.Tiff int stripIndex = i; for (int planeIndex = 0; planeIndex < stripsPerPixel; planeIndex++) { - ulong offset = stripOffsets.GetValue(stripIndex) switch - { - ulong val => val, - Number val => (uint)val, - _ => throw TiffThrowHelper.ThrowImageFormatException("Expected Number or Long8 array") - }; - - ulong count = stripByteCounts.GetValue(stripIndex) switch - { - ulong val => val, - Number val => (uint)val, - _ => throw TiffThrowHelper.ThrowImageFormatException("Expected Number or Long8 array") - }; - decompressor.Decompress( this.inputStream, - offset, - count, + stripOffsets[stripIndex], + stripByteCounts[stripIndex], stripHeight, stripBuffers[planeIndex].GetSpan()); + stripIndex += stripsPerPlane; } @@ -379,7 +402,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff /// The strip offsets. /// The strip byte counts. /// The token to monitor cancellation. - private void DecodeStripsChunky(ImageFrame frame, int rowsPerStrip, Array stripOffsets, Array stripByteCounts, CancellationToken cancellationToken) + private void DecodeStripsChunky(ImageFrame frame, int rowsPerStrip, Span stripOffsets, Span stripByteCounts, CancellationToken cancellationToken) where TPixel : unmanaged, IPixel { // If the rowsPerStrip has the default value, which is effectively infinity. That is, the entire image is one strip. @@ -435,24 +458,10 @@ namespace SixLabors.ImageSharp.Formats.Tiff break; } - ulong offset = stripOffsets.GetValue(stripIndex) switch - { - ulong val => val, - Number val => (uint)val, - _ => throw TiffThrowHelper.ThrowImageFormatException("Expected Number or Long8 array") - }; - - ulong count = stripByteCounts.GetValue(stripIndex) switch - { - ulong val => val, - Number val => (uint)val, - _ => throw TiffThrowHelper.ThrowImageFormatException("Expected Number or Long8 array") - }; - decompressor.Decompress( this.inputStream, - offset, - count, + stripOffsets[stripIndex], + stripByteCounts[stripIndex], stripHeight, stripBufferSpan); From 0f4bc33c60958f22700491de1d94977cf4b3d75c Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Sat, 27 Nov 2021 12:05:32 +0300 Subject: [PATCH 053/121] Add exif tag tests --- .../Formats/Tiff/BigTiffMetadataTests.cs | 66 ++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) diff --git a/tests/ImageSharp.Tests/Formats/Tiff/BigTiffMetadataTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/BigTiffMetadataTests.cs index 8e90aeea1..b81ddce4d 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/BigTiffMetadataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/BigTiffMetadataTests.cs @@ -1,10 +1,15 @@ // 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; +using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.Metadata.Profiles.Exif; - +using SixLabors.ImageSharp.PixelFormats; using Xunit; +using static SixLabors.ImageSharp.Tests.TestImages.Tiff; namespace SixLabors.ImageSharp.Tests.Formats.Tiff { @@ -101,5 +106,64 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff Assert.Equal(new[] { -1L, 2L, long.MinValue, 4L }, long8.GetValue()); Assert.Equal(ExifDataType.SignedLong8, long8.DataType); } + + [Theory] + [WithFile(RgbUncompressed, PixelTypes.Rgb24)] + public void ExifTags(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using Image input = provider.GetImage(); + + var testTags = new Dictionary + { + { new ExifTag((ExifTagValue)0xdd01), (ExifDataType.SingleFloat, new float[] { 1.2f, 2.3f, 4.5f }) }, + { new ExifTag((ExifTagValue)0xdd02), (ExifDataType.DoubleFloat, new double[] { 4.5, 6.7 }) }, + { new ExifTag((ExifTagValue)0xdd03), (ExifDataType.DoubleFloat, 8.903) }, + { new ExifTag((ExifTagValue)0xdd04), (ExifDataType.SignedByte, (sbyte)-3) }, + { new ExifTag((ExifTagValue)0xdd05), (ExifDataType.SignedByte, new sbyte[] { -3, 0, 5 }) }, + { new ExifTag((ExifTagValue)0xdd06), (ExifDataType.SignedLong, new int[] { int.MinValue, 1, int.MaxValue }) }, + { new ExifTag((ExifTagValue)0xdd07), (ExifDataType.Long, new uint[] { 0, 1, uint.MaxValue }) }, + { new ExifTag((ExifTagValue)0xdd08), (ExifDataType.Short, (ushort)1234) }, + //{ new ExifTag((ExifTagValue)0xdd09), (ExifDataType.Long8, ulong.MaxValue) }, + }; + + // arrange + var values = new List(); + foreach (KeyValuePair tag in testTags) + { + ExifValue newExifValue = ExifValues.Create((ExifTagValue)(ushort)tag.Key, tag.Value.DataType, tag.Value.Value is Array); + + Assert.True(newExifValue.TrySetValue(tag.Value.Value)); + values.Add(newExifValue); + } + + input.Frames.RootFrame.Metadata.ExifProfile = new ExifProfile(values, Array.Empty()); + + // act + var encoder = new TiffEncoder(); + using var memStream = new MemoryStream(); + input.Save(memStream, encoder); + + // assert + memStream.Position = 0; + using var output = Image.Load(memStream); + ImageFrameMetadata loadedFrameMetadata = output.Frames.RootFrame.Metadata; + foreach (KeyValuePair tag in testTags) + { + IExifValue exifValue = loadedFrameMetadata.ExifProfile.GetValueInternal(tag.Key); + Assert.NotNull(exifValue); + object value = exifValue.GetValue(); + + Assert.Equal(tag.Value.DataType, exifValue.DataType); + if (value is Array array) + { + Assert.Equal(array, tag.Value.Value as Array); + } + else + { + Assert.Equal(value, tag.Value.Value); + } + } + } } } From 494ca166cb1833ee139f2bc7968d8f87b0b4ee26 Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Sat, 27 Nov 2021 12:33:43 +0300 Subject: [PATCH 054/121] cleanup --- tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderBaseTester.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderBaseTester.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderBaseTester.cs index ff70eaf8a..aeadae255 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderBaseTester.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderBaseTester.cs @@ -8,8 +8,6 @@ using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; using SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs; -using Xunit; - namespace SixLabors.ImageSharp.Tests.Formats.Tiff { public abstract class TiffDecoderBaseTester From 6aee72308a1cbb88c3f5e9f112996db399cf5f9c Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Sat, 27 Nov 2021 14:21:52 +0300 Subject: [PATCH 055/121] Enable long8 read/write methods, add tests --- .../Metadata/Profiles/Exif/ExifReader.cs | 32 ++--- .../Metadata/Profiles/Exif/ExifWriter.cs | 18 +++ .../Formats/Tiff/BigTiffMetadataTests.cs | 132 +++++++++++++++--- .../Profiles/Exif/Values/ExifValuesTests.cs | 3 + 4 files changed, 150 insertions(+), 35 deletions(-) diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs index 651ebe422..4fcac5299 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs @@ -358,13 +358,13 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif } return ToArray(dataType, buffer, this.ConvertToUInt64); - ////case ExifDataType.SignedLong8: - //// if (!isArray) - //// { - //// return this.ConvertToInt64(buffer); - //// } + case ExifDataType.SignedLong8: + if (!isArray) + { + return this.ConvertToInt64(buffer); + } - //// return ToArray(dataType, buffer, this.ConvertToUInt64); + return ToArray(dataType, buffer, this.ConvertToUInt64); case ExifDataType.Undefined: if (!isArray) { @@ -593,17 +593,17 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif ? this.ConvertToShort(this.buf2) : default; - ////private long ConvertToInt64(ReadOnlySpan buffer) - ////{ - //// if (buffer.Length < 8) - //// { - //// return default; - //// } + private long ConvertToInt64(ReadOnlySpan buffer) + { + if (buffer.Length < 8) + { + return default; + } - //// return this.IsBigEndian - //// ? BinaryPrimitives.ReadInt64BigEndian(buffer) - //// : BinaryPrimitives.ReadInt64LittleEndian(buffer); - ////} + return this.IsBigEndian + ? BinaryPrimitives.ReadInt64BigEndian(buffer) + : BinaryPrimitives.ReadInt64LittleEndian(buffer); + } private ulong ConvertToUInt64(ReadOnlySpan buffer) { diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifWriter.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifWriter.cs index e7a01b070..498eec952 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/ExifWriter.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifWriter.cs @@ -150,6 +150,20 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif return offset + 4; } + private static int WriteInt64(long value, Span destination, int offset) + { + BinaryPrimitives.WriteInt64LittleEndian(destination.Slice(offset, 8), value); + + return offset + 8; + } + + private static int WriteUInt64(ulong value, Span destination, int offset) + { + BinaryPrimitives.WriteUInt64LittleEndian(destination.Slice(offset, 8), value); + + return offset + 8; + } + private static int WriteInt32(int value, Span destination, int offset) { BinaryPrimitives.WriteInt32LittleEndian(destination.Slice(offset, 4), value); @@ -390,6 +404,10 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif } return WriteUInt32((uint)value, destination, offset); + case ExifDataType.Long8: + return WriteUInt64((ulong)value, destination, offset); + case ExifDataType.SignedLong8: + return WriteInt64((long)value, destination, offset); case ExifDataType.Rational: WriteRational(destination.Slice(offset, 8), (Rational)value); return offset + 8; diff --git a/tests/ImageSharp.Tests/Formats/Tiff/BigTiffMetadataTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/BigTiffMetadataTests.cs index b81ddce4d..cdeb789de 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/BigTiffMetadataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/BigTiffMetadataTests.cs @@ -2,22 +2,21 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers.Binary; using System.Collections.Generic; using System.IO; using SixLabors.ImageSharp.Formats.Tiff; +using SixLabors.ImageSharp.Formats.Tiff.Writers; using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.Metadata.Profiles.Exif; using SixLabors.ImageSharp.PixelFormats; using Xunit; -using static SixLabors.ImageSharp.Tests.TestImages.Tiff; namespace SixLabors.ImageSharp.Tests.Formats.Tiff { [Trait("Format", "Tiff")] public class BigTiffMetadataTests { - private static TiffDecoder TiffDecoder => new TiffDecoder(); - [Fact] public void ExifLong8() { @@ -107,24 +106,27 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff Assert.Equal(ExifDataType.SignedLong8, long8.DataType); } - [Theory] - [WithFile(RgbUncompressed, PixelTypes.Rgb24)] - public void ExifTags(TestImageProvider provider) - where TPixel : unmanaged, IPixel + [Fact] + public void NotCoveredTags() { - using Image input = provider.GetImage(); + using var input = new Image(10, 10); var testTags = new Dictionary { { new ExifTag((ExifTagValue)0xdd01), (ExifDataType.SingleFloat, new float[] { 1.2f, 2.3f, 4.5f }) }, - { new ExifTag((ExifTagValue)0xdd02), (ExifDataType.DoubleFloat, new double[] { 4.5, 6.7 }) }, - { new ExifTag((ExifTagValue)0xdd03), (ExifDataType.DoubleFloat, 8.903) }, - { new ExifTag((ExifTagValue)0xdd04), (ExifDataType.SignedByte, (sbyte)-3) }, - { new ExifTag((ExifTagValue)0xdd05), (ExifDataType.SignedByte, new sbyte[] { -3, 0, 5 }) }, - { new ExifTag((ExifTagValue)0xdd06), (ExifDataType.SignedLong, new int[] { int.MinValue, 1, int.MaxValue }) }, - { new ExifTag((ExifTagValue)0xdd07), (ExifDataType.Long, new uint[] { 0, 1, uint.MaxValue }) }, - { new ExifTag((ExifTagValue)0xdd08), (ExifDataType.Short, (ushort)1234) }, - //{ new ExifTag((ExifTagValue)0xdd09), (ExifDataType.Long8, ulong.MaxValue) }, + { new ExifTag((ExifTagValue)0xdd02), (ExifDataType.SingleFloat, 2.345f) }, + { new ExifTag((ExifTagValue)0xdd03), (ExifDataType.DoubleFloat, new double[] { 4.5, 6.7 }) }, + { new ExifTag((ExifTagValue)0xdd04), (ExifDataType.DoubleFloat, 8.903) }, + { new ExifTag((ExifTagValue)0xdd05), (ExifDataType.SignedByte, (sbyte)-3) }, + { new ExifTag((ExifTagValue)0xdd06), (ExifDataType.SignedByte, new sbyte[] { -3, 0, 5 }) }, + { new ExifTag((ExifTagValue)0xdd07), (ExifDataType.SignedLong, new int[] { int.MinValue, 1, int.MaxValue }) }, + { new ExifTag((ExifTagValue)0xdd08), (ExifDataType.Long, new uint[] { 0, 1, uint.MaxValue }) }, + { new ExifTag((ExifTagValue)0xdd09), (ExifDataType.SignedShort, (short)-1234) }, + { new ExifTag((ExifTagValue)0xdd10), (ExifDataType.Short, (ushort)1234) }, + ////{ new ExifTag((ExifTagValue)0xdd11), (ExifDataType.Long8, ulong.MaxValue) }, + ////{ new ExifTag((ExifTagValue)0xdd12), (ExifDataType.SignedLong8, long.MaxValue) }, + ////{ new ExifTag((ExifTagValue)0xdd13), (ExifDataType.Long8, new ulong[] { 0, 1234, 56789UL, ulong.MaxValue }) }, + ////{ new ExifTag((ExifTagValue)0xdd14), (ExifDataType.SignedLong8, new long[] { -1234, 56789L, long.MaxValue }) }, }; // arrange @@ -155,15 +157,107 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff object value = exifValue.GetValue(); Assert.Equal(tag.Value.DataType, exifValue.DataType); - if (value is Array array) { - Assert.Equal(array, tag.Value.Value as Array); + Assert.Equal(value, tag.Value.Value); } - else + } + } + + [Fact] + public void NotCoveredTags64() + { + var testTags = new Dictionary + { + { new ExifTag((ExifTagValue)0xdd11), (ExifDataType.Long8, ulong.MaxValue) }, + { new ExifTag((ExifTagValue)0xdd12), (ExifDataType.SignedLong8, long.MaxValue) }, + ////{ new ExifTag((ExifTagValue)0xdd13), (ExifDataType.Long8, new ulong[] { 0, 1234, 56789UL, ulong.MaxValue }) }, + ////{ new ExifTag((ExifTagValue)0xdd14), (ExifDataType.SignedLong8, new long[] { -1234, 56789L, long.MaxValue }) }, + }; + + var values = new List(); + foreach (KeyValuePair tag in testTags) + { + ExifValue newExifValue = ExifValues.Create((ExifTagValue)(ushort)tag.Key, tag.Value.DataType, tag.Value.Value is Array); + + Assert.True(newExifValue.TrySetValue(tag.Value.Value)); + values.Add(newExifValue); + } + + // act + byte[] inputBytes = WriteIfd64(values); + Configuration config = Configuration.Default; + var reader = new EntryReader( + new MemoryStream(inputBytes), + BitConverter.IsLittleEndian ? ByteOrder.LittleEndian : ByteOrder.BigEndian, + config.MemoryAllocator); + + reader.ReadTags(true, 0); + + List outputTags = reader.Values; + + // assert + foreach (KeyValuePair tag in testTags) + { + IExifValue exifValue = outputTags.Find(t => t.Tag == tag.Key); + Assert.NotNull(exifValue); + object value = exifValue.GetValue(); + + Assert.Equal(tag.Value.DataType, exifValue.DataType); { Assert.Equal(value, tag.Value.Value); } } } + + private static byte[] WriteIfd64(List values) + { + byte[] buffer = new byte[8]; + var ms = new MemoryStream(); + var writer = new TiffStreamWriter(ms); + WriteLong8(writer, buffer, (ulong)values.Count); + + foreach (IExifValue entry in values) + { + writer.Write((ushort)entry.Tag); + writer.Write((ushort)entry.DataType); + WriteLong8(writer, buffer, ExifWriter.GetNumberOfComponents(entry)); + + uint length = ExifWriter.GetLength(entry); + + Assert.True(length <= 8); + + if (length <= 8) + { + int sz = ExifWriter.WriteValue(entry, buffer, 0); + DebugGuard.IsTrue(sz == length, "Incorrect number of bytes written"); + + // write padded + writer.BaseStream.Write(buffer.AsSpan(0, sz)); + int d = sz % 8; + if (d != 0) + { + writer.BaseStream.Write(new byte[d]); + } + } + } + + WriteLong8(writer, buffer, 0); + + return ms.ToArray(); + } + + private static void WriteLong8(TiffStreamWriter writer, byte[] buffer, ulong value) + { + if (writer.IsLittleEndian) + { + BinaryPrimitives.WriteUInt64LittleEndian(buffer, value); + } + else + { + BinaryPrimitives.WriteUInt64BigEndian(buffer, value); + } + + writer.BaseStream.Write(buffer); + } } } diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/Exif/Values/ExifValuesTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/Exif/Values/ExifValuesTests.cs index 341beca5c..a5ca115d4 100644 --- a/tests/ImageSharp.Tests/Metadata/Profiles/Exif/Values/ExifValuesTests.cs +++ b/tests/ImageSharp.Tests/Metadata/Profiles/Exif/Values/ExifValuesTests.cs @@ -436,6 +436,9 @@ namespace SixLabors.ImageSharp.Tests.Metadata.Profiles.Exif.Values var typed = (ExifNumber)value; Assert.Equal(expected, typed.Value); + + typed.Value = ushort.MaxValue + 1; + Assert.True(expected < typed.Value); } [Theory] From 8c61c8064c7219aa24b48d3397d87d3077259b2b Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Sat, 27 Nov 2021 14:55:19 +0300 Subject: [PATCH 056/121] cleanup --- .../Formats/Tiff/BigTiffMetadataTests.cs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/tests/ImageSharp.Tests/Formats/Tiff/BigTiffMetadataTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/BigTiffMetadataTests.cs index cdeb789de..1493060d5 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/BigTiffMetadataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/BigTiffMetadataTests.cs @@ -123,10 +123,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff { new ExifTag((ExifTagValue)0xdd08), (ExifDataType.Long, new uint[] { 0, 1, uint.MaxValue }) }, { new ExifTag((ExifTagValue)0xdd09), (ExifDataType.SignedShort, (short)-1234) }, { new ExifTag((ExifTagValue)0xdd10), (ExifDataType.Short, (ushort)1234) }, - ////{ new ExifTag((ExifTagValue)0xdd11), (ExifDataType.Long8, ulong.MaxValue) }, - ////{ new ExifTag((ExifTagValue)0xdd12), (ExifDataType.SignedLong8, long.MaxValue) }, - ////{ new ExifTag((ExifTagValue)0xdd13), (ExifDataType.Long8, new ulong[] { 0, 1234, 56789UL, ulong.MaxValue }) }, - ////{ new ExifTag((ExifTagValue)0xdd14), (ExifDataType.SignedLong8, new long[] { -1234, 56789L, long.MaxValue }) }, }; // arrange @@ -164,12 +160,13 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff } [Fact] - public void NotCoveredTags64() + public void NotCoveredTags64bit() { var testTags = new Dictionary { { new ExifTag((ExifTagValue)0xdd11), (ExifDataType.Long8, ulong.MaxValue) }, { new ExifTag((ExifTagValue)0xdd12), (ExifDataType.SignedLong8, long.MaxValue) }, + //// WriteIfdTags64Bit: arrays aren't support ////{ new ExifTag((ExifTagValue)0xdd13), (ExifDataType.Long8, new ulong[] { 0, 1234, 56789UL, ulong.MaxValue }) }, ////{ new ExifTag((ExifTagValue)0xdd14), (ExifDataType.SignedLong8, new long[] { -1234, 56789L, long.MaxValue }) }, }; @@ -184,7 +181,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff } // act - byte[] inputBytes = WriteIfd64(values); + byte[] inputBytes = WriteIfdTags64Bit(values); Configuration config = Configuration.Default; var reader = new EntryReader( new MemoryStream(inputBytes), @@ -209,7 +206,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff } } - private static byte[] WriteIfd64(List values) + private static byte[] WriteIfdTags64Bit(List values) { byte[] buffer = new byte[8]; var ms = new MemoryStream(); From 2c12c78e83bff820cb974302030ad5eff712fd29 Mon Sep 17 00:00:00 2001 From: "WINDEV2110EVAL\\User" Date: Sun, 5 Dec 2021 15:20:03 -0800 Subject: [PATCH 057/121] Added support for loading exif data from pre-2017 pngs from the "raw profile type exif" text chunk. --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 104 +++++++++++++++++- .../Formats/Png/PngDecoderTests.cs | 19 ++++ tests/ImageSharp.Tests/TestImages.cs | 3 + .../Input/Png/raw-profile-type-exif.png | 3 + 4 files changed, 124 insertions(+), 5 deletions(-) create mode 100644 tests/Images/Input/Png/raw-profile-type-exif.png diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index cf3cd7eb1..82fc5e815 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -112,6 +112,11 @@ namespace SixLabors.ImageSharp.Formats.Png /// private PngChunk? nextChunk; + /// + /// "Exif" and two zero bytes. Used for the legacy exif parsing. + /// + private static readonly byte[] ExifHeader = new byte[] { 0x45, 0x78, 0x69, 0x66, 0x00, 0x00 }; + /// /// Initializes a new instance of the class. /// @@ -182,7 +187,7 @@ namespace SixLabors.ImageSharp.Formats.Png this.ReadTextChunk(pngMetadata, chunk.Data.GetSpan()); break; case PngChunkType.CompressedText: - this.ReadCompressedTextChunk(pngMetadata, chunk.Data.GetSpan()); + this.ReadCompressedTextChunk(metadata, pngMetadata, chunk.Data.GetSpan()); break; case PngChunkType.InternationalText: this.ReadInternationalTextChunk(pngMetadata, chunk.Data.GetSpan()); @@ -192,7 +197,7 @@ namespace SixLabors.ImageSharp.Formats.Png { var exifData = new byte[chunk.Length]; chunk.Data.GetSpan().CopyTo(exifData); - metadata.ExifProfile = new ExifProfile(exifData); + this.MergeOrSetExifProfile(metadata, new ExifProfile(exifData), replaceExistingKeys: true); } break; @@ -255,7 +260,7 @@ namespace SixLabors.ImageSharp.Formats.Png this.ReadTextChunk(pngMetadata, chunk.Data.GetSpan()); break; case PngChunkType.CompressedText: - this.ReadCompressedTextChunk(pngMetadata, chunk.Data.GetSpan()); + this.ReadCompressedTextChunk(metadata, pngMetadata, chunk.Data.GetSpan()); break; case PngChunkType.InternationalText: this.ReadInternationalTextChunk(pngMetadata, chunk.Data.GetSpan()); @@ -265,7 +270,7 @@ namespace SixLabors.ImageSharp.Formats.Png { var exifData = new byte[chunk.Length]; chunk.Data.GetSpan().CopyTo(exifData); - metadata.ExifProfile = new ExifProfile(exifData); + this.MergeOrSetExifProfile(metadata, new ExifProfile(exifData), replaceExistingKeys: true); } break; @@ -937,9 +942,10 @@ namespace SixLabors.ImageSharp.Formats.Png /// /// Reads the compressed text chunk. Contains a uncompressed keyword and a compressed text string. /// + /// The object. /// The metadata to decode to. /// The containing the data. - private void ReadCompressedTextChunk(PngMetadata metadata, ReadOnlySpan data) + private void ReadCompressedTextChunk(ImageMetadata baseMetadata, PngMetadata metadata, ReadOnlySpan data) { if (this.ignoreMetadata) { @@ -971,6 +977,94 @@ namespace SixLabors.ImageSharp.Formats.Png { metadata.TextData.Add(new PngTextData(name, uncompressed, string.Empty, string.Empty)); } + + if (name.Equals("Raw profile type exif", StringComparison.OrdinalIgnoreCase)) + { + this.ReadLegacyExifTextChunk(baseMetadata, uncompressed); + } + } + + /// + /// Reads exif data encoded into a text chunk with the name "raw profile type exif". + /// This method was used by ImageMagick, exiftool, exiv2, digiKam, etc, before the + /// 2017 update to png that allowed a true exif chunk. We load + /// + /// The to store the decoded exif tags into. + /// The contents of the "raw profile type exif" text chunk. + private void ReadLegacyExifTextChunk(ImageMetadata metadata, string data) + { + ReadOnlySpan dataSpan = data.AsSpan(); + dataSpan = dataSpan.TrimStart(); + + if (!dataSpan.Slice(0, 4).ToString().Equals("exif", StringComparison.OrdinalIgnoreCase)) + { + // "exif" identifier is missing from the beginning of the text chunk + return; + } + + // Skip to the data length + dataSpan = dataSpan.Slice(4).TrimStart(); + int dataLengthEnd = dataSpan.IndexOf('\n'); + int dataLength = int.Parse(dataSpan.Slice(0, dataSpan.IndexOf('\n')).ToString()); + + // Skip to the hex-encoded data + dataSpan = dataSpan.Slice(dataLengthEnd).Trim(); + string dataSpanString = dataSpan.ToString().Replace("\n", string.Empty); + if (dataSpanString.Length != (dataLength * 2)) + { + // Invalid length + return; + } + + // Parse the hex-encoded data into the byte array we are going to hand off to ExifProfile + byte[] dataBlob = new byte[dataLength - ExifHeader.Length]; + for (int i = 0; i < dataLength; i++) + { + byte parsed = Convert.ToByte(dataSpanString.Substring(i * 2, 2), 16); + if (i < ExifHeader.Length) + { + if (parsed != ExifHeader[i]) + { + // Invalid exif header in the actual data blob + return; + } + } + else + { + dataBlob[i - ExifHeader.Length] = parsed; + } + } + + this.MergeOrSetExifProfile(metadata, new ExifProfile(dataBlob), replaceExistingKeys: false); + } + + /// + /// Sets the in to , + /// or copies exif tags if already contains an . + /// + /// The to store the exif data in. + /// The to copy exif tags from. + /// If already contains an , + /// controls whether existing exif tags in will be overwritten with any conflicting + /// tags from . + private void MergeOrSetExifProfile(ImageMetadata metadata, ExifProfile newProfile, bool replaceExistingKeys) + { + if (metadata.ExifProfile is null) + { + // No exif metadata was loaded yet, so just assign it + metadata.ExifProfile = newProfile; + } + else + { + // Try to merge existing keys with the ones from the new profile + foreach (IExifValue newKey in newProfile.Values) + { + if (replaceExistingKeys || metadata.ExifProfile.GetValueInternal(newKey.Tag) is null) + { + metadata.ExifProfile.SetValueInternal(newKey.Tag, newKey.GetValue()); + } + } + } } /// diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs index 9fc4d03dd..215cd14a1 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs @@ -444,5 +444,24 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png "Disco") .Dispose(); } + + [Theory] + [WithFile(TestImages.Png.Issue1875, PixelTypes.Rgba32)] + public void PngDecoder_CanDecode_LegacyTextExifChunk(TestImageProvider provider) + { + using Image image = provider.GetImage(PngDecoder); + + Assert.Equal(0, image.Metadata.ExifProfile.InvalidTags.Count); + Assert.Equal(3, image.Metadata.ExifProfile.Values.Count); + + Assert.Equal( + "A colorful tiling of blue, red, yellow, and green 4x4 pixel blocks.", + image.Metadata.ExifProfile.GetValue(ImageSharp.Metadata.Profiles.Exif.ExifTag.ImageDescription).Value); + Assert.Equal( + "Duplicated from basn3p02.png, then image metadata modified with exiv2", + image.Metadata.ExifProfile.GetValue(ImageSharp.Metadata.Profiles.Exif.ExifTag.ImageHistory).Value); + + Assert.Equal(42, (int)image.Metadata.ExifProfile.GetValue(ImageSharp.Metadata.Profiles.Exif.ExifTag.ImageNumber).Value); + } } } diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index e00364913..41e5e15d3 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -117,6 +117,9 @@ namespace SixLabors.ImageSharp.Tests // Issue 1765: https://github.com/SixLabors/ImageSharp/issues/1765 public const string Issue1765_Net6DeflateStreamRead = "Png/issues/Issue_1765_Net6DeflateStreamRead.png"; + // Discussion 1875: https://github.com/SixLabors/ImageSharp/discussions/1875 + public const string Issue1875 = "Png/raw-profile-type-exif.png"; + public static class Bad { public const string MissingDataChunk = "Png/xdtn0g01.png"; diff --git a/tests/Images/Input/Png/raw-profile-type-exif.png b/tests/Images/Input/Png/raw-profile-type-exif.png new file mode 100644 index 000000000..efd9b35aa --- /dev/null +++ b/tests/Images/Input/Png/raw-profile-type-exif.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2259b08fd0c4681ecd068244df358b486f5eca1fcd18edbc7d9207eeef3ca5ed +size 392 From d5ddc4696e851d93569e7b9c356691b386993ca2 Mon Sep 17 00:00:00 2001 From: "WINDEV2110EVAL\\User" Date: Sun, 5 Dec 2021 15:57:05 -0800 Subject: [PATCH 058/121] Fixed an incomplete comment --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 82fc5e815..042bcb92b 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -987,7 +987,7 @@ namespace SixLabors.ImageSharp.Formats.Png /// /// Reads exif data encoded into a text chunk with the name "raw profile type exif". /// This method was used by ImageMagick, exiftool, exiv2, digiKam, etc, before the - /// 2017 update to png that allowed a true exif chunk. We load + /// 2017 update to png that allowed a true exif chunk. /// /// The to store the decoded exif tags into. /// The contents of the "raw profile type exif" text chunk. From c8a191d2968fe2ed61302e35675f449317435150 Mon Sep 17 00:00:00 2001 From: jubilant-enigma <54286000+jubilant-enigma@users.noreply.github.com> Date: Mon, 6 Dec 2021 10:18:14 -0800 Subject: [PATCH 059/121] Update src/ImageSharp/Formats/Png/PngDecoderCore.cs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Günther Foidl --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 042bcb92b..6db2328f5 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -115,7 +115,8 @@ namespace SixLabors.ImageSharp.Formats.Png /// /// "Exif" and two zero bytes. Used for the legacy exif parsing. /// - private static readonly byte[] ExifHeader = new byte[] { 0x45, 0x78, 0x69, 0x66, 0x00, 0x00 }; + // This uses C# compiler's optimization to refer to the static data directly, no intermediate array allocations happen. + private static ReadOnlySpan ExifHeader => new byte[] { 0x45, 0x78, 0x69, 0x66, 0x00, 0x00 }; /// /// Initializes a new instance of the class. From 7f4c9cdd8fd337d13e27c79bb045928ccb2fd70b Mon Sep 17 00:00:00 2001 From: jubilant-enigma <54286000+jubilant-enigma@users.noreply.github.com> Date: Mon, 6 Dec 2021 10:33:08 -0800 Subject: [PATCH 060/121] Update src/ImageSharp/Formats/Png/PngDecoderCore.cs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Günther Foidl --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 6db2328f5..a08242e68 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -1022,7 +1022,7 @@ namespace SixLabors.ImageSharp.Formats.Png for (int i = 0; i < dataLength; i++) { byte parsed = Convert.ToByte(dataSpanString.Substring(i * 2, 2), 16); - if (i < ExifHeader.Length) + if ((uint)i < (uint)ExifHeader.Length) { if (parsed != ExifHeader[i]) { From 8b9c334bca8f9363893d54235ec5f883c4dc5777 Mon Sep 17 00:00:00 2001 From: "WINDEV2110EVAL\\User" Date: Mon, 6 Dec 2021 12:58:02 -0800 Subject: [PATCH 061/121] Moved the ExifHeader property to after the constructor to satisfy StyleCop. --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index a08242e68..5a18826d1 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -112,12 +112,6 @@ namespace SixLabors.ImageSharp.Formats.Png /// private PngChunk? nextChunk; - /// - /// "Exif" and two zero bytes. Used for the legacy exif parsing. - /// - // This uses C# compiler's optimization to refer to the static data directly, no intermediate array allocations happen. - private static ReadOnlySpan ExifHeader => new byte[] { 0x45, 0x78, 0x69, 0x66, 0x00, 0x00 }; - /// /// Initializes a new instance of the class. /// @@ -130,6 +124,12 @@ namespace SixLabors.ImageSharp.Formats.Png this.ignoreMetadata = options.IgnoreMetadata; } + /// + /// Gets the sequence of bytes for the exif header ("Exif" ASCII and two zero bytes). Used for the legacy exif parsing. + /// + // This uses C# compiler's optimization to refer to the static data directly, no intermediate array allocations happen. + private static ReadOnlySpan ExifHeader => new byte[] { 0x45, 0x78, 0x69, 0x66, 0x00, 0x00 }; + /// public Configuration Configuration { get; } From c2b906ee12262957c1b91d70d89edd9dd4c4d2a5 Mon Sep 17 00:00:00 2001 From: "WINDEV2110EVAL\\User" Date: Mon, 6 Dec 2021 13:04:56 -0800 Subject: [PATCH 062/121] Removed unnecessary temporary allocations. --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 134 +++++++++++++++++-- 1 file changed, 120 insertions(+), 14 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 5a18826d1..236c447ab 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -997,7 +997,7 @@ namespace SixLabors.ImageSharp.Formats.Png ReadOnlySpan dataSpan = data.AsSpan(); dataSpan = dataSpan.TrimStart(); - if (!dataSpan.Slice(0, 4).ToString().Equals("exif", StringComparison.OrdinalIgnoreCase)) + if (!StringEquals(dataSpan.Slice(0, 4), "exif".AsSpan(), StringComparison.OrdinalIgnoreCase)) { // "exif" identifier is missing from the beginning of the text chunk return; @@ -1006,37 +1006,143 @@ namespace SixLabors.ImageSharp.Formats.Png // Skip to the data length dataSpan = dataSpan.Slice(4).TrimStart(); int dataLengthEnd = dataSpan.IndexOf('\n'); - int dataLength = int.Parse(dataSpan.Slice(0, dataSpan.IndexOf('\n')).ToString()); + int dataLength = ParseInt32(dataSpan.Slice(0, dataSpan.IndexOf('\n'))); // Skip to the hex-encoded data dataSpan = dataSpan.Slice(dataLengthEnd).Trim(); - string dataSpanString = dataSpan.ToString().Replace("\n", string.Empty); - if (dataSpanString.Length != (dataLength * 2)) + + if (dataLength < ExifHeader.Length) { - // Invalid length + // Not enough room for the required exif header, this data couldn't possibly be valid return; } // Parse the hex-encoded data into the byte array we are going to hand off to ExifProfile - byte[] dataBlob = new byte[dataLength - ExifHeader.Length]; - for (int i = 0; i < dataLength; i++) + byte[] exifBlob = new byte[dataLength - ExifHeader.Length]; + + try { - byte parsed = Convert.ToByte(dataSpanString.Substring(i * 2, 2), 16); - if ((uint)i < (uint)ExifHeader.Length) + // Check for the presence of the exif header in the hex-encoded binary data + byte[] tempExifBuf = exifBlob; + if (exifBlob.Length < ExifHeader.Length) + { + // Need to allocate a temporary array, this should be an extremely uncommon (TODO: impossible?) case + tempExifBuf = new byte[ExifHeader.Length]; + } + + HexStringToBytes(dataSpan.Slice(0, ExifHeader.Length * 2), tempExifBuf.AsSpan()); + if (!tempExifBuf.AsSpan().Slice(0, ExifHeader.Length).SequenceEqual(ExifHeader)) { - if (parsed != ExifHeader[i]) + // Exif header in the hex data is not valid + return; + } + + // Skip over the exif header we just tested + dataSpan = dataSpan.Slice(ExifHeader.Length * 2); + dataLength -= ExifHeader.Length; + + // Load the hex-encoded data, one line at a time + for (int i = 0; i < dataLength;) + { + ReadOnlySpan lineSpan = dataSpan; + + int newlineIndex = dataSpan.IndexOf('\n'); + if (newlineIndex != -1) { - // Invalid exif header in the actual data blob - return; + lineSpan = dataSpan.Slice(0, newlineIndex); } + + i += HexStringToBytes(lineSpan, exifBlob.AsSpan().Slice(i)); + + dataSpan = dataSpan.Slice(newlineIndex + 1); + } + } + catch + { + return; + } + + this.MergeOrSetExifProfile(metadata, new ExifProfile(exifBlob), replaceExistingKeys: false); + } + + private static bool StringEquals(ReadOnlySpan span1, ReadOnlySpan span2, StringComparison comparisonType) + { +#pragma warning disable IDE0022 // Use expression body for methods +#if NETSTANDARD2_1 || NETCOREAPP2_1_OR_GREATER + return span1.Equals(span2, comparisonType); +#else + return span1.ToString().Equals(span2.ToString(), comparisonType); +#endif +#pragma warning restore IDE0022 // Use expression body for methods + } + + /// + /// int.Parse() a ReadOnlySpan<char>, with a fallback for older frameworks. + /// + /// The to parse. + /// The of the integer to parse. + /// The to use when parsing the integer. + /// The parsed . + private static int ParseInt32( + ReadOnlySpan span, + System.Globalization.NumberStyles style = System.Globalization.NumberStyles.Integer, + IFormatProvider provider = null) + { +#pragma warning disable IDE0022 // Use expression body for methods +#if NETSTANDARD2_1 || NETCOREAPP2_1_OR_GREATER + return int.Parse(span, style, provider); +#else + return int.Parse(span.ToString(), style, provider); +#endif +#pragma warning restore IDE0022 // Use expression body for methods + } + + /// + /// Parses a hexadecimal string into a byte array without allocations. + /// Adapted from https://stackoverflow.com/a/9995303/871842 + /// + /// The hexadecimal string to parse. + /// The destination for the parsed bytes. Must be at least .Length / 2 bytes long. + /// The number of bytes written to . + private static int HexStringToBytes(ReadOnlySpan hexString, Span outputBytes) + { + if ((hexString.Length % 2) != 0) + { + throw new ArgumentException("Input string length must be a multiple of 2", nameof(hexString)); + } + + if ((outputBytes.Length * 2) < hexString.Length) + { + throw new ArgumentException("Output span must be at least half the length of the input string"); + } + + static int GetHexVal(char hexChar) + { + if (hexChar >= '0' && hexChar <= '9') + { + return hexChar - '0'; + } + else if (hexChar >= 'A' && hexChar <= 'F') + { + return 10 + (hexChar - 'A'); + } + else if (hexChar >= 'a' && hexChar <= 'f') + { + return 10 + (hexChar - 'a'); } else { - dataBlob[i - ExifHeader.Length] = parsed; + throw new ArgumentException($"Invalid hexadecimal value {hexChar}"); } } - this.MergeOrSetExifProfile(metadata, new ExifProfile(dataBlob), replaceExistingKeys: false); + int inputByteCount = hexString.Length / 2; + for (int i = 0; i < inputByteCount; i++) + { + outputBytes[i] = (byte)((GetHexVal(hexString[i * 2]) << 4) + GetHexVal(hexString[(i * 2) + 1])); + } + + return inputByteCount; } /// From c8e2902be2e1ad4e271e316b36e946eaa2d35e43 Mon Sep 17 00:00:00 2001 From: "WINDEV2110EVAL\\User" Date: Mon, 6 Dec 2021 13:14:35 -0800 Subject: [PATCH 063/121] Moved legacy exif data loading test from PngDecoderTests to PngMetadataTests. --- .../Formats/Png/PngDecoderTests.cs | 19 -------------- .../Formats/Png/PngMetadataTests.cs | 26 +++++++++++++++++++ 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs index 215cd14a1..9fc4d03dd 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs @@ -444,24 +444,5 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png "Disco") .Dispose(); } - - [Theory] - [WithFile(TestImages.Png.Issue1875, PixelTypes.Rgba32)] - public void PngDecoder_CanDecode_LegacyTextExifChunk(TestImageProvider provider) - { - using Image image = provider.GetImage(PngDecoder); - - Assert.Equal(0, image.Metadata.ExifProfile.InvalidTags.Count); - Assert.Equal(3, image.Metadata.ExifProfile.Values.Count); - - Assert.Equal( - "A colorful tiling of blue, red, yellow, and green 4x4 pixel blocks.", - image.Metadata.ExifProfile.GetValue(ImageSharp.Metadata.Profiles.Exif.ExifTag.ImageDescription).Value); - Assert.Equal( - "Duplicated from basn3p02.png, then image metadata modified with exiv2", - image.Metadata.ExifProfile.GetValue(ImageSharp.Metadata.Profiles.Exif.ExifTag.ImageHistory).Value); - - Assert.Equal(42, (int)image.Metadata.ExifProfile.GetValue(ImageSharp.Metadata.Profiles.Exif.ExifTag.ImageNumber).Value); - } } } diff --git a/tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs index b4307af5d..d763d2ba0 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs @@ -289,5 +289,31 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png Assert.Contains(meta.TextData, m => m.Keyword is "NoLang" && m.Value is "this text chunk is missing a language tag"); Assert.Contains(meta.TextData, m => m.Keyword is "NoTranslatedKeyword" && m.Value is "dieser chunk hat kein übersetztes Schlüßelwort"); } + + [Theory] + [InlineData(TestImages.Png.Issue1875)] + public void Identify_ReadsLegacyExifData(string imagePath) + { + var testFile = TestFile.Create(imagePath); + using (var stream = new MemoryStream(testFile.Bytes, false)) + { + IImageInfo imageInfo = Image.Identify(stream); + Assert.NotNull(imageInfo); + Assert.NotNull(imageInfo.Metadata.ExifProfile); + ExifProfile exif = imageInfo.Metadata.ExifProfile; + + Assert.Equal(0, exif.InvalidTags.Count); + Assert.Equal(3, exif.Values.Count); + + Assert.Equal( + "A colorful tiling of blue, red, yellow, and green 4x4 pixel blocks.", + exif.GetValue(ExifTag.ImageDescription).Value); + Assert.Equal( + "Duplicated from basn3p02.png, then image metadata modified with exiv2", + exif.GetValue(ExifTag.ImageHistory).Value); + + Assert.Equal(42, (int)exif.GetValue(ExifTag.ImageNumber).Value); + } + } } } From 0c65e13a4ec6becac842f3fda5c4bca92913f97a Mon Sep 17 00:00:00 2001 From: "WINDEV2110EVAL\\User" Date: Mon, 6 Dec 2021 21:40:26 -0800 Subject: [PATCH 064/121] Don't save the exif text chunk if it is successfully parsed --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 27 +++++++++++-------- .../Formats/Png/PngMetadataTests.cs | 6 ++++- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 236c447ab..436e706e8 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -976,12 +976,16 @@ namespace SixLabors.ImageSharp.Formats.Png if (this.TryUncompressTextData(compressedData, PngConstants.Encoding, out string uncompressed)) { - metadata.TextData.Add(new PngTextData(name, uncompressed, string.Empty, string.Empty)); - } - - if (name.Equals("Raw profile type exif", StringComparison.OrdinalIgnoreCase)) - { - this.ReadLegacyExifTextChunk(baseMetadata, uncompressed); + if (name.Equals("Raw profile type exif", StringComparison.OrdinalIgnoreCase) && + this.TryReadLegacyExifTextChunk(baseMetadata, uncompressed)) + { + // Successfully parsed exif data stored as text in this chunk + } + else + { + // Seems to be regular old text data, or we failed to parse it in any special way + metadata.TextData.Add(new PngTextData(name, uncompressed, string.Empty, string.Empty)); + } } } @@ -992,7 +996,7 @@ namespace SixLabors.ImageSharp.Formats.Png /// /// The to store the decoded exif tags into. /// The contents of the "raw profile type exif" text chunk. - private void ReadLegacyExifTextChunk(ImageMetadata metadata, string data) + private bool TryReadLegacyExifTextChunk(ImageMetadata metadata, string data) { ReadOnlySpan dataSpan = data.AsSpan(); dataSpan = dataSpan.TrimStart(); @@ -1000,7 +1004,7 @@ namespace SixLabors.ImageSharp.Formats.Png if (!StringEquals(dataSpan.Slice(0, 4), "exif".AsSpan(), StringComparison.OrdinalIgnoreCase)) { // "exif" identifier is missing from the beginning of the text chunk - return; + return false; } // Skip to the data length @@ -1014,7 +1018,7 @@ namespace SixLabors.ImageSharp.Formats.Png if (dataLength < ExifHeader.Length) { // Not enough room for the required exif header, this data couldn't possibly be valid - return; + return false; } // Parse the hex-encoded data into the byte array we are going to hand off to ExifProfile @@ -1034,7 +1038,7 @@ namespace SixLabors.ImageSharp.Formats.Png if (!tempExifBuf.AsSpan().Slice(0, ExifHeader.Length).SequenceEqual(ExifHeader)) { // Exif header in the hex data is not valid - return; + return false; } // Skip over the exif header we just tested @@ -1059,10 +1063,11 @@ namespace SixLabors.ImageSharp.Formats.Png } catch { - return; + return false; } this.MergeOrSetExifProfile(metadata, new ExifProfile(exifBlob), replaceExistingKeys: false); + return true; } private static bool StringEquals(ReadOnlySpan span1, ReadOnlySpan span2, StringComparison comparisonType) diff --git a/tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs index d763d2ba0..8db1d1aaf 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Apache License, Version 2.0. +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -300,8 +301,11 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png IImageInfo imageInfo = Image.Identify(stream); Assert.NotNull(imageInfo); Assert.NotNull(imageInfo.Metadata.ExifProfile); - ExifProfile exif = imageInfo.Metadata.ExifProfile; + PngMetadata meta = imageInfo.Metadata.GetFormatMetadata(PngFormat.Instance); + Assert.DoesNotContain(meta.TextData, t => t.Keyword.Equals("Raw profile type exif", StringComparison.OrdinalIgnoreCase)); + + ExifProfile exif = imageInfo.Metadata.ExifProfile; Assert.Equal(0, exif.InvalidTags.Count); Assert.Equal(3, exif.Values.Count); From bf3035f06b4ad4fd528a6d7826ea8935a4a764ac Mon Sep 17 00:00:00 2001 From: "WINDEV2110EVAL\\User" Date: Mon, 6 Dec 2021 21:46:59 -0800 Subject: [PATCH 065/121] Don't include unnecessary parameters for helper functions that are only used once. Added a missing comment for StringEqualsInsensitive. --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 26 +++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 436e706e8..721a05240 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -1001,7 +1001,7 @@ namespace SixLabors.ImageSharp.Formats.Png ReadOnlySpan dataSpan = data.AsSpan(); dataSpan = dataSpan.TrimStart(); - if (!StringEquals(dataSpan.Slice(0, 4), "exif".AsSpan(), StringComparison.OrdinalIgnoreCase)) + if (!StringEqualsInsensitive(dataSpan.Slice(0, 4), "exif".AsSpan())) { // "exif" identifier is missing from the beginning of the text chunk return false; @@ -1070,13 +1070,20 @@ namespace SixLabors.ImageSharp.Formats.Png return true; } - private static bool StringEquals(ReadOnlySpan span1, ReadOnlySpan span2, StringComparison comparisonType) + /// + /// Compares two ReadOnlySpan<char>s in a case-insensitive method. + /// This is only needed because older frameworks are missing the extension method. + /// + /// The first to compare. + /// The second to compare. + /// True if the spans were identical, false otherwise. + private static bool StringEqualsInsensitive(ReadOnlySpan span1, ReadOnlySpan span2) { #pragma warning disable IDE0022 // Use expression body for methods #if NETSTANDARD2_1 || NETCOREAPP2_1_OR_GREATER - return span1.Equals(span2, comparisonType); + return span1.Equals(span2, StringComparison.OrdinalIgnoreCase); #else - return span1.ToString().Equals(span2.ToString(), comparisonType); + return span1.ToString().Equals(span2.ToString(), StringComparison.OrdinalIgnoreCase); #endif #pragma warning restore IDE0022 // Use expression body for methods } @@ -1085,19 +1092,14 @@ namespace SixLabors.ImageSharp.Formats.Png /// int.Parse() a ReadOnlySpan<char>, with a fallback for older frameworks. /// /// The to parse. - /// The of the integer to parse. - /// The to use when parsing the integer. /// The parsed . - private static int ParseInt32( - ReadOnlySpan span, - System.Globalization.NumberStyles style = System.Globalization.NumberStyles.Integer, - IFormatProvider provider = null) + private static int ParseInt32(ReadOnlySpan span) { #pragma warning disable IDE0022 // Use expression body for methods #if NETSTANDARD2_1 || NETCOREAPP2_1_OR_GREATER - return int.Parse(span, style, provider); + return int.Parse(span); #else - return int.Parse(span.ToString(), style, provider); + return int.Parse(span.ToString()); #endif #pragma warning restore IDE0022 // Use expression body for methods } From c6f9050a5e06abdf815699f2f33885f71859b0dc Mon Sep 17 00:00:00 2001 From: Ynse Hoornenborg Date: Sat, 4 Dec 2021 20:55:41 +0100 Subject: [PATCH 066/121] Initial Abgr32 pixel format implementation --- shared-infrastructure | 2 +- src/ImageSharp/Advanced/AotCompilerTools.cs | 2 + src/ImageSharp/Color/Color.Conversions.cs | 24 ++ .../Helpers/Shuffle/IComponentShuffle.cs | 70 ++++ src/ImageSharp/ImageSharp.csproj | 9 + src/ImageSharp/PixelFormats/IPixel.cs | 6 + .../PixelFormats/PixelImplementations/A8.cs | 4 + .../PixelImplementations/Abgr32.cs | 394 ++++++++++++++++++ .../PixelImplementations/Argb32.cs | 10 + .../PixelImplementations/Bgr24.cs | 9 + .../PixelImplementations/Bgr565.cs | 4 + .../PixelImplementations/Bgra32.cs | 10 + .../PixelImplementations/Bgra4444.cs | 4 + .../PixelImplementations/Bgra5551.cs | 4 + .../PixelImplementations/Byte4.cs | 4 + .../PixelImplementations/HalfSingle.cs | 4 + .../PixelImplementations/HalfVector2.cs | 4 + .../PixelImplementations/HalfVector4.cs | 4 + .../PixelFormats/PixelImplementations/L16.cs | 7 + .../PixelFormats/PixelImplementations/L8.cs | 4 + .../PixelFormats/PixelImplementations/La16.cs | 8 + .../PixelFormats/PixelImplementations/La32.cs | 12 + .../PixelImplementations/NormalizedByte2.cs | 4 + .../PixelImplementations/NormalizedByte4.cs | 4 + .../PixelImplementations/NormalizedShort2.cs | 4 + .../PixelImplementations/NormalizedShort4.cs | 4 + .../PixelOperations/Abgr32.PixelOperations.cs | 26 ++ .../Abgr32.PixelOperations.Generated.cs | 346 +++++++++++++++ .../Abgr32.PixelOperations.Generated.tt | 18 + .../Generated/_Common.ttinclude | 3 + .../PixelFormats/PixelImplementations/Rg32.cs | 4 + .../PixelImplementations/Rgb24.cs | 9 + .../PixelImplementations/Rgb48.cs | 9 + .../PixelImplementations/Rgba1010102.cs | 4 + .../PixelImplementations/Rgba32.cs | 10 + .../PixelImplementations/Rgba64.cs | 37 ++ .../PixelImplementations/RgbaVector.cs | 4 + .../PixelImplementations/Short2.cs | 4 + .../PixelImplementations/Short4.cs | 4 + .../PixelOperations{TPixel}.Generated.cs | 72 ++++ .../PixelOperations{TPixel}.Generated.tt | 3 + .../PixelFormats/Utils/PixelConverter.cs | 125 +++++- .../Color/ColorTests.CastFrom.cs | 13 + .../Color/ColorTests.CastTo.cs | 13 + .../Color/ColorTests.ConstructFrom.cs | 13 + .../ImageSharp.Tests/Image/ImageCloneTests.cs | 26 ++ .../PixelFormats/Abgr32Tests.cs | 148 +++++++ .../PixelFormats/Bgra32Tests.cs | 11 +- ...ConverterTests.ReferenceImplementations.cs | 15 + .../PixelFormats/PixelConverterTests.cs | 59 +++ ...elOperationsTests.Specialized.Generated.cs | 47 +-- .../Generated/_Common.ttinclude | 2 + .../PixelOperations/PixelOperationsTests.cs | 45 ++ .../PixelFormats/Rgba32Tests.cs | 16 + .../PixelFormats/Rgba64Tests.cs | 24 ++ .../PixelFormats/Short4Tests.cs | 18 + tests/ImageSharp.Tests/TestFormat.cs | 4 + .../TestUtilities/PixelTypes.cs | 2 + .../Tests/TestUtilityExtensionsTests.cs | 5 +- 59 files changed, 1717 insertions(+), 37 deletions(-) create mode 100644 src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs create mode 100644 src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Abgr32.PixelOperations.cs create mode 100644 src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Abgr32.PixelOperations.Generated.cs create mode 100644 src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Abgr32.PixelOperations.Generated.tt create mode 100644 tests/ImageSharp.Tests/PixelFormats/Abgr32Tests.cs diff --git a/shared-infrastructure b/shared-infrastructure index 59ce17f5a..a042aba17 160000 --- a/shared-infrastructure +++ b/shared-infrastructure @@ -1 +1 @@ -Subproject commit 59ce17f5a4e1f956811133f41add7638e74c2836 +Subproject commit a042aba176cdb840d800c6ed4cfe41a54fb7b1e3 diff --git a/src/ImageSharp/Advanced/AotCompilerTools.cs b/src/ImageSharp/Advanced/AotCompilerTools.cs index b90a6ce3c..f5714fa5e 100644 --- a/src/ImageSharp/Advanced/AotCompilerTools.cs +++ b/src/ImageSharp/Advanced/AotCompilerTools.cs @@ -74,6 +74,7 @@ namespace SixLabors.ImageSharp.Advanced Seed(); Seed(); + Seed(); Seed(); Seed(); Seed(); @@ -148,6 +149,7 @@ namespace SixLabors.ImageSharp.Advanced Image img = default; img.CloneAs(default); img.CloneAs(default); + img.CloneAs(default); img.CloneAs(default); img.CloneAs(default); img.CloneAs(default); diff --git a/src/ImageSharp/Color/Color.Conversions.cs b/src/ImageSharp/Color/Color.Conversions.cs index bf7869e53..5c10bfaa0 100644 --- a/src/ImageSharp/Color/Color.Conversions.cs +++ b/src/ImageSharp/Color/Color.Conversions.cs @@ -89,6 +89,17 @@ namespace SixLabors.ImageSharp this.boxedHighPrecisionPixel = null; } + /// + /// Initializes a new instance of the struct. + /// + /// The containing the color information. + [MethodImpl(InliningOptions.ShortMethod)] + public Color(Abgr32 pixel) + { + this.data = new Rgba64(pixel); + this.boxedHighPrecisionPixel = null; + } + /// /// Initializes a new instance of the struct. /// @@ -177,6 +188,19 @@ namespace SixLabors.ImageSharp return value; } + [MethodImpl(InliningOptions.ShortMethod)] + internal Abgr32 ToAbgr32() + { + if (this.boxedHighPrecisionPixel is null) + { + return this.data.ToAbgr32(); + } + + Abgr32 value = default; + value.FromScaledVector4(this.boxedHighPrecisionPixel.ToScaledVector4()); + return value; + } + [MethodImpl(InliningOptions.ShortMethod)] internal Rgb24 ToRgb24() { diff --git a/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs b/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs index 929b78692..8d1236ee9 100644 --- a/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs +++ b/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs @@ -194,4 +194,74 @@ namespace SixLabors.ImageSharp } } } + + internal readonly struct XWZYShuffle4 : IShuffle4 + { + public byte Control + { + [MethodImpl(InliningOptions.ShortMethod)] + get => SimdUtils.Shuffle.MmShuffle(1, 2, 3, 0); + } + + [MethodImpl(InliningOptions.ShortMethod)] + public void RunFallbackShuffle(ReadOnlySpan source, Span dest) + { + ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); + ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); + int n = source.Length / 4; + + for (int i = 0; i < n; i++) + { + uint packed = Unsafe.Add(ref sBase, i); + + // packed = [W Z Y X] + // tmp1 = [0 Z 0 X] + // tmp2 = [W 0 Y 0] + // tmp3=ROTL(16, tmp2) = [Y 0 W 0] + // tmp1 + tmp3 = [Y Z W X] + uint tmp1 = packed & 0xFF00FF00; + uint tmp2 = packed & 0x00FF00FF; + uint tmp3 = (tmp2 << 16) | (tmp2 >> 16); + + Unsafe.Add(ref dBase, i) = tmp1 + tmp3; + } + } + } + + internal readonly struct XZWYShuffle4 : IShuffle4 + { + public byte Control + { + [MethodImpl(InliningOptions.ShortMethod)] + get => SimdUtils.Shuffle.MmShuffle(1, 3, 2, 0); + } + + [MethodImpl(InliningOptions.ShortMethod)] + public void RunFallbackShuffle(ReadOnlySpan source, Span dest) + { + ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); + ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); + int n = source.Length / 4; + + for (int i = 0; i < n; i++) + { + uint packed = Unsafe.Add(ref sBase, i); + + // packed = [W Z Y X] + // tmp1 = [0 0 0 X] + // tmp2 = [W Z 0 0] + // tmp3 = [0 0 Y 0] + // tmp4=ROTR(8, tmp2) = [0 W Z 0] + // tmp5=ROTL(16, tmp3) = [Y 0 0 0] + // tmp1+ tmp3 + tmp4 = [Y W Z X] + uint tmp1 = packed & 0x000000FF; + uint tmp2 = packed & 0xFFFF0000; + uint tmp3 = packed & 0x0000FF00; + uint tmp4 = tmp2 >> 8; + uint tmp5 = tmp3 << 16; + + Unsafe.Add(ref dBase, i) = tmp1 + tmp4 + tmp5; + } + } + } } diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index f90e40edb..b138f8d5e 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -75,6 +75,11 @@ True Block8x8F.Generated.tt + + True + True + Abgr32.PixelOperations.Generated.tt + True True @@ -166,6 +171,10 @@ TextTemplatingFileGenerator Block8x8F.Generated.cs + + TextTemplatingFileGenerator + Abgr32.PixelOperations.Generated.cs + TextTemplatingFileGenerator PixelOperations{TPixel}.Generated.cs diff --git a/src/ImageSharp/PixelFormats/IPixel.cs b/src/ImageSharp/PixelFormats/IPixel.cs index 12b5bc784..09f8cc955 100644 --- a/src/ImageSharp/PixelFormats/IPixel.cs +++ b/src/ImageSharp/PixelFormats/IPixel.cs @@ -79,6 +79,12 @@ namespace SixLabors.ImageSharp.PixelFormats /// The value. void FromBgra32(Bgra32 source); + /// + /// Initializes the pixel instance from an value. + /// + /// The value. + void FromAbgr32(Abgr32 source); + /// /// Initializes the pixel instance from an value. /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/A8.cs b/src/ImageSharp/PixelFormats/PixelImplementations/A8.cs index cca7ff7db..afb07433f 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/A8.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/A8.cs @@ -87,6 +87,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void FromBgra32(Bgra32 source) => this.PackedValue = source.A; + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromAbgr32(Abgr32 source) => this.PackedValue = source.A; + /// [MethodImpl(InliningOptions.ShortMethod)] public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs new file mode 100644 index 000000000..157ac2a83 --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs @@ -0,0 +1,394 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace SixLabors.ImageSharp.PixelFormats +{ + /// + /// Packed pixel type containing 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). + /// + /// Ranges from [0, 0, 0, 0] to [1, 1, 1, 1] in vector form. + /// + /// + /// + /// 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. + /// + [StructLayout(LayoutKind.Sequential)] + public partial struct Abgr32 : IPixel, IPackedVector + { + /// + /// Gets or sets the alpha component. + /// + public byte A; + + /// + /// Gets or sets the blue component. + /// + public byte B; + + /// + /// Gets or sets the green component. + /// + public byte G; + + /// + /// Gets or sets the red component. + /// + public byte R; + + /// + /// The maximum byte value. + /// + private static readonly Vector4 MaxBytes = new(255); + + /// + /// The half vector value. + /// + private static readonly Vector4 Half = new(0.5F); + + /// + /// Initializes a new instance of the struct. + /// + /// The red component. + /// The green component. + /// The blue component. + [MethodImpl(InliningOptions.ShortMethod)] + public Abgr32(byte r, byte g, byte b) + { + this.R = r; + this.G = g; + this.B = b; + this.A = byte.MaxValue; + } + + /// + /// Initializes a new instance of the struct. + /// + /// The red component. + /// The green component. + /// The blue component. + /// The alpha component. + [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; + } + + /// + /// Initializes a new instance of the struct. + /// + /// The red component. + /// The green component. + /// The blue component. + /// The alpha component. + [MethodImpl(InliningOptions.ShortMethod)] + public Abgr32(float r, float g, float b, float a = 1) + : this() => this.Pack(r, g, b, a); + + /// + /// Initializes a new instance of the struct. + /// + /// + /// The vector containing the components for the packed vector. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Abgr32(Vector3 vector) + : this() => this.Pack(ref vector); + + /// + /// Initializes a new instance of the struct. + /// + /// + /// The vector containing the components for the packed vector. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Abgr32(Vector4 vector) + : this() => this.Pack(ref vector); + + /// + /// Initializes a new instance of the struct. + /// + /// + /// The packed value. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Abgr32(uint packed) + : this() => this.Abgr = packed; + + /// + /// Gets or sets the packed representation of the Abgrb32 struct. + /// + public uint Abgr + { + [MethodImpl(InliningOptions.ShortMethod)] + readonly get => Unsafe.As(ref Unsafe.AsRef(this)); + + [MethodImpl(InliningOptions.ShortMethod)] + set => Unsafe.As(ref this) = value; + } + + /// + public uint PackedValue + { + [MethodImpl(InliningOptions.ShortMethod)] + readonly get => this.Abgr; + + [MethodImpl(InliningOptions.ShortMethod)] + set => this.Abgr = value; + } + + /// + /// Converts an to . + /// + /// The . + /// The . + [MethodImpl(InliningOptions.ShortMethod)] + public static implicit operator Color(Abgr32 source) => new(source); + + /// + /// Converts a to . + /// + /// The . + /// The . + [MethodImpl(InliningOptions.ShortMethod)] + public static implicit operator Abgr32(Color color) => color.ToAbgr32(); + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Abgr32 left, Abgr32 right) => left.Equals(right); + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is not equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Abgr32 left, Abgr32 right) => !left.Equals(right); + + /// + public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public readonly Vector4 ToScaledVector4() => this.ToVector4(); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromVector4(Vector4 vector) => this.Pack(ref vector); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public readonly Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A) / MaxBytes; + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromAbgr32(Abgr32 source) => this.PackedValue = source.PackedValue; + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromBgr24(Bgr24 source) + { + this.R = source.R; + this.G = source.G; + this.B = source.B; + this.A = byte.MaxValue; + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromArgb32(Argb32 source) + { + this.R = source.R; + this.G = source.G; + this.B = source.B; + this.A = source.A; + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromBgra32(Bgra32 source) + { + this.R = source.R; + this.G = source.G; + this.B = source.B; + this.A = source.A; + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromL8(L8 source) + { + this.R = source.PackedValue; + this.G = source.PackedValue; + this.B = source.PackedValue; + this.A = byte.MaxValue; + } + + /// + [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; + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromLa16(La16 source) + { + this.R = source.L; + this.G = source.L; + this.B = source.L; + this.A = source.A; + } + + /// + [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); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgb24(Rgb24 source) + { + this.R = source.R; + this.G = source.G; + this.B = source.B; + this.A = byte.MaxValue; + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgba32(Rgba32 source) + { + this.R = source.R; + this.G = source.G; + this.B = source.B; + this.A = source.A; + } + + /// + [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; + } + + /// + [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; + } + + /// + [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); + } + + /// + public override readonly bool Equals(object obj) => obj is Abgr32 abgr32 && this.Equals(abgr32); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public readonly bool Equals(Abgr32 other) => this.Abgr == other.Abgr; + + /// + /// Gets a string representation of the packed vector. + /// + /// A string representation of the packed vector. + public override readonly string ToString() => $"Abgr({this.A}, {this.B}, {this.G}, {this.R})"; + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public override readonly int GetHashCode() => this.Abgr.GetHashCode(); + + /// + /// Packs the four floats into a color. + /// + /// The x-component + /// The y-component + /// The z-component + /// The w-component + [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); + } + + /// + /// Packs a into a uint. + /// + /// The vector containing the values to pack. + [MethodImpl(InliningOptions.ShortMethod)] + private void Pack(ref Vector3 vector) + { + var value = new Vector4(vector, 1); + this.Pack(ref value); + } + + /// + /// Packs a into a color. + /// + /// The vector containing the values to pack. + [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; + } + } +} diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs index 8c1b04ff1..2ec85de93 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs @@ -230,6 +230,16 @@ namespace SixLabors.ImageSharp.PixelFormats this.A = source.A; } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromAbgr32(Abgr32 source) + { + this.R = source.R; + this.G = source.G; + this.B = source.B; + this.A = source.A; + } + /// [MethodImpl(InliningOptions.ShortMethod)] public void FromL8(L8 source) diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs index 22e983a65..882306928 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs @@ -185,6 +185,15 @@ namespace SixLabors.ImageSharp.PixelFormats this.B = source.B; } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromAbgr32(Abgr32 source) + { + this.R = source.R; + this.G = source.G; + this.B = source.B; + } + /// [MethodImpl(InliningOptions.ShortMethod)] public void FromRgba32(Rgba32 source) => this = source.Bgr; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs index 5585310b9..bd21d0425 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs @@ -99,6 +99,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void FromBgra32(Bgra32 source) => this.FromVector4(source.ToVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromAbgr32(Abgr32 source) => this.FromVector4(source.ToVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void FromL8(L8 source) => this.FromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs index be4e178c2..34769e32d 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs @@ -165,6 +165,16 @@ namespace SixLabors.ImageSharp.PixelFormats this.A = source.A; } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromAbgr32(Abgr32 source) + { + this.R = source.R; + this.G = source.G; + this.B = source.B; + this.A = source.A; + } + /// [MethodImpl(InliningOptions.ShortMethod)] public void FromBgr24(Bgr24 source) diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs index 3578f1dd3..059d61136 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs @@ -102,6 +102,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void FromL8(L8 source) => this.FromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs index 0254397c3..b6cc1f878 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs @@ -124,6 +124,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void ToRgba32(ref Rgba32 dest) => dest.FromScaledVector4(this.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs index 0995f8417..e1ed4577e 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs @@ -124,6 +124,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void ToRgba32(ref Rgba32 dest) => dest.FromScaledVector4(this.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs b/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs index b0ef0f6a9..51b6af640 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs @@ -88,6 +88,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs index 8be826130..1fff37757 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs @@ -99,6 +99,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs index 955b274ac..94051e263 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs @@ -104,6 +104,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs b/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs index 6d1128dd2..c40e301de 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs @@ -91,6 +91,13 @@ namespace SixLabors.ImageSharp.PixelFormats ColorNumerics.UpscaleFrom8BitTo16Bit(source.G), ColorNumerics.UpscaleFrom8BitTo16Bit(source.B)); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromAbgr32(Abgr32 source) => this.PackedValue = ColorNumerics.Get16BitBT709Luminance( + ColorNumerics.UpscaleFrom8BitTo16Bit(source.R), + ColorNumerics.UpscaleFrom8BitTo16Bit(source.G), + ColorNumerics.UpscaleFrom8BitTo16Bit(source.B)); + /// [MethodImpl(InliningOptions.ShortMethod)] public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs b/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs index ffff60be5..70d031aa1 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs @@ -83,6 +83,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void FromBgra32(Bgra32 source) => this.PackedValue = ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromAbgr32(Abgr32 source) => this.PackedValue = ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B); + /// [MethodImpl(InliningOptions.ShortMethod)] public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs b/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs index 877aaed81..72f188fa3 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs @@ -112,6 +112,14 @@ namespace SixLabors.ImageSharp.PixelFormats this.A = source.A; } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromAbgr32(Abgr32 source) + { + this.L = ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B); + this.A = source.A; + } + /// [MethodImpl(InliningOptions.ShortMethod)] public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs index f19f22813..d9104aa4f 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs @@ -127,6 +127,18 @@ namespace SixLabors.ImageSharp.PixelFormats this.A = ColorNumerics.UpscaleFrom8BitTo16Bit(source.A); } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromAbgr32(Abgr32 source) + { + this.L = ColorNumerics.Get16BitBT709Luminance( + ColorNumerics.UpscaleFrom8BitTo16Bit(source.R), + ColorNumerics.UpscaleFrom8BitTo16Bit(source.G), + ColorNumerics.UpscaleFrom8BitTo16Bit(source.B)); + + this.A = ColorNumerics.UpscaleFrom8BitTo16Bit(source.A); + } + /// [MethodImpl(InliningOptions.ShortMethod)] public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs index 62eaf949d..78c83a543 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs @@ -107,6 +107,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs index 2e81b3e2d..432461f75 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs @@ -109,6 +109,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs index b97aaacec..60fe2368a 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs @@ -108,6 +108,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs index f2e8aedd8..01b9777b0 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs @@ -110,6 +110,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Abgr32.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Abgr32.PixelOperations.cs new file mode 100644 index 000000000..439c5529a --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Abgr32.PixelOperations.cs @@ -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 +{ + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Abgr32 + { + /// + /// Provides optimized overrides for bulk operations. + /// + internal partial class PixelOperations : PixelOperations + { + private static readonly Lazy LazyInfo = + new Lazy(() => PixelTypeInfo.Create(PixelAlphaRepresentation.Unassociated), true); + + /// + public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; + } + } +} diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Abgr32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Abgr32.PixelOperations.Generated.cs new file mode 100644 index 000000000..6386d315c --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Abgr32.PixelOperations.Generated.cs @@ -0,0 +1,346 @@ +// 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; +using SixLabors.ImageSharp.PixelFormats.Utils; + +namespace SixLabors.ImageSharp.PixelFormats +{ + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Abgr32 + { + /// + /// Provides optimized overrides for bulk operations. + /// + internal partial class PixelOperations : PixelOperations + { + /// + public override void FromAbgr32(Configuration configuration, ReadOnlySpan source, Span destinationPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(source, destinationPixels, nameof(destinationPixels)); + + source.CopyTo(destinationPixels.Slice(0, source.Length)); + } + + /// + public override void ToAbgr32(Configuration configuration, ReadOnlySpan sourcePixels, Span destinationPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + + sourcePixels.CopyTo(destinationPixels.Slice(0, sourcePixels.Length)); + } + /// + public override void FromVector4Destructive( + Configuration configuration, + Span sourceVectors, + Span destinationPixels, + PixelConversionModifiers modifiers) + { + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destinationPixels, modifiers.Remove(PixelConversionModifiers.Scale)); + } + + /// + public override void ToVector4( + Configuration configuration, + ReadOnlySpan sourcePixels, + Span destVectors, + PixelConversionModifiers modifiers) + { + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, modifiers.Remove(PixelConversionModifiers.Scale)); + } + /// + public override void ToRgba32( + Configuration configuration, + ReadOnlySpan sourcePixels, + Span destinationPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + + ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); + Span dest = MemoryMarshal.Cast(destinationPixels); + PixelConverter.FromAbgr32.ToRgba32(source, dest); + } + + /// + public override void FromRgba32( + Configuration configuration, + ReadOnlySpan sourcePixels, + Span destinationPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + + ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); + Span dest = MemoryMarshal.Cast(destinationPixels); + PixelConverter.FromRgba32.ToAbgr32(source, dest); + } + /// + public override void ToArgb32( + Configuration configuration, + ReadOnlySpan sourcePixels, + Span destinationPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + + ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); + Span dest = MemoryMarshal.Cast(destinationPixels); + PixelConverter.FromAbgr32.ToArgb32(source, dest); + } + + /// + public override void FromArgb32( + Configuration configuration, + ReadOnlySpan sourcePixels, + Span destinationPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + + ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); + Span dest = MemoryMarshal.Cast(destinationPixels); + PixelConverter.FromArgb32.ToAbgr32(source, dest); + } + /// + public override void ToBgra32( + Configuration configuration, + ReadOnlySpan sourcePixels, + Span destinationPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + + ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); + Span dest = MemoryMarshal.Cast(destinationPixels); + PixelConverter.FromAbgr32.ToBgra32(source, dest); + } + + /// + public override void FromBgra32( + Configuration configuration, + ReadOnlySpan sourcePixels, + Span destinationPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + + ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); + Span dest = MemoryMarshal.Cast(destinationPixels); + PixelConverter.FromBgra32.ToAbgr32(source, dest); + } + /// + public override void ToRgb24( + Configuration configuration, + ReadOnlySpan sourcePixels, + Span destinationPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + + ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); + Span dest = MemoryMarshal.Cast(destinationPixels); + PixelConverter.FromAbgr32.ToRgb24(source, dest); + } + + /// + public override void FromRgb24( + Configuration configuration, + ReadOnlySpan sourcePixels, + Span destinationPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + + ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); + Span dest = MemoryMarshal.Cast(destinationPixels); + PixelConverter.FromRgb24.ToAbgr32(source, dest); + } + /// + public override void ToBgr24( + Configuration configuration, + ReadOnlySpan sourcePixels, + Span destinationPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + + ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); + Span dest = MemoryMarshal.Cast(destinationPixels); + PixelConverter.FromAbgr32.ToBgr24(source, dest); + } + + /// + public override void FromBgr24( + Configuration configuration, + ReadOnlySpan sourcePixels, + Span destinationPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + + ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); + Span dest = MemoryMarshal.Cast(destinationPixels); + PixelConverter.FromBgr24.ToAbgr32(source, dest); + } + /// + public override void ToL8( + Configuration configuration, + ReadOnlySpan sourcePixels, + Span 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 (int 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); + } + } + /// + public override void ToL16( + Configuration configuration, + ReadOnlySpan sourcePixels, + Span 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 (int 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); + } + } + /// + public override void ToLa16( + Configuration configuration, + ReadOnlySpan sourcePixels, + Span 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 (int 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); + } + } + /// + public override void ToLa32( + Configuration configuration, + ReadOnlySpan sourcePixels, + Span 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 (int 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); + } + } + /// + public override void ToRgb48( + Configuration configuration, + ReadOnlySpan sourcePixels, + Span 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 (int 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); + } + } + /// + public override void ToRgba64( + Configuration configuration, + ReadOnlySpan sourcePixels, + Span 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 (int 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); + } + } + /// + public override void ToBgra5551( + Configuration configuration, + ReadOnlySpan sourcePixels, + Span 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 (int 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); + } + } + /// + public override void From( + Configuration configuration, + ReadOnlySpan sourcePixels, + Span destinationPixels) + { + PixelOperations.Instance.ToAbgr32(configuration, sourcePixels, destinationPixels.Slice(0, sourcePixels.Length)); + } + + } + } +} diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Abgr32.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Abgr32.PixelOperations.Generated.tt new file mode 100644 index 000000000..071c74fbb --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Abgr32.PixelOperations.Generated.tt @@ -0,0 +1,18 @@ +<#@include file="_Common.ttinclude" #> +<#@ output extension=".cs" #> +namespace SixLabors.ImageSharp.PixelFormats +{ + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Abgr32 + { + /// + /// Provides optimized overrides for bulk operations. + /// + internal partial class PixelOperations : PixelOperations + { + <# GenerateAllDefaultConversionMethods("Abgr32"); #> + } + } +} diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/_Common.ttinclude b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/_Common.ttinclude index 784ecf6fb..b6b0a14a7 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/_Common.ttinclude +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/_Common.ttinclude @@ -17,6 +17,7 @@ using SixLabors.ImageSharp.PixelFormats.Utils; private static readonly string[] CommonPixelTypes = { "Argb32", + "Abgr32", "Bgr24", "Bgra32", "L8", @@ -34,6 +35,7 @@ using SixLabors.ImageSharp.PixelFormats.Utils; { "Rgba32", "Argb32", + "Abgr32", "Bgra32", "Rgb24", "Bgr24" @@ -43,6 +45,7 @@ using SixLabors.ImageSharp.PixelFormats.Utils; private static readonly string[] Rgba32CompatibleTypes = { "Argb32", + "Abgr32", "Bgra32", "Rgb24", "Bgr24" diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs index 12b6e153f..d408f301b 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs @@ -93,6 +93,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs index 3b5bdb3d5..00f072268 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs @@ -153,6 +153,15 @@ namespace SixLabors.ImageSharp.PixelFormats this.B = source.B; } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromAbgr32(Abgr32 source) + { + this.R = source.R; + this.G = source.G; + this.B = source.B; + } + /// [MethodImpl(InliningOptions.ShortMethod)] public void FromL8(L8 source) diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs index d16b7db7a..90c15ae26 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs @@ -186,6 +186,15 @@ namespace SixLabors.ImageSharp.PixelFormats this.B = ColorNumerics.UpscaleFrom8BitTo16Bit(source.B); } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromAbgr32(Abgr32 source) + { + this.R = ColorNumerics.UpscaleFrom8BitTo16Bit(source.R); + this.G = ColorNumerics.UpscaleFrom8BitTo16Bit(source.G); + this.B = ColorNumerics.UpscaleFrom8BitTo16Bit(source.B); + } + /// [MethodImpl(InliningOptions.ShortMethod)] public void ToRgba32(ref Rgba32 dest) diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs index e68726018..11e11bc6c 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs @@ -96,6 +96,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs index 3dc6490f1..2d250f71d 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs @@ -333,6 +333,16 @@ namespace SixLabors.ImageSharp.PixelFormats this.A = source.A; } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromAbgr32(Abgr32 source) + { + this.R = source.R; + this.G = source.G; + this.B = source.B; + this.A = source.A; + } + /// [MethodImpl(InliningOptions.ShortMethod)] public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs index 4cfa0bf97..bf7452592 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs @@ -94,6 +94,19 @@ namespace SixLabors.ImageSharp.PixelFormats this.A = ColorNumerics.UpscaleFrom8BitTo16Bit(source.A); } + /// + /// Initializes a new instance of the struct. + /// + /// A structure of 4 bytes in ABGR byte order. + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba64(Abgr32 source) + { + this.R = ColorNumerics.UpscaleFrom8BitTo16Bit(source.R); + this.G = ColorNumerics.UpscaleFrom8BitTo16Bit(source.G); + this.B = ColorNumerics.UpscaleFrom8BitTo16Bit(source.B); + this.A = ColorNumerics.UpscaleFrom8BitTo16Bit(source.A); + } + /// /// Initializes a new instance of the struct. /// @@ -250,6 +263,16 @@ namespace SixLabors.ImageSharp.PixelFormats this.A = ColorNumerics.UpscaleFrom8BitTo16Bit(source.A); } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromAbgr32(Abgr32 source) + { + this.R = ColorNumerics.UpscaleFrom8BitTo16Bit(source.R); + this.G = ColorNumerics.UpscaleFrom8BitTo16Bit(source.G); + this.B = ColorNumerics.UpscaleFrom8BitTo16Bit(source.B); + this.A = ColorNumerics.UpscaleFrom8BitTo16Bit(source.A); + } + /// [MethodImpl(InliningOptions.ShortMethod)] public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); @@ -380,6 +403,20 @@ namespace SixLabors.ImageSharp.PixelFormats return new Argb32(r, g, b, a); } + /// + /// Convert to . + /// + /// The . + [MethodImpl(InliningOptions.ShortMethod)] + public readonly Abgr32 ToAbgr32() + { + byte r = ColorNumerics.DownScaleFrom16BitTo8Bit(this.R); + byte g = ColorNumerics.DownScaleFrom16BitTo8Bit(this.G); + byte b = ColorNumerics.DownScaleFrom16BitTo8Bit(this.B); + byte a = ColorNumerics.DownScaleFrom16BitTo8Bit(this.A); + return new Abgr32(r, g, b, a); + } + /// /// Convert to . /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs index cd6f53c4e..e582e6166 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs @@ -134,6 +134,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs index 24f6b4d1d..f0117707c 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs @@ -111,6 +111,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs index 86a519297..fd58477d9 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs @@ -116,6 +116,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs index cc36c7d13..ea107b35a 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs @@ -82,6 +82,78 @@ namespace SixLabors.ImageSharp.PixelFormats this.ToArgb32(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); } + /// + /// Converts all pixels in 'source` span of into a span of -s. + /// + /// A to configure internal operations. + /// The source of data. + /// The to the destination pixels. + public virtual void FromAbgr32(Configuration configuration, ReadOnlySpan source, Span destinationPixels) + { + Guard.DestinationShouldNotBeTooShort(source, destinationPixels, nameof(destinationPixels)); + + ref Abgr32 sourceBaseRef = ref MemoryMarshal.GetReference(source); + ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); + + for (int i = 0; i < source.Length; i++) + { + ref Abgr32 sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); + + dp.FromAbgr32(sp); + } + } + + /// + /// A helper for that expects a byte span. + /// The layout of the data in 'sourceBytes' must be compatible with layout. + /// + /// A to configure internal operations. + /// The to the source bytes. + /// The to the destination pixels. + /// The number of pixels to convert. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromAbgr32Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destinationPixels, int count) + { + this.FromAbgr32(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destinationPixels); + } + + /// + /// Converts all pixels of the 'sourcePixels` span to a span of -s. + /// + /// A to configure internal operations + /// The span of source pixels + /// The destination span of data. + public virtual void ToAbgr32(Configuration configuration, ReadOnlySpan sourcePixels, Span destinationPixels) + { + Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + + ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Abgr32 destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref Abgr32 dp = ref Unsafe.Add(ref destBaseRef, i); + + dp.FromScaledVector4(sp.ToScaledVector4()); + } + } + + /// + /// A helper for that expects a byte span as destination. + /// The layout of the data in 'destBytes' must be compatible with layout. + /// + /// A to configure internal operations + /// The to the source pixels. + /// The to the destination bytes. + /// The number of pixels to convert. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToAbgr32Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) + { + this.ToAbgr32(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + } + /// /// Converts all pixels in 'source` span of into a span of -s. /// diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt index 21ed328fa..e8cf6f9a5 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt @@ -112,6 +112,9 @@ namespace SixLabors.ImageSharp.PixelFormats GenerateFromMethods("Argb32"); GenerateToDestFormatMethods("Argb32"); + GenerateFromMethods("Abgr32"); + GenerateToDestFormatMethods("Abgr32"); + GenerateFromMethods("Bgr24"); GenerateToDestFormatMethods("Bgr24"); diff --git a/src/ImageSharp/PixelFormats/Utils/PixelConverter.cs b/src/ImageSharp/PixelFormats/Utils/PixelConverter.cs index 7215fa860..907399d5f 100644 --- a/src/ImageSharp/PixelFormats/Utils/PixelConverter.cs +++ b/src/ImageSharp/PixelFormats/Utils/PixelConverter.cs @@ -18,8 +18,13 @@ namespace SixLabors.ImageSharp.PixelFormats.Utils /// internal static class PixelConverter { + /// + /// Optimized converters from . + /// public static class FromRgba32 { + // Input pixels have: X = R, Y = G, Z = B and W = A. + /// /// Converts a representing a collection of /// pixels to a representing @@ -38,6 +43,15 @@ namespace SixLabors.ImageSharp.PixelFormats.Utils public static void ToBgra32(ReadOnlySpan source, Span dest) => SimdUtils.Shuffle4(source, dest, default); + /// + /// Converts a representing a collection of + /// pixels to a representing + /// a collection of pixels. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static void ToAbgr32(ReadOnlySpan source, Span dest) + => SimdUtils.Shuffle4(source, dest, default); + /// /// Converts a representing a collection of /// pixels to a representing @@ -57,8 +71,13 @@ namespace SixLabors.ImageSharp.PixelFormats.Utils => SimdUtils.Shuffle4Slice3(source, dest, new DefaultShuffle4Slice3(3, 0, 1, 2)); } + /// + /// Optimized converters from . + /// public static class FromArgb32 { + // Input pixels have: X = A, Y = R, Z = G and W = B. + /// /// Converts a representing a collection of /// pixels to a representing @@ -77,6 +96,15 @@ namespace SixLabors.ImageSharp.PixelFormats.Utils public static void ToBgra32(ReadOnlySpan source, Span dest) => SimdUtils.Shuffle4(source, dest, default); + /// + /// Converts a representing a collection of + /// pixels to a representing + /// a collection of pixels. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static void ToAbgr32(ReadOnlySpan source, Span dest) + => SimdUtils.Shuffle4(source, dest, default); + /// /// Converts a representing a collection of /// pixels to a representing @@ -96,8 +124,13 @@ namespace SixLabors.ImageSharp.PixelFormats.Utils => SimdUtils.Shuffle4Slice3(source, dest, new DefaultShuffle4Slice3(0, 1, 2, 3)); } + /// + /// Optimized converters from . + /// public static class FromBgra32 { + // Input pixels have: X = B, Y = G, Z = R and W = A. + /// /// Converts a representing a collection of /// pixels to a representing @@ -110,12 +143,21 @@ namespace SixLabors.ImageSharp.PixelFormats.Utils /// /// Converts a representing a collection of /// pixels to a representing - /// a collection of pixels. + /// a collection of pixels. /// [MethodImpl(InliningOptions.ShortMethod)] public static void ToRgba32(ReadOnlySpan source, Span dest) => SimdUtils.Shuffle4(source, dest, default); + /// + /// Converts a representing a collection of + /// pixels to a representing + /// a collection of pixels. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static void ToAbgr32(ReadOnlySpan source, Span dest) + => SimdUtils.Shuffle4(source, dest, default); + /// /// Converts a representing a collection of /// pixels to a representing @@ -135,8 +177,66 @@ namespace SixLabors.ImageSharp.PixelFormats.Utils => SimdUtils.Shuffle4Slice3(source, dest, default); } + /// + /// Optimized converters from . + /// + public static class FromAbgr32 + { + // Input pixels have: X = A, Y = B, Z = G and W = R. + + /// + /// Converts a representing a collection of + /// pixels to a representing + /// a collection of pixels. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static void ToArgb32(ReadOnlySpan source, Span dest) + => SimdUtils.Shuffle4(source, dest, default); + + /// + /// Converts a representing a collection of + /// pixels to a representing + /// a collection of pixels. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static void ToRgba32(ReadOnlySpan source, Span dest) + => SimdUtils.Shuffle4(source, dest, default); + + /// + /// Converts a representing a collection of + /// pixels to a representing + /// a collection of pixels. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static void ToBgra32(ReadOnlySpan source, Span dest) + => SimdUtils.Shuffle4(source, dest, default); + + /// + /// Converts a representing a collection of + /// pixels to a representing + /// a collection of pixels. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static void ToRgb24(ReadOnlySpan source, Span dest) + => SimdUtils.Shuffle4Slice3(source, dest, new DefaultShuffle4Slice3(0, 1, 2, 3)); + + /// + /// Converts a representing a collection of + /// pixels to a representing + /// a collection of pixels. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static void ToBgr24(ReadOnlySpan source, Span dest) + => SimdUtils.Shuffle4Slice3(source, dest, new DefaultShuffle4Slice3(0, 3, 2, 1)); + } + + /// + /// Optimized converters from . + /// public static class FromRgb24 { + // Input pixels have: X = R, Y = G and Z = B. + /// /// Converts a representing a collection of /// pixels to a representing @@ -164,6 +264,15 @@ namespace SixLabors.ImageSharp.PixelFormats.Utils public static void ToBgra32(ReadOnlySpan source, Span dest) => SimdUtils.Pad3Shuffle4(source, dest, new DefaultPad3Shuffle4(3, 0, 1, 2)); + /// + /// Converts a representing a collection of + /// pixels to a representing + /// a collection of pixels. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static void ToAbgr32(ReadOnlySpan source, Span dest) + => SimdUtils.Pad3Shuffle4(source, dest, new DefaultPad3Shuffle4(0, 1, 2, 3)); + /// /// Converts a representing a collection of /// pixels to a representing @@ -174,8 +283,13 @@ namespace SixLabors.ImageSharp.PixelFormats.Utils => SimdUtils.Shuffle3(source, dest, new DefaultShuffle3(0, 1, 2)); } + /// + /// Optimized converters from . + /// public static class FromBgr24 { + // Input pixels have: X = B, Y = G and Z = R. + /// /// Converts a representing a collection of /// pixels to a representing @@ -203,6 +317,15 @@ namespace SixLabors.ImageSharp.PixelFormats.Utils public static void ToBgra32(ReadOnlySpan source, Span dest) => SimdUtils.Pad3Shuffle4(source, dest, default); + /// + /// Converts a representing a collection of + /// pixels to a representing + /// a collection of pixels. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static void ToAbgr32(ReadOnlySpan source, Span dest) + => SimdUtils.Pad3Shuffle4(source, dest, new DefaultPad3Shuffle4(2, 1, 0, 3)); + /// /// Converts a representing a collection of /// pixels to a representing diff --git a/tests/ImageSharp.Tests/Color/ColorTests.CastFrom.cs b/tests/ImageSharp.Tests/Color/ColorTests.CastFrom.cs index 38b94f486..ec03847df 100644 --- a/tests/ImageSharp.Tests/Color/ColorTests.CastFrom.cs +++ b/tests/ImageSharp.Tests/Color/ColorTests.CastFrom.cs @@ -63,6 +63,19 @@ namespace SixLabors.ImageSharp.Tests Assert.Equal(source, data); } + [Fact] + public void Abgr32() + { + var source = new Abgr32(1, 22, 33, 231); + + // Act: + Color color = source; + + // Assert: + Abgr32 data = color.ToPixel(); + Assert.Equal(source, data); + } + [Fact] public void Rgb24() { diff --git a/tests/ImageSharp.Tests/Color/ColorTests.CastTo.cs b/tests/ImageSharp.Tests/Color/ColorTests.CastTo.cs index bfc290c2e..1997cc6b1 100644 --- a/tests/ImageSharp.Tests/Color/ColorTests.CastTo.cs +++ b/tests/ImageSharp.Tests/Color/ColorTests.CastTo.cs @@ -64,6 +64,19 @@ namespace SixLabors.ImageSharp.Tests Assert.Equal(source, data); } + [Fact] + public void Abgr32() + { + var source = new Abgr32(1, 22, 33, 231); + + // Act: + var color = new Color(source); + + // Assert: + Abgr32 data = color; + Assert.Equal(source, data); + } + [Fact] public void Rgb24() { diff --git a/tests/ImageSharp.Tests/Color/ColorTests.ConstructFrom.cs b/tests/ImageSharp.Tests/Color/ColorTests.ConstructFrom.cs index 89276014b..d61361c80 100644 --- a/tests/ImageSharp.Tests/Color/ColorTests.ConstructFrom.cs +++ b/tests/ImageSharp.Tests/Color/ColorTests.ConstructFrom.cs @@ -63,6 +63,19 @@ namespace SixLabors.ImageSharp.Tests Assert.Equal(source, data); } + [Fact] + public void Abgr32() + { + var source = new Abgr32(1, 22, 33, 231); + + // Act: + var color = new Color(source); + + // Assert: + Abgr32 data = color.ToPixel(); + Assert.Equal(source, data); + } + [Fact] public void Rgb24() { diff --git a/tests/ImageSharp.Tests/Image/ImageCloneTests.cs b/tests/ImageSharp.Tests/Image/ImageCloneTests.cs index f60264334..c1012e2df 100644 --- a/tests/ImageSharp.Tests/Image/ImageCloneTests.cs +++ b/tests/ImageSharp.Tests/Image/ImageCloneTests.cs @@ -56,6 +56,32 @@ namespace SixLabors.ImageSharp.Tests }); } + [Theory] + [WithTestPatternImages(9, 9, PixelTypes.Rgba32)] + public void CloneAs_ToAbgr32(TestImageProvider provider) + { + using (Image image = provider.GetImage()) + using (Image clone = image.CloneAs()) + { + for (int y = 0; y < image.Height; y++) + { + Span row = image.GetPixelRowSpan(y); + Span rowClone = clone.GetPixelRowSpan(y); + + for (int x = 0; x < image.Width; x++) + { + Rgba32 expected = row[x]; + Abgr32 actual = rowClone[x]; + + Assert.Equal(expected.R, actual.R); + Assert.Equal(expected.G, actual.G); + Assert.Equal(expected.B, actual.B); + Assert.Equal(expected.A, actual.A); + } + } + } + } + [Theory] [WithTestPatternImages(9, 9, PixelTypes.Rgba32)] public void CloneAs_ToBgr24(TestImageProvider provider) diff --git a/tests/ImageSharp.Tests/PixelFormats/Abgr32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Abgr32Tests.cs new file mode 100644 index 000000000..278de3357 --- /dev/null +++ b/tests/ImageSharp.Tests/PixelFormats/Abgr32Tests.cs @@ -0,0 +1,148 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +using System.Numerics; +using SixLabors.ImageSharp.PixelFormats; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.PixelFormats +{ + [Trait("Category", "PixelFormats")] + public class Abgr32Tests + { + /// + /// Tests the equality operators for equality. + /// + [Fact] + public void AreEqual() + { + var color1 = new Abgr32(byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue); + var color2 = new Abgr32(byte.MaxValue, byte.MaxValue, byte.MaxValue); + + Assert.Equal(color1, color2); + } + + /// + /// Tests the equality operators for inequality. + /// + [Fact] + public void AreNotEqual() + { + var color1 = new Abgr32(0, 0, byte.MaxValue, byte.MaxValue); + var color2 = new Abgr32(byte.MaxValue, byte.MaxValue, byte.MaxValue); + + Assert.NotEqual(color1, color2); + } + + public static readonly TheoryData ColorData = + new() + { + { 1, 2, 3, 4 }, + { 4, 5, 6, 7 }, + { 0, 255, 42, 0 }, + { 1, 2, 3, 255 } + }; + + [Theory] + [MemberData(nameof(ColorData))] + public void Constructor(byte b, byte g, byte r, byte a) + { + var p = new Abgr32(r, g, b, a); + + Assert.Equal(r, p.R); + Assert.Equal(g, p.G); + Assert.Equal(b, p.B); + Assert.Equal(a, p.A); + } + + [Fact] + public unsafe void ByteLayoutIsSequentialBgra() + { + var color = new Abgr32(1, 2, 3, 4); + byte* ptr = (byte*)&color; + + Assert.Equal(4, ptr[0]); + Assert.Equal(3, ptr[1]); + Assert.Equal(2, ptr[2]); + Assert.Equal(1, ptr[3]); + } + + [Theory] + [MemberData(nameof(ColorData))] + public void Equality_WhenTrue(byte r, byte g, byte b, byte a) + { + var x = new Abgr32(r, g, b, a); + var y = new Abgr32(r, g, b, a); + + Assert.True(x.Equals(y)); + Assert.True(x.Equals((object)y)); + Assert.Equal(x.GetHashCode(), y.GetHashCode()); + } + + [Theory] + [InlineData(1, 2, 3, 4, 1, 2, 3, 5)] + [InlineData(0, 0, 255, 0, 0, 0, 244, 0)] + [InlineData(0, 255, 0, 0, 0, 244, 0, 0)] + [InlineData(1, 255, 0, 0, 0, 255, 0, 0)] + public void Equality_WhenFalse(byte b1, byte g1, byte r1, byte a1, byte b2, byte g2, byte r2, byte a2) + { + var x = new Abgr32(r1, g1, b1, a1); + var y = new Abgr32(r2, g2, b2, a2); + + Assert.False(x.Equals(y)); + Assert.False(x.Equals((object)y)); + } + + [Fact] + public void FromRgba32() + { + var abgr = default(Abgr32); + abgr.FromRgba32(new Rgba32(1, 2, 3, 4)); + + Assert.Equal(1, abgr.R); + Assert.Equal(2, abgr.G); + Assert.Equal(3, abgr.B); + Assert.Equal(4, abgr.A); + } + + private static Vector4 Vec(byte r, byte g, byte b, byte a = 255) => new Vector4( + r / 255f, + g / 255f, + b / 255f, + a / 255f); + + [Fact] + public void FromVector4() + { + var c = default(Abgr32); + c.FromVector4(Vec(1, 2, 3, 4)); + + Assert.Equal(1, c.R); + Assert.Equal(2, c.G); + Assert.Equal(3, c.B); + Assert.Equal(4, c.A); + } + + [Fact] + public void ToVector4() + { + var abgr = new Abgr32(1, 2, 3, 4); + + Assert.Equal(Vec(1, 2, 3, 4), abgr.ToVector4()); + } + + [Fact] + public void Abgr32_FromBgra5551() + { + // arrange + var abgr = default(Abgr32); + uint expected = uint.MaxValue; + + // act + abgr.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); + + // assert + Assert.Equal(expected, abgr.PackedValue); + } + } +} diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs index 4b8f4c2ea..7a2f29e2c 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs @@ -96,12 +96,13 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Fact] public void FromRgba32() { - var rgb = default(Rgb24); - rgb.FromRgba32(new Rgba32(1, 2, 3, 4)); + var bgra = default(Bgra32); + bgra.FromRgba32(new Rgba32(1, 2, 3, 4)); - Assert.Equal(1, rgb.R); - Assert.Equal(2, rgb.G); - Assert.Equal(3, rgb.B); + Assert.Equal(1, bgra.R); + Assert.Equal(2, bgra.G); + Assert.Equal(3, bgra.B); + Assert.Equal(4, bgra.A); } private static Vector4 Vec(byte r, byte g, byte b, byte a = 255) => new Vector4( diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.ReferenceImplementations.cs b/tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.ReferenceImplementations.cs index 8b3483145..e51ee233c 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.ReferenceImplementations.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.ReferenceImplementations.cs @@ -60,6 +60,21 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats return buffer; } + public static byte[] MakeAbgr32ByteArray(byte r, byte g, byte b, byte a) + { + var buffer = new byte[256]; + + for (int i = 0; i < buffer.Length; i += 4) + { + buffer[i] = a; + buffer[i + 1] = b; + buffer[i + 2] = g; + buffer[i + 3] = r; + } + + return buffer; + } + internal static void To( Configuration configuration, ReadOnlySpan sourcePixels, diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.cs index 315f9f776..986f4189b 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.cs @@ -56,6 +56,20 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(expected, actual); } + + [Theory] + [MemberData(nameof(RgbaData))] + public void ToAbgr32(byte r, byte g, byte b, byte a) + { + byte[] source = ReferenceImplementations.MakeRgba32ByteArray(r, g, b, a); + byte[] actual = new byte[source.Length]; + + PixelConverter.FromRgba32.ToAbgr32(source, actual); + + byte[] expected = ReferenceImplementations.MakeAbgr32ByteArray(r, g, b, a); + + Assert.Equal(expected, actual); + } } public class FromArgb32 : PixelConverterTests @@ -119,5 +133,50 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(expected, actual); } } + + public class FromAbgr32 : PixelConverterTests + { + [Theory] + [MemberData(nameof(RgbaData))] + public void ToArgb32(byte r, byte g, byte b, byte a) + { + byte[] source = ReferenceImplementations.MakeAbgr32ByteArray(r, g, b, a); + byte[] actual = new byte[source.Length]; + + PixelConverter.FromAbgr32.ToArgb32(source, actual); + + byte[] expected = ReferenceImplementations.MakeArgb32ByteArray(r, g, b, a); + + Assert.Equal(expected, actual); + } + + [Theory] + [MemberData(nameof(RgbaData))] + public void ToRgba32(byte r, byte g, byte b, byte a) + { + byte[] source = ReferenceImplementations.MakeAbgr32ByteArray(r, g, b, a); + byte[] actual = new byte[source.Length]; + + PixelConverter.FromAbgr32.ToRgba32(source, actual); + + byte[] expected = ReferenceImplementations.MakeRgba32ByteArray(r, g, b, a); + + Assert.Equal(expected, actual); + } + + [Theory] + [MemberData(nameof(RgbaData))] + public void ToBgra32(byte r, byte g, byte b, byte a) + { + byte[] source = ReferenceImplementations.MakeAbgr32ByteArray(r, g, b, a); + byte[] actual = new byte[source.Length]; + + PixelConverter.FromAbgr32.ToBgra32(source, actual); + + byte[] expected = ReferenceImplementations.MakeBgra32ByteArray(r, g, b, a); + + Assert.Equal(expected, actual); + } + } } } diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/Generated/PixelOperationsTests.Specialized.Generated.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/Generated/PixelOperationsTests.Specialized.Generated.cs index 1069eb9ac..10b06df3b 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/Generated/PixelOperationsTests.Specialized.Generated.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/Generated/PixelOperationsTests.Specialized.Generated.cs @@ -12,8 +12,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations { public partial class PixelOperationsTests { - - public partial class A8_OperationsTests : PixelOperationsTests + public partial class A8_OperationsTests : PixelOperationsTests { public A8_OperationsTests(ITestOutputHelper output) : base(output) @@ -32,7 +31,6 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations Assert.Equal(PixelAlphaRepresentation.Unassociated, alphaRepresentation); } } - public partial class Argb32_OperationsTests : PixelOperationsTests { public Argb32_OperationsTests(ITestOutputHelper output) @@ -52,7 +50,25 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations Assert.Equal(PixelAlphaRepresentation.Unassociated, alphaRepresentation); } } + public partial class Abgr32_OperationsTests : PixelOperationsTests + { + public Abgr32_OperationsTests(ITestOutputHelper output) + : base(output) + { + } + protected override PixelOperations Operations => Abgr32.PixelOperations.Instance; + + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + + [Fact] + public void PixelTypeInfoHasCorrectAlphaRepresentation() + { + var alphaRepresentation = this.Operations.GetPixelTypeInfo().AlphaRepresentation; + Assert.Equal(PixelAlphaRepresentation.Unassociated, alphaRepresentation); + } + } public partial class Bgr24_OperationsTests : PixelOperationsTests { public Bgr24_OperationsTests(ITestOutputHelper output) @@ -72,7 +88,6 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations Assert.Equal(PixelAlphaRepresentation.None, alphaRepresentation); } } - public partial class Bgr565_OperationsTests : PixelOperationsTests { public Bgr565_OperationsTests(ITestOutputHelper output) @@ -92,7 +107,6 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations Assert.Equal(PixelAlphaRepresentation.None, alphaRepresentation); } } - public partial class Bgra32_OperationsTests : PixelOperationsTests { public Bgra32_OperationsTests(ITestOutputHelper output) @@ -112,7 +126,6 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations Assert.Equal(PixelAlphaRepresentation.Unassociated, alphaRepresentation); } } - public partial class Bgra4444_OperationsTests : PixelOperationsTests { public Bgra4444_OperationsTests(ITestOutputHelper output) @@ -132,7 +145,6 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations Assert.Equal(PixelAlphaRepresentation.Unassociated, alphaRepresentation); } } - public partial class Bgra5551_OperationsTests : PixelOperationsTests { public Bgra5551_OperationsTests(ITestOutputHelper output) @@ -152,7 +164,6 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations Assert.Equal(PixelAlphaRepresentation.Unassociated, alphaRepresentation); } } - public partial class Byte4_OperationsTests : PixelOperationsTests { public Byte4_OperationsTests(ITestOutputHelper output) @@ -172,7 +183,6 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations Assert.Equal(PixelAlphaRepresentation.Unassociated, alphaRepresentation); } } - public partial class HalfSingle_OperationsTests : PixelOperationsTests { public HalfSingle_OperationsTests(ITestOutputHelper output) @@ -192,7 +202,6 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations Assert.Equal(PixelAlphaRepresentation.None, alphaRepresentation); } } - public partial class HalfVector2_OperationsTests : PixelOperationsTests { public HalfVector2_OperationsTests(ITestOutputHelper output) @@ -212,7 +221,6 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations Assert.Equal(PixelAlphaRepresentation.None, alphaRepresentation); } } - public partial class HalfVector4_OperationsTests : PixelOperationsTests { public HalfVector4_OperationsTests(ITestOutputHelper output) @@ -232,7 +240,6 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations Assert.Equal(PixelAlphaRepresentation.Unassociated, alphaRepresentation); } } - public partial class L16_OperationsTests : PixelOperationsTests { public L16_OperationsTests(ITestOutputHelper output) @@ -252,7 +259,6 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations Assert.Equal(PixelAlphaRepresentation.None, alphaRepresentation); } } - public partial class L8_OperationsTests : PixelOperationsTests { public L8_OperationsTests(ITestOutputHelper output) @@ -272,7 +278,6 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations Assert.Equal(PixelAlphaRepresentation.None, alphaRepresentation); } } - public partial class La16_OperationsTests : PixelOperationsTests { public La16_OperationsTests(ITestOutputHelper output) @@ -292,7 +297,6 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations Assert.Equal(PixelAlphaRepresentation.Unassociated, alphaRepresentation); } } - public partial class La32_OperationsTests : PixelOperationsTests { public La32_OperationsTests(ITestOutputHelper output) @@ -312,7 +316,6 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations Assert.Equal(PixelAlphaRepresentation.Unassociated, alphaRepresentation); } } - public partial class NormalizedByte2_OperationsTests : PixelOperationsTests { public NormalizedByte2_OperationsTests(ITestOutputHelper output) @@ -332,7 +335,6 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations Assert.Equal(PixelAlphaRepresentation.None, alphaRepresentation); } } - public partial class NormalizedByte4_OperationsTests : PixelOperationsTests { public NormalizedByte4_OperationsTests(ITestOutputHelper output) @@ -352,7 +354,6 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations Assert.Equal(PixelAlphaRepresentation.Unassociated, alphaRepresentation); } } - public partial class NormalizedShort2_OperationsTests : PixelOperationsTests { public NormalizedShort2_OperationsTests(ITestOutputHelper output) @@ -372,7 +373,6 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations Assert.Equal(PixelAlphaRepresentation.None, alphaRepresentation); } } - public partial class NormalizedShort4_OperationsTests : PixelOperationsTests { public NormalizedShort4_OperationsTests(ITestOutputHelper output) @@ -392,7 +392,6 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations Assert.Equal(PixelAlphaRepresentation.Unassociated, alphaRepresentation); } } - public partial class Rg32_OperationsTests : PixelOperationsTests { public Rg32_OperationsTests(ITestOutputHelper output) @@ -412,7 +411,6 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations Assert.Equal(PixelAlphaRepresentation.None, alphaRepresentation); } } - public partial class Rgb24_OperationsTests : PixelOperationsTests { public Rgb24_OperationsTests(ITestOutputHelper output) @@ -432,7 +430,6 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations Assert.Equal(PixelAlphaRepresentation.None, alphaRepresentation); } } - public partial class Rgb48_OperationsTests : PixelOperationsTests { public Rgb48_OperationsTests(ITestOutputHelper output) @@ -452,7 +449,6 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations Assert.Equal(PixelAlphaRepresentation.None, alphaRepresentation); } } - public partial class Rgba1010102_OperationsTests : PixelOperationsTests { public Rgba1010102_OperationsTests(ITestOutputHelper output) @@ -472,7 +468,6 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations Assert.Equal(PixelAlphaRepresentation.Unassociated, alphaRepresentation); } } - public partial class Rgba32_OperationsTests : PixelOperationsTests { public Rgba32_OperationsTests(ITestOutputHelper output) @@ -492,7 +487,6 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations Assert.Equal(PixelAlphaRepresentation.Unassociated, alphaRepresentation); } } - public partial class Rgba64_OperationsTests : PixelOperationsTests { public Rgba64_OperationsTests(ITestOutputHelper output) @@ -512,7 +506,6 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations Assert.Equal(PixelAlphaRepresentation.Unassociated, alphaRepresentation); } } - public partial class RgbaVector_OperationsTests : PixelOperationsTests { public RgbaVector_OperationsTests(ITestOutputHelper output) @@ -532,7 +525,6 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations Assert.Equal(PixelAlphaRepresentation.Unassociated, alphaRepresentation); } } - public partial class Short2_OperationsTests : PixelOperationsTests { public Short2_OperationsTests(ITestOutputHelper output) @@ -552,7 +544,6 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations Assert.Equal(PixelAlphaRepresentation.None, alphaRepresentation); } } - public partial class Short4_OperationsTests : PixelOperationsTests { public Short4_OperationsTests(ITestOutputHelper output) diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/Generated/_Common.ttinclude b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/Generated/_Common.ttinclude index 8c436eecc..6ef3e914f 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/Generated/_Common.ttinclude +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/Generated/_Common.ttinclude @@ -16,6 +16,7 @@ using Xunit.Abstractions; { "A8", "Argb32", + "Abgr32", "Bgra32", "Bgra4444", "Bgra5551", @@ -38,6 +39,7 @@ using Xunit.Abstractions; { "A8", "Argb32", + "Abgr32", "Bgr24", "Bgr565", "Bgra32", diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs index a2688359f..2a89c1d39 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs @@ -322,6 +322,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations public static readonly TheoryData Generic_To_Data = new TheoryData { + new TestPixel(), new TestPixel(), new TestPixel(), new TestPixel(), @@ -586,6 +587,50 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations (s, d) => this.Operations.ToBgra32Bytes(this.Configuration, s, d.GetSpan(), count)); } + [Theory] + [MemberData(nameof(ArraySizesData))] + public void FromAbgr32Bytes(int count) + { + byte[] source = CreateByteTestData(count * 4); + var expected = new TPixel[count]; + + for (int i = 0; i < count; i++) + { + int i4 = i * 4; + + expected[i].FromAbgr32(new Abgr32(source[i4 + 3], source[i4 + 2], source[i4 + 1], source[i4 + 0])); + } + + TestOperation( + source, + expected, + (s, d) => this.Operations.FromAbgr32Bytes(this.Configuration, s, d.GetSpan(), count)); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToAbgr32Bytes(int count) + { + TPixel[] source = CreatePixelTestData(count); + byte[] expected = new byte[count * 4]; + var abgr = default(Abgr32); + + for (int i = 0; i < count; i++) + { + int i4 = i * 4; + abgr.FromScaledVector4(source[i].ToScaledVector4()); + expected[i4] = abgr.A; + expected[i4 + 1] = abgr.B; + expected[i4 + 2] = abgr.G; + expected[i4 + 3] = abgr.R; + } + + TestOperation( + source, + expected, + (s, d) => this.Operations.ToAbgr32Bytes(this.Configuration, s, d.GetSpan(), count)); + } + [Theory] [MemberData(nameof(ArraySizesData))] public void FromBgra5551Bytes(int count) diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs index bc66d404b..aff16d6d8 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs @@ -230,6 +230,22 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(expected, actual); } + [Fact] + public void Rgba32_FromAbgr32_ToRgba32() + { + // arrange + var rgba = default(Rgba32); + var actual = default(Abgr32); + var expected = new Abgr32(0x1a, 0, 0x80, 0); + + // act + rgba.FromAbgr32(expected); + actual.FromRgba32(rgba); + + // assert + Assert.Equal(expected, actual); + } + [Fact] public void Rgba32_FromArgb32_ToArgb32() { diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs index 8daf960d6..e08cd2950 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs @@ -183,6 +183,16 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(expected, actual); } + [Fact] + public void ConstructFrom_Abgr32() + { + var expected = new Rgba64(5140, 9766, 19532, 29555); + var source = new Abgr32(20, 38, 76, 115); + var actual = new Rgba64(source); + + Assert.Equal(expected, actual); + } + [Fact] public void ConstructFrom_Rgb24() { @@ -257,6 +267,20 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(expected, actual); } + [Fact] + public void ToAbgr32_Retval() + { + // arrange + var source = new Rgba64(5140, 9766, 19532, 29555); + var expected = new Abgr32(20, 38, 76, 115); + + // act + var actual = source.ToAbgr32(); + + // assert + Assert.Equal(expected, actual); + } + [Fact] public void ToRgb24_Retval() { diff --git a/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs index 3709205ac..a95ac9ab9 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs @@ -150,6 +150,24 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(expected, actual); } + [Fact] + public void Short4_FromAbgrb32_ToRgba32() + { + // arrange + var short4 = default(Short4); + var actual = default(Abgr32); + var expected = new Abgr32(20, 38, 0, 255); + + // act + short4.FromAbgr32(expected); + Rgba32 temp = default; + short4.ToRgba32(ref temp); + actual.FromRgba32(temp); + + // assert + Assert.Equal(expected, actual); + } + [Fact] public void Short4_FromRgb48_ToRgb48() { diff --git a/tests/ImageSharp.Tests/TestFormat.cs b/tests/ImageSharp.Tests/TestFormat.cs index c8d0633d7..6c2b97eb6 100644 --- a/tests/ImageSharp.Tests/TestFormat.cs +++ b/tests/ImageSharp.Tests/TestFormat.cs @@ -310,6 +310,10 @@ namespace SixLabors.ImageSharp.Tests { } + public void FromAbgr32(Abgr32 source) + { + } + public void FromL8(L8 source) { } diff --git a/tests/ImageSharp.Tests/TestUtilities/PixelTypes.cs b/tests/ImageSharp.Tests/TestUtilities/PixelTypes.cs index eb840231c..8ba383125 100644 --- a/tests/ImageSharp.Tests/TestUtilities/PixelTypes.cs +++ b/tests/ImageSharp.Tests/TestUtilities/PixelTypes.cs @@ -69,6 +69,8 @@ namespace SixLabors.ImageSharp.Tests La32 = 1 << 26, + Abgr32 = 1 << 27, + // TODO: Add multi-flag entries by rules defined in PackedPixelConverterHelper // "All" is handled as a separate, individual case instead of using bitwise OR diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/TestUtilityExtensionsTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/TestUtilityExtensionsTests.cs index bb9ed8260..1a46f91e5 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/TestUtilityExtensionsTests.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/TestUtilityExtensionsTests.cs @@ -112,14 +112,15 @@ namespace SixLabors.ImageSharp.Tests [Fact] public void ExpandAllTypes_2() { - PixelTypes pixelTypes = PixelTypes.Rgba32 | PixelTypes.Bgra32 | PixelTypes.RgbaVector; + PixelTypes pixelTypes = PixelTypes.Rgba32 | PixelTypes.Bgra32 | PixelTypes.Abgr32 | PixelTypes.RgbaVector; IEnumerable> expanded = pixelTypes.ExpandAllTypes(); - Assert.Equal(3, expanded.Count()); + Assert.Equal(4, expanded.Count()); AssertContainsPixelType(PixelTypes.Rgba32, expanded); AssertContainsPixelType(PixelTypes.Bgra32, expanded); + AssertContainsPixelType(PixelTypes.Abgr32, expanded); AssertContainsPixelType(PixelTypes.RgbaVector, expanded); } From 98e44174293bbc0718e4cbdeca7039a2ea4b105c Mon Sep 17 00:00:00 2001 From: Ynse Hoornenborg Date: Mon, 6 Dec 2021 22:23:17 +0100 Subject: [PATCH 067/121] Fix pixel conversion tests --- .../Helpers/Shuffle/IComponentShuffle.cs | 4 +-- .../PixelImplementations/Abgr32.cs | 2 +- .../Argb32.PixelOperations.Generated.cs | 27 +++++++++++++++++++ .../Bgr24.PixelOperations.Generated.cs | 27 +++++++++++++++++++ .../Bgra32.PixelOperations.Generated.cs | 27 +++++++++++++++++++ .../Bgra5551.PixelOperations.Generated.cs | 20 ++++++++++++++ .../L16.PixelOperations.Generated.cs | 20 ++++++++++++++ .../Generated/L8.PixelOperations.Generated.cs | 20 ++++++++++++++ .../La16.PixelOperations.Generated.cs | 20 ++++++++++++++ .../La32.PixelOperations.Generated.cs | 20 ++++++++++++++ .../Rgb24.PixelOperations.Generated.cs | 27 +++++++++++++++++++ .../Rgb48.PixelOperations.Generated.cs | 20 ++++++++++++++ .../Rgba32.PixelOperations.Generated.cs | 27 +++++++++++++++++++ .../Rgba64.PixelOperations.Generated.cs | 20 ++++++++++++++ 14 files changed, 278 insertions(+), 3 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs b/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs index 8d1236ee9..2fc2b4430 100644 --- a/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs +++ b/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs @@ -219,8 +219,8 @@ namespace SixLabors.ImageSharp // tmp2 = [W 0 Y 0] // tmp3=ROTL(16, tmp2) = [Y 0 W 0] // tmp1 + tmp3 = [Y Z W X] - uint tmp1 = packed & 0xFF00FF00; - uint tmp2 = packed & 0x00FF00FF; + uint tmp1 = packed & 0x00FF00FF; + uint tmp2 = packed & 0xFF00FF00; uint tmp3 = (tmp2 << 16) | (tmp2 >> 16); Unsafe.Add(ref dBase, i) = tmp1 + tmp3; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs index 157ac2a83..0a95fc1ff 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs @@ -204,7 +204,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void FromAbgr32(Abgr32 source) => this.PackedValue = source.PackedValue; + public void FromAbgr32(Abgr32 source) => this = source; /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Argb32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Argb32.PixelOperations.Generated.cs index cedd1762d..0f183df0d 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Argb32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Argb32.PixelOperations.Generated.cs @@ -85,6 +85,33 @@ namespace SixLabors.ImageSharp.PixelFormats PixelConverter.FromRgba32.ToArgb32(source, dest); } /// + public override void ToAbgr32( + Configuration configuration, + ReadOnlySpan sourcePixels, + Span destinationPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + + ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); + Span dest = MemoryMarshal.Cast(destinationPixels); + PixelConverter.FromArgb32.ToAbgr32(source, dest); + } + + /// + public override void FromAbgr32( + Configuration configuration, + ReadOnlySpan sourcePixels, + Span destinationPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + + ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); + Span dest = MemoryMarshal.Cast(destinationPixels); + PixelConverter.FromAbgr32.ToArgb32(source, dest); + } + /// public override void ToBgra32( Configuration configuration, ReadOnlySpan sourcePixels, diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgr24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgr24.PixelOperations.Generated.cs index c98e35656..ea08c6391 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgr24.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgr24.PixelOperations.Generated.cs @@ -112,6 +112,33 @@ namespace SixLabors.ImageSharp.PixelFormats PixelConverter.FromArgb32.ToBgr24(source, dest); } /// + public override void ToAbgr32( + Configuration configuration, + ReadOnlySpan sourcePixels, + Span destinationPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + + ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); + Span dest = MemoryMarshal.Cast(destinationPixels); + PixelConverter.FromBgr24.ToAbgr32(source, dest); + } + + /// + public override void FromAbgr32( + Configuration configuration, + ReadOnlySpan sourcePixels, + Span destinationPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + + ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); + Span dest = MemoryMarshal.Cast(destinationPixels); + PixelConverter.FromAbgr32.ToBgr24(source, dest); + } + /// public override void ToBgra32( Configuration configuration, ReadOnlySpan sourcePixels, diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgra32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgra32.PixelOperations.Generated.cs index 02bb67532..0ec9a552c 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgra32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgra32.PixelOperations.Generated.cs @@ -112,6 +112,33 @@ namespace SixLabors.ImageSharp.PixelFormats PixelConverter.FromArgb32.ToBgra32(source, dest); } /// + public override void ToAbgr32( + Configuration configuration, + ReadOnlySpan sourcePixels, + Span destinationPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + + ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); + Span dest = MemoryMarshal.Cast(destinationPixels); + PixelConverter.FromBgra32.ToAbgr32(source, dest); + } + + /// + public override void FromAbgr32( + Configuration configuration, + ReadOnlySpan sourcePixels, + Span destinationPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + + ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); + Span dest = MemoryMarshal.Cast(destinationPixels); + PixelConverter.FromAbgr32.ToBgra32(source, dest); + } + /// public override void ToRgb24( Configuration configuration, ReadOnlySpan sourcePixels, diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgra5551.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgra5551.PixelOperations.Generated.cs index a02ffc3a4..877ce1a6f 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgra5551.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgra5551.PixelOperations.Generated.cs @@ -59,6 +59,26 @@ namespace SixLabors.ImageSharp.PixelFormats } } /// + public override void ToAbgr32( + Configuration configuration, + ReadOnlySpan sourcePixels, + Span destinationPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + + ref Bgra5551 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Abgr32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, i); + ref Abgr32 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromBgra5551(sp); + } + } + /// public override void ToBgr24( Configuration configuration, ReadOnlySpan sourcePixels, diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/L16.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/L16.PixelOperations.Generated.cs index 954ef2d98..94eb3229b 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/L16.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/L16.PixelOperations.Generated.cs @@ -59,6 +59,26 @@ namespace SixLabors.ImageSharp.PixelFormats } } /// + public override void ToAbgr32( + Configuration configuration, + ReadOnlySpan sourcePixels, + Span destinationPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + + ref L16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Abgr32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref L16 sp = ref Unsafe.Add(ref sourceRef, i); + ref Abgr32 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromL16(sp); + } + } + /// public override void ToBgr24( Configuration configuration, ReadOnlySpan sourcePixels, diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/L8.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/L8.PixelOperations.Generated.cs index b3d809de5..a748590f7 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/L8.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/L8.PixelOperations.Generated.cs @@ -59,6 +59,26 @@ namespace SixLabors.ImageSharp.PixelFormats } } /// + public override void ToAbgr32( + Configuration configuration, + ReadOnlySpan sourcePixels, + Span destinationPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + + ref L8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Abgr32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref L8 sp = ref Unsafe.Add(ref sourceRef, i); + ref Abgr32 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromL8(sp); + } + } + /// public override void ToBgr24( Configuration configuration, ReadOnlySpan sourcePixels, diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/La16.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/La16.PixelOperations.Generated.cs index 14618d026..f47cd6c40 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/La16.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/La16.PixelOperations.Generated.cs @@ -59,6 +59,26 @@ namespace SixLabors.ImageSharp.PixelFormats } } /// + public override void ToAbgr32( + Configuration configuration, + ReadOnlySpan sourcePixels, + Span destinationPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + + ref La16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Abgr32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref La16 sp = ref Unsafe.Add(ref sourceRef, i); + ref Abgr32 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromLa16(sp); + } + } + /// public override void ToBgr24( Configuration configuration, ReadOnlySpan sourcePixels, diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/La32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/La32.PixelOperations.Generated.cs index 9620a1df4..f0c2c3323 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/La32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/La32.PixelOperations.Generated.cs @@ -59,6 +59,26 @@ namespace SixLabors.ImageSharp.PixelFormats } } /// + public override void ToAbgr32( + Configuration configuration, + ReadOnlySpan sourcePixels, + Span destinationPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + + ref La32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Abgr32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref La32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Abgr32 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromLa32(sp); + } + } + /// public override void ToBgr24( Configuration configuration, ReadOnlySpan sourcePixels, diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgb24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgb24.PixelOperations.Generated.cs index 2fe7f3c20..75f677cdd 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgb24.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgb24.PixelOperations.Generated.cs @@ -112,6 +112,33 @@ namespace SixLabors.ImageSharp.PixelFormats PixelConverter.FromArgb32.ToRgb24(source, dest); } /// + public override void ToAbgr32( + Configuration configuration, + ReadOnlySpan sourcePixels, + Span destinationPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + + ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); + Span dest = MemoryMarshal.Cast(destinationPixels); + PixelConverter.FromRgb24.ToAbgr32(source, dest); + } + + /// + public override void FromAbgr32( + Configuration configuration, + ReadOnlySpan sourcePixels, + Span destinationPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + + ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); + Span dest = MemoryMarshal.Cast(destinationPixels); + PixelConverter.FromAbgr32.ToRgb24(source, dest); + } + /// public override void ToBgra32( Configuration configuration, ReadOnlySpan sourcePixels, diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgb48.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgb48.PixelOperations.Generated.cs index 031008fe1..22b96fd5a 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgb48.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgb48.PixelOperations.Generated.cs @@ -59,6 +59,26 @@ namespace SixLabors.ImageSharp.PixelFormats } } /// + public override void ToAbgr32( + Configuration configuration, + ReadOnlySpan sourcePixels, + Span destinationPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + + ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Abgr32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); + ref Abgr32 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromRgb48(sp); + } + } + /// public override void ToBgr24( Configuration configuration, ReadOnlySpan sourcePixels, diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgba32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgba32.PixelOperations.Generated.cs index 16f96d2da..093182c82 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgba32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgba32.PixelOperations.Generated.cs @@ -66,6 +66,33 @@ namespace SixLabors.ImageSharp.PixelFormats PixelConverter.FromArgb32.ToRgba32(source, dest); } /// + public override void ToAbgr32( + Configuration configuration, + ReadOnlySpan sourcePixels, + Span destinationPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + + ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); + Span dest = MemoryMarshal.Cast(destinationPixels); + PixelConverter.FromRgba32.ToAbgr32(source, dest); + } + + /// + public override void FromAbgr32( + Configuration configuration, + ReadOnlySpan sourcePixels, + Span destinationPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + + ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); + Span dest = MemoryMarshal.Cast(destinationPixels); + PixelConverter.FromAbgr32.ToRgba32(source, dest); + } + /// public override void ToBgra32( Configuration configuration, ReadOnlySpan sourcePixels, diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgba64.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgba64.PixelOperations.Generated.cs index 1f1571e91..ce1b53e66 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgba64.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgba64.PixelOperations.Generated.cs @@ -59,6 +59,26 @@ namespace SixLabors.ImageSharp.PixelFormats } } /// + public override void ToAbgr32( + Configuration configuration, + ReadOnlySpan sourcePixels, + Span destinationPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + + ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Abgr32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); + ref Abgr32 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromRgba64(sp); + } + } + /// public override void ToBgr24( Configuration configuration, ReadOnlySpan sourcePixels, From a8d3cebde8690896a1919df4fac585ad48360dd8 Mon Sep 17 00:00:00 2001 From: Ynse Hoornenborg Date: Mon, 6 Dec 2021 22:31:23 +0100 Subject: [PATCH 068/121] Remove dead code from IComponentShuffle --- .../Helpers/Shuffle/IComponentShuffle.cs | 37 ------------------- 1 file changed, 37 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs b/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs index 2fc2b4430..4c02deb2d 100644 --- a/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs +++ b/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs @@ -227,41 +227,4 @@ namespace SixLabors.ImageSharp } } } - - internal readonly struct XZWYShuffle4 : IShuffle4 - { - public byte Control - { - [MethodImpl(InliningOptions.ShortMethod)] - get => SimdUtils.Shuffle.MmShuffle(1, 3, 2, 0); - } - - [MethodImpl(InliningOptions.ShortMethod)] - public void RunFallbackShuffle(ReadOnlySpan source, Span dest) - { - ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); - ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); - int n = source.Length / 4; - - for (int i = 0; i < n; i++) - { - uint packed = Unsafe.Add(ref sBase, i); - - // packed = [W Z Y X] - // tmp1 = [0 0 0 X] - // tmp2 = [W Z 0 0] - // tmp3 = [0 0 Y 0] - // tmp4=ROTR(8, tmp2) = [0 W Z 0] - // tmp5=ROTL(16, tmp3) = [Y 0 0 0] - // tmp1+ tmp3 + tmp4 = [Y W Z X] - uint tmp1 = packed & 0x000000FF; - uint tmp2 = packed & 0xFFFF0000; - uint tmp3 = packed & 0x0000FF00; - uint tmp4 = tmp2 >> 8; - uint tmp5 = tmp3 << 16; - - Unsafe.Add(ref dBase, i) = tmp1 + tmp4 + tmp5; - } - } - } } From 296e412f3fe0ff9adc364d6139d45bb3f4d375f7 Mon Sep 17 00:00:00 2001 From: Ynse Hoornenborg Date: Fri, 10 Dec 2021 16:57:05 +0100 Subject: [PATCH 069/121] Fixes after rebasing to latest master --- .gitattributes | 8 ++------ tests/ImageSharp.Tests/Image/ImageCloneTests.cs | 17 +++++++++-------- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/.gitattributes b/.gitattributes index 355b64dce..70ced6903 100644 --- a/.gitattributes +++ b/.gitattributes @@ -87,6 +87,7 @@ *.eot binary *.exe binary *.otf binary +*.pbm binary *.pdf binary *.ppt binary *.pptx binary @@ -94,6 +95,7 @@ *.snk binary *.ttc binary *.ttf binary +*.wbmp binary *.woff binary *.woff2 binary *.xls binary @@ -124,9 +126,3 @@ *.dds filter=lfs diff=lfs merge=lfs -text *.ktx filter=lfs diff=lfs merge=lfs -text *.ktx2 filter=lfs diff=lfs merge=lfs -text -*.pam filter=lfs diff=lfs merge=lfs -text -*.pbm filter=lfs diff=lfs merge=lfs -text -*.pgm filter=lfs diff=lfs merge=lfs -text -*.ppm filter=lfs diff=lfs merge=lfs -text -*.pnm filter=lfs diff=lfs merge=lfs -text -*.wbmp filter=lfs diff=lfs merge=lfs -text diff --git a/tests/ImageSharp.Tests/Image/ImageCloneTests.cs b/tests/ImageSharp.Tests/Image/ImageCloneTests.cs index c1012e2df..9d978ee52 100644 --- a/tests/ImageSharp.Tests/Image/ImageCloneTests.cs +++ b/tests/ImageSharp.Tests/Image/ImageCloneTests.cs @@ -60,15 +60,17 @@ namespace SixLabors.ImageSharp.Tests [WithTestPatternImages(9, 9, PixelTypes.Rgba32)] public void CloneAs_ToAbgr32(TestImageProvider provider) { - using (Image image = provider.GetImage()) - using (Image clone = image.CloneAs()) + using Image image = provider.GetImage(); + using Image clone = image.CloneAs(); + + image.ProcessPixelRows(clone, static (imageAccessor, cloneAccessor) => { - for (int y = 0; y < image.Height; y++) + for (int y = 0; y < imageAccessor.Height; y++) { - Span row = image.GetPixelRowSpan(y); - Span rowClone = clone.GetPixelRowSpan(y); + Span row = imageAccessor.GetRowSpan(y); + Span rowClone = cloneAccessor.GetRowSpan(y); - for (int x = 0; x < image.Width; x++) + for (int x = 0; x < cloneAccessor.Width; x++) { Rgba32 expected = row[x]; Abgr32 actual = rowClone[x]; @@ -76,10 +78,9 @@ namespace SixLabors.ImageSharp.Tests Assert.Equal(expected.R, actual.R); Assert.Equal(expected.G, actual.G); Assert.Equal(expected.B, actual.B); - Assert.Equal(expected.A, actual.A); } } - } + }); } [Theory] From f7fc4c6c027c7748d392a62cd7300f91d9b1f975 Mon Sep 17 00:00:00 2001 From: Ynse Hoornenborg Date: Sat, 11 Dec 2021 15:45:24 +0100 Subject: [PATCH 070/121] Use native integers as loop counters --- .../Common/Helpers/BitOperations.cs | 26 +++++++ .../Helpers/Shuffle/IComponentShuffle.cs | 46 ++++++------ .../PixelImplementations/Abgr32.cs | 8 ++- .../PixelImplementations/Bgr24.cs | 7 +- .../Abgr32.PixelOperations.Generated.cs | 42 +++++------ .../Argb32.PixelOperations.Generated.cs | 42 +++++------ .../Bgr24.PixelOperations.Generated.cs | 42 +++++------ .../Bgra32.PixelOperations.Generated.cs | 42 +++++------ .../Bgra5551.PixelOperations.Generated.cs | 72 +++++++++---------- .../L16.PixelOperations.Generated.cs | 72 +++++++++---------- .../Generated/L8.PixelOperations.Generated.cs | 72 +++++++++---------- .../La16.PixelOperations.Generated.cs | 72 +++++++++---------- .../La32.PixelOperations.Generated.cs | 72 +++++++++---------- .../Rgb24.PixelOperations.Generated.cs | 42 +++++------ .../Rgb48.PixelOperations.Generated.cs | 72 +++++++++---------- .../Rgba32.PixelOperations.Generated.cs | 42 +++++------ .../Rgba64.PixelOperations.Generated.cs | 72 +++++++++---------- .../Generated/_Common.ttinclude | 6 +- 18 files changed, 440 insertions(+), 409 deletions(-) create mode 100644 src/ImageSharp/Common/Helpers/BitOperations.cs diff --git a/src/ImageSharp/Common/Helpers/BitOperations.cs b/src/ImageSharp/Common/Helpers/BitOperations.cs new file mode 100644 index 000000000..b4b6c890c --- /dev/null +++ b/src/ImageSharp/Common/Helpers/BitOperations.cs @@ -0,0 +1,26 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +using System.Runtime.CompilerServices; + +#if !NETCOREAPP3_1 +namespace SixLabors.ImageSharp.Common.Helpers +{ + /// + /// Polyfill for System.Numerics.BitOperations class, introduced in .NET Core 3.0. + /// + /// + public static class BitOperations + { + /// + /// Rotates the specified value left by the specified number of bits. + /// + /// The value to rotate. + /// The number of bits to roate with. + /// The rotated value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static uint RotateLeft(uint value, int offset) + => (value << offset) | (value >> (32 - offset)); + } +} +#endif diff --git a/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs b/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs index 4c02deb2d..89bac8e10 100644 --- a/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs +++ b/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs @@ -3,8 +3,10 @@ using System; using System.Buffers.Binary; +using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using SixLabors.ImageSharp.Common.Helpers; // The JIT can detect and optimize rotation idioms ROTL (Rotate Left) // and ROTR (Rotate Right) emitting efficient CPU instructions: @@ -97,15 +99,15 @@ namespace SixLabors.ImageSharp { ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); - int n = source.Length / 4; + nuint n = (nuint)(uint)source.Length / 4; - for (int i = 0; i < n; i++) + for (nuint i = 0; i < n; i++) { - uint packed = Unsafe.Add(ref sBase, i); + uint packed = Unsafe.Add(ref sBase, (int)i); // packed = [W Z Y X] // ROTL(8, packed) = [Z Y X W] - Unsafe.Add(ref dBase, i) = (packed << 8) | (packed >> 24); + Unsafe.Add(ref dBase, (int)i) = (packed << 8) | (packed >> 24); } } } @@ -123,15 +125,15 @@ namespace SixLabors.ImageSharp { ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); - int n = source.Length / 4; + nuint n = (nuint)(uint)source.Length / 4; - for (int i = 0; i < n; i++) + for (nuint i = 0; i < n; i++) { - uint packed = Unsafe.Add(ref sBase, i); + uint packed = Unsafe.Add(ref sBase, (int)i); // packed = [W Z Y X] // REVERSE(packedArgb) = [X Y Z W] - Unsafe.Add(ref dBase, i) = BinaryPrimitives.ReverseEndianness(packed); + Unsafe.Add(ref dBase, (int)i) = BinaryPrimitives.ReverseEndianness(packed); } } } @@ -149,15 +151,15 @@ namespace SixLabors.ImageSharp { ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); - int n = source.Length / 4; + nuint n = (nuint)(uint)source.Length / 4; - for (int i = 0; i < n; i++) + for (nuint i = 0; i < n; i++) { - uint packed = Unsafe.Add(ref sBase, i); + uint packed = Unsafe.Add(ref sBase, (int)i); // packed = [W Z Y X] // ROTR(8, packedArgb) = [Y Z W X] - Unsafe.Add(ref dBase, i) = (packed >> 8) | (packed << 24); + Unsafe.Add(ref dBase, (int)i) = (packed >> 8) | (packed << 24); } } } @@ -175,11 +177,11 @@ namespace SixLabors.ImageSharp { ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); - int n = source.Length / 4; + nuint n = (nuint)(uint)source.Length / 4; - for (int i = 0; i < n; i++) + for (nuint i = 0; i < n; i++) { - uint packed = Unsafe.Add(ref sBase, i); + uint packed = Unsafe.Add(ref sBase, (int)i); // packed = [W Z Y X] // tmp1 = [W 0 Y 0] @@ -188,9 +190,9 @@ namespace SixLabors.ImageSharp // tmp1 + tmp3 = [W X Y Z] uint tmp1 = packed & 0xFF00FF00; uint tmp2 = packed & 0x00FF00FF; - uint tmp3 = (tmp2 << 16) | (tmp2 >> 16); + uint tmp3 = BitOperations.RotateLeft(tmp2, 16); - Unsafe.Add(ref dBase, i) = tmp1 + tmp3; + Unsafe.Add(ref dBase, (int)i) = tmp1 + tmp3; } } } @@ -208,11 +210,11 @@ namespace SixLabors.ImageSharp { ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); - int n = source.Length / 4; + nuint n = (nuint)(uint)source.Length / 4; - for (int i = 0; i < n; i++) + for (nuint i = 0; i < n; i++) { - uint packed = Unsafe.Add(ref sBase, i); + uint packed = Unsafe.Add(ref sBase, (int)i); // packed = [W Z Y X] // tmp1 = [0 Z 0 X] @@ -221,9 +223,9 @@ namespace SixLabors.ImageSharp // tmp1 + tmp3 = [Y Z W X] uint tmp1 = packed & 0x00FF00FF; uint tmp2 = packed & 0xFF00FF00; - uint tmp3 = (tmp2 << 16) | (tmp2 >> 16); + uint tmp3 = BitOperations.RotateLeft(tmp2, 16); - Unsafe.Add(ref dBase, i) = tmp1 + tmp3; + Unsafe.Add(ref dBase, (int)i) = tmp1 + tmp3; } } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs index 0a95fc1ff..ca8f5c144 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs @@ -1,6 +1,7 @@ // 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; @@ -214,9 +215,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void FromBgr24(Bgr24 source) { - this.R = source.R; - this.G = source.G; - this.B = source.B; + // We can assign the Bgr24 value directly to last three bytes of this instance. + ref byte thisRef = ref Unsafe.As(ref this); + ref byte thisRefFromB = ref Unsafe.AddByteOffset(ref thisRef, new IntPtr(1)); + Unsafe.As(ref thisRefFromB) = source; this.A = byte.MaxValue; } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs index 882306928..81c178348 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs @@ -189,9 +189,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void FromAbgr32(Abgr32 source) { - this.R = source.R; - this.G = source.G; - this.B = source.B; + // We can assign this instances value directly to last three bytes of the Abgr32. + ref byte sourceRef = ref Unsafe.As(ref source); + ref byte sourceRefFromB = ref Unsafe.AddByteOffset(ref sourceRef, new IntPtr(1)); + this = Unsafe.As(ref sourceRefFromB); } /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Abgr32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Abgr32.PixelOperations.Generated.cs index 6386d315c..1333fbb6a 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Abgr32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Abgr32.PixelOperations.Generated.cs @@ -204,10 +204,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Abgr32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref L8 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + 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); + ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref L8 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromAbgr32(sp); } @@ -224,10 +224,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Abgr32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref L16 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + 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); + ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref L16 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromAbgr32(sp); } @@ -244,10 +244,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Abgr32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref La16 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + 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); + ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref La16 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromAbgr32(sp); } @@ -264,10 +264,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Abgr32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref La32 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + 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); + ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref La32 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromAbgr32(sp); } @@ -284,10 +284,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Abgr32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgb48 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + 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); + ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Rgb48 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromAbgr32(sp); } @@ -304,10 +304,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Abgr32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba64 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + 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); + ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Rgba64 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromAbgr32(sp); } @@ -324,10 +324,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Abgr32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgra5551 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + 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); + ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Bgra5551 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromAbgr32(sp); } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Argb32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Argb32.PixelOperations.Generated.cs index 0f183df0d..fa646512d 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Argb32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Argb32.PixelOperations.Generated.cs @@ -204,10 +204,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref L8 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); - ref L8 dp = ref Unsafe.Add(ref destRef, i); + ref Argb32 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref L8 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromArgb32(sp); } @@ -224,10 +224,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref L16 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); - ref L16 dp = ref Unsafe.Add(ref destRef, i); + ref Argb32 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref L16 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromArgb32(sp); } @@ -244,10 +244,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref La16 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); - ref La16 dp = ref Unsafe.Add(ref destRef, i); + ref Argb32 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref La16 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromArgb32(sp); } @@ -264,10 +264,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref La32 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); - ref La32 dp = ref Unsafe.Add(ref destRef, i); + ref Argb32 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref La32 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromArgb32(sp); } @@ -284,10 +284,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgb48 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); + ref Argb32 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Rgb48 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromArgb32(sp); } @@ -304,10 +304,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba64 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); + ref Argb32 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Rgba64 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromArgb32(sp); } @@ -324,10 +324,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgra5551 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i); + ref Argb32 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Bgra5551 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromArgb32(sp); } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgr24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgr24.PixelOperations.Generated.cs index ea08c6391..b193251ce 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgr24.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgr24.PixelOperations.Generated.cs @@ -204,10 +204,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref L8 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); - ref L8 dp = ref Unsafe.Add(ref destRef, i); + ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref L8 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromBgr24(sp); } @@ -224,10 +224,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref L16 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); - ref L16 dp = ref Unsafe.Add(ref destRef, i); + ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref L16 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromBgr24(sp); } @@ -244,10 +244,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref La16 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); - ref La16 dp = ref Unsafe.Add(ref destRef, i); + ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref La16 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromBgr24(sp); } @@ -264,10 +264,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref La32 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); - ref La32 dp = ref Unsafe.Add(ref destRef, i); + ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref La32 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromBgr24(sp); } @@ -284,10 +284,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgb48 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); + ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Rgb48 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromBgr24(sp); } @@ -304,10 +304,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba64 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); + ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Rgba64 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromBgr24(sp); } @@ -324,10 +324,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgra5551 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i); + ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Bgra5551 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromBgr24(sp); } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgra32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgra32.PixelOperations.Generated.cs index 0ec9a552c..4426bc0d9 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgra32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgra32.PixelOperations.Generated.cs @@ -204,10 +204,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref L8 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); - ref L8 dp = ref Unsafe.Add(ref destRef, i); + ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref L8 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromBgra32(sp); } @@ -224,10 +224,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref L16 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); - ref L16 dp = ref Unsafe.Add(ref destRef, i); + ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref L16 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromBgra32(sp); } @@ -244,10 +244,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref La16 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); - ref La16 dp = ref Unsafe.Add(ref destRef, i); + ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref La16 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromBgra32(sp); } @@ -264,10 +264,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref La32 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); - ref La32 dp = ref Unsafe.Add(ref destRef, i); + ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref La32 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromBgra32(sp); } @@ -284,10 +284,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgb48 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); + ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Rgb48 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromBgra32(sp); } @@ -304,10 +304,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba64 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); + ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Rgba64 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromBgra32(sp); } @@ -324,10 +324,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgra5551 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i); + ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Bgra5551 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromBgra32(sp); } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgra5551.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgra5551.PixelOperations.Generated.cs index 877ce1a6f..90ace9181 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgra5551.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgra5551.PixelOperations.Generated.cs @@ -50,10 +50,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgra5551 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Argb32 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, i); - ref Argb32 dp = ref Unsafe.Add(ref destRef, i); + ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Argb32 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromBgra5551(sp); } @@ -70,10 +70,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgra5551 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Abgr32 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, i); - ref Abgr32 dp = ref Unsafe.Add(ref destRef, i); + ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Abgr32 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromBgra5551(sp); } @@ -90,10 +90,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgra5551 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgr24 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); + ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Bgr24 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromBgra5551(sp); } @@ -110,10 +110,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgra5551 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgra32 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); + ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Bgra32 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromBgra5551(sp); } @@ -130,10 +130,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgra5551 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref L8 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, i); - ref L8 dp = ref Unsafe.Add(ref destRef, i); + ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref L8 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromBgra5551(sp); } @@ -150,10 +150,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgra5551 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref L16 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, i); - ref L16 dp = ref Unsafe.Add(ref destRef, i); + ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref L16 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromBgra5551(sp); } @@ -170,10 +170,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgra5551 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref La16 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, i); - ref La16 dp = ref Unsafe.Add(ref destRef, i); + ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref La16 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromBgra5551(sp); } @@ -190,10 +190,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgra5551 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref La32 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, i); - ref La32 dp = ref Unsafe.Add(ref destRef, i); + ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref La32 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromBgra5551(sp); } @@ -210,10 +210,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgra5551 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgb24 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); + ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Rgb24 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromBgra5551(sp); } @@ -230,10 +230,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgra5551 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba32 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); + ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Rgba32 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromBgra5551(sp); } @@ -250,10 +250,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgra5551 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgb48 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); + ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Rgb48 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromBgra5551(sp); } @@ -270,10 +270,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgra5551 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba64 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); + ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Rgba64 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromBgra5551(sp); } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/L16.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/L16.PixelOperations.Generated.cs index 94eb3229b..8c5b2e99a 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/L16.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/L16.PixelOperations.Generated.cs @@ -50,10 +50,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref L16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Argb32 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref L16 sp = ref Unsafe.Add(ref sourceRef, i); - ref Argb32 dp = ref Unsafe.Add(ref destRef, i); + ref L16 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Argb32 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromL16(sp); } @@ -70,10 +70,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref L16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Abgr32 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref L16 sp = ref Unsafe.Add(ref sourceRef, i); - ref Abgr32 dp = ref Unsafe.Add(ref destRef, i); + ref L16 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Abgr32 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromL16(sp); } @@ -90,10 +90,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref L16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgr24 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref L16 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); + ref L16 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Bgr24 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromL16(sp); } @@ -110,10 +110,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref L16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgra32 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref L16 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); + ref L16 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Bgra32 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromL16(sp); } @@ -130,10 +130,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref L16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref L8 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref L16 sp = ref Unsafe.Add(ref sourceRef, i); - ref L8 dp = ref Unsafe.Add(ref destRef, i); + ref L16 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref L8 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromL16(sp); } @@ -150,10 +150,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref L16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref La16 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref L16 sp = ref Unsafe.Add(ref sourceRef, i); - ref La16 dp = ref Unsafe.Add(ref destRef, i); + ref L16 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref La16 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromL16(sp); } @@ -170,10 +170,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref L16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref La32 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref L16 sp = ref Unsafe.Add(ref sourceRef, i); - ref La32 dp = ref Unsafe.Add(ref destRef, i); + ref L16 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref La32 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromL16(sp); } @@ -190,10 +190,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref L16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgb24 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref L16 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); + ref L16 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Rgb24 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromL16(sp); } @@ -210,10 +210,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref L16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba32 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref L16 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); + ref L16 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Rgba32 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromL16(sp); } @@ -230,10 +230,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref L16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgb48 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref L16 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); + ref L16 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Rgb48 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromL16(sp); } @@ -250,10 +250,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref L16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba64 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref L16 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); + ref L16 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Rgba64 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromL16(sp); } @@ -270,10 +270,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref L16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgra5551 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref L16 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i); + ref L16 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Bgra5551 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromL16(sp); } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/L8.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/L8.PixelOperations.Generated.cs index a748590f7..f61dc25ec 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/L8.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/L8.PixelOperations.Generated.cs @@ -50,10 +50,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref L8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Argb32 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref L8 sp = ref Unsafe.Add(ref sourceRef, i); - ref Argb32 dp = ref Unsafe.Add(ref destRef, i); + ref L8 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Argb32 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromL8(sp); } @@ -70,10 +70,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref L8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Abgr32 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref L8 sp = ref Unsafe.Add(ref sourceRef, i); - ref Abgr32 dp = ref Unsafe.Add(ref destRef, i); + ref L8 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Abgr32 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromL8(sp); } @@ -90,10 +90,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref L8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgr24 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref L8 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); + ref L8 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Bgr24 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromL8(sp); } @@ -110,10 +110,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref L8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgra32 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref L8 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); + ref L8 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Bgra32 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromL8(sp); } @@ -130,10 +130,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref L8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref L16 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref L8 sp = ref Unsafe.Add(ref sourceRef, i); - ref L16 dp = ref Unsafe.Add(ref destRef, i); + ref L8 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref L16 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromL8(sp); } @@ -150,10 +150,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref L8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref La16 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref L8 sp = ref Unsafe.Add(ref sourceRef, i); - ref La16 dp = ref Unsafe.Add(ref destRef, i); + ref L8 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref La16 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromL8(sp); } @@ -170,10 +170,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref L8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref La32 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref L8 sp = ref Unsafe.Add(ref sourceRef, i); - ref La32 dp = ref Unsafe.Add(ref destRef, i); + ref L8 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref La32 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromL8(sp); } @@ -190,10 +190,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref L8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgb24 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref L8 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); + ref L8 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Rgb24 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromL8(sp); } @@ -210,10 +210,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref L8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba32 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref L8 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); + ref L8 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Rgba32 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromL8(sp); } @@ -230,10 +230,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref L8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgb48 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref L8 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); + ref L8 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Rgb48 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromL8(sp); } @@ -250,10 +250,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref L8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba64 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref L8 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); + ref L8 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Rgba64 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromL8(sp); } @@ -270,10 +270,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref L8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgra5551 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref L8 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i); + ref L8 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Bgra5551 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromL8(sp); } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/La16.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/La16.PixelOperations.Generated.cs index f47cd6c40..feec77618 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/La16.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/La16.PixelOperations.Generated.cs @@ -50,10 +50,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref La16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Argb32 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref La16 sp = ref Unsafe.Add(ref sourceRef, i); - ref Argb32 dp = ref Unsafe.Add(ref destRef, i); + ref La16 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Argb32 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromLa16(sp); } @@ -70,10 +70,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref La16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Abgr32 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref La16 sp = ref Unsafe.Add(ref sourceRef, i); - ref Abgr32 dp = ref Unsafe.Add(ref destRef, i); + ref La16 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Abgr32 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromLa16(sp); } @@ -90,10 +90,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref La16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgr24 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref La16 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); + ref La16 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Bgr24 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromLa16(sp); } @@ -110,10 +110,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref La16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgra32 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref La16 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); + ref La16 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Bgra32 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromLa16(sp); } @@ -130,10 +130,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref La16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref L8 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref La16 sp = ref Unsafe.Add(ref sourceRef, i); - ref L8 dp = ref Unsafe.Add(ref destRef, i); + ref La16 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref L8 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromLa16(sp); } @@ -150,10 +150,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref La16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref L16 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref La16 sp = ref Unsafe.Add(ref sourceRef, i); - ref L16 dp = ref Unsafe.Add(ref destRef, i); + ref La16 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref L16 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromLa16(sp); } @@ -170,10 +170,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref La16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref La32 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref La16 sp = ref Unsafe.Add(ref sourceRef, i); - ref La32 dp = ref Unsafe.Add(ref destRef, i); + ref La16 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref La32 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromLa16(sp); } @@ -190,10 +190,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref La16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgb24 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref La16 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); + ref La16 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Rgb24 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromLa16(sp); } @@ -210,10 +210,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref La16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba32 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref La16 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); + ref La16 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Rgba32 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromLa16(sp); } @@ -230,10 +230,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref La16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgb48 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref La16 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); + ref La16 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Rgb48 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromLa16(sp); } @@ -250,10 +250,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref La16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba64 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref La16 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); + ref La16 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Rgba64 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromLa16(sp); } @@ -270,10 +270,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref La16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgra5551 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref La16 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i); + ref La16 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Bgra5551 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromLa16(sp); } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/La32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/La32.PixelOperations.Generated.cs index f0c2c3323..ddf94261e 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/La32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/La32.PixelOperations.Generated.cs @@ -50,10 +50,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref La32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Argb32 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref La32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Argb32 dp = ref Unsafe.Add(ref destRef, i); + ref La32 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Argb32 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromLa32(sp); } @@ -70,10 +70,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref La32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Abgr32 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref La32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Abgr32 dp = ref Unsafe.Add(ref destRef, i); + ref La32 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Abgr32 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromLa32(sp); } @@ -90,10 +90,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref La32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgr24 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref La32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); + ref La32 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Bgr24 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromLa32(sp); } @@ -110,10 +110,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref La32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgra32 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref La32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); + ref La32 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Bgra32 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromLa32(sp); } @@ -130,10 +130,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref La32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref L8 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref La32 sp = ref Unsafe.Add(ref sourceRef, i); - ref L8 dp = ref Unsafe.Add(ref destRef, i); + ref La32 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref L8 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromLa32(sp); } @@ -150,10 +150,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref La32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref L16 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref La32 sp = ref Unsafe.Add(ref sourceRef, i); - ref L16 dp = ref Unsafe.Add(ref destRef, i); + ref La32 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref L16 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromLa32(sp); } @@ -170,10 +170,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref La32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref La16 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref La32 sp = ref Unsafe.Add(ref sourceRef, i); - ref La16 dp = ref Unsafe.Add(ref destRef, i); + ref La32 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref La16 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromLa32(sp); } @@ -190,10 +190,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref La32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgb24 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref La32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); + ref La32 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Rgb24 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromLa32(sp); } @@ -210,10 +210,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref La32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba32 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref La32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); + ref La32 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Rgba32 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromLa32(sp); } @@ -230,10 +230,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref La32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgb48 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref La32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); + ref La32 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Rgb48 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromLa32(sp); } @@ -250,10 +250,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref La32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba64 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref La32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); + ref La32 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Rgba64 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromLa32(sp); } @@ -270,10 +270,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref La32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgra5551 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref La32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i); + ref La32 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Bgra5551 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromLa32(sp); } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgb24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgb24.PixelOperations.Generated.cs index 75f677cdd..e89b17f72 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgb24.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgb24.PixelOperations.Generated.cs @@ -204,10 +204,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref L8 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); - ref L8 dp = ref Unsafe.Add(ref destRef, i); + ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref L8 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromRgb24(sp); } @@ -224,10 +224,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref L16 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); - ref L16 dp = ref Unsafe.Add(ref destRef, i); + ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref L16 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromRgb24(sp); } @@ -244,10 +244,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref La16 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); - ref La16 dp = ref Unsafe.Add(ref destRef, i); + ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref La16 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromRgb24(sp); } @@ -264,10 +264,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref La32 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); - ref La32 dp = ref Unsafe.Add(ref destRef, i); + ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref La32 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromRgb24(sp); } @@ -284,10 +284,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgb48 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); + ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Rgb48 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromRgb24(sp); } @@ -304,10 +304,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba64 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); + ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Rgba64 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromRgb24(sp); } @@ -324,10 +324,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgra5551 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i); + ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Bgra5551 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromRgb24(sp); } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgb48.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgb48.PixelOperations.Generated.cs index 22b96fd5a..017124ef1 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgb48.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgb48.PixelOperations.Generated.cs @@ -50,10 +50,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Argb32 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); - ref Argb32 dp = ref Unsafe.Add(ref destRef, i); + ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Argb32 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromRgb48(sp); } @@ -70,10 +70,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Abgr32 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); - ref Abgr32 dp = ref Unsafe.Add(ref destRef, i); + ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Abgr32 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromRgb48(sp); } @@ -90,10 +90,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgr24 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); + ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Bgr24 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromRgb48(sp); } @@ -110,10 +110,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgra32 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); + ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Bgra32 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromRgb48(sp); } @@ -130,10 +130,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref L8 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); - ref L8 dp = ref Unsafe.Add(ref destRef, i); + ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref L8 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromRgb48(sp); } @@ -150,10 +150,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref L16 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); - ref L16 dp = ref Unsafe.Add(ref destRef, i); + ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref L16 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromRgb48(sp); } @@ -170,10 +170,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref La16 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); - ref La16 dp = ref Unsafe.Add(ref destRef, i); + ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref La16 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromRgb48(sp); } @@ -190,10 +190,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref La32 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); - ref La32 dp = ref Unsafe.Add(ref destRef, i); + ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref La32 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromRgb48(sp); } @@ -210,10 +210,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgb24 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); + ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Rgb24 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromRgb48(sp); } @@ -230,10 +230,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba32 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); + ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Rgba32 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromRgb48(sp); } @@ -250,10 +250,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba64 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); + ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Rgba64 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromRgb48(sp); } @@ -270,10 +270,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgra5551 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i); + ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Bgra5551 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromRgb48(sp); } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgba32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgba32.PixelOperations.Generated.cs index 093182c82..483c3f69c 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgba32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgba32.PixelOperations.Generated.cs @@ -185,10 +185,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref L8 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); - ref L8 dp = ref Unsafe.Add(ref destRef, i); + ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref L8 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromRgba32(sp); } @@ -205,10 +205,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref L16 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); - ref L16 dp = ref Unsafe.Add(ref destRef, i); + ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref L16 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromRgba32(sp); } @@ -225,10 +225,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref La16 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); - ref La16 dp = ref Unsafe.Add(ref destRef, i); + ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref La16 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromRgba32(sp); } @@ -245,10 +245,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref La32 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); - ref La32 dp = ref Unsafe.Add(ref destRef, i); + ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref La32 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromRgba32(sp); } @@ -265,10 +265,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgb48 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); + ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Rgb48 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromRgba32(sp); } @@ -285,10 +285,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba64 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); + ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Rgba64 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromRgba32(sp); } @@ -305,10 +305,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgra5551 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i); + ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Bgra5551 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromRgba32(sp); } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgba64.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgba64.PixelOperations.Generated.cs index ce1b53e66..a82fb26b4 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgba64.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgba64.PixelOperations.Generated.cs @@ -50,10 +50,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Argb32 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); - ref Argb32 dp = ref Unsafe.Add(ref destRef, i); + ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Argb32 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromRgba64(sp); } @@ -70,10 +70,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Abgr32 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); - ref Abgr32 dp = ref Unsafe.Add(ref destRef, i); + ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Abgr32 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromRgba64(sp); } @@ -90,10 +90,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgr24 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); + ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Bgr24 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromRgba64(sp); } @@ -110,10 +110,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgra32 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); + ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Bgra32 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromRgba64(sp); } @@ -130,10 +130,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref L8 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); - ref L8 dp = ref Unsafe.Add(ref destRef, i); + ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref L8 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromRgba64(sp); } @@ -150,10 +150,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref L16 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); - ref L16 dp = ref Unsafe.Add(ref destRef, i); + ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref L16 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromRgba64(sp); } @@ -170,10 +170,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref La16 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); - ref La16 dp = ref Unsafe.Add(ref destRef, i); + ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref La16 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromRgba64(sp); } @@ -190,10 +190,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref La32 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); - ref La32 dp = ref Unsafe.Add(ref destRef, i); + ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref La32 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromRgba64(sp); } @@ -210,10 +210,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgb24 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); + ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Rgb24 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromRgba64(sp); } @@ -230,10 +230,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba32 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); + ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Rgba32 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromRgba64(sp); } @@ -250,10 +250,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgb48 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); + ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Rgb48 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromRgba64(sp); } @@ -270,10 +270,10 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgra5551 destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i); + ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref Bgra5551 dp = ref Unsafe.Add(ref destRef, (int)i); dp.FromRgba64(sp); } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/_Common.ttinclude b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/_Common.ttinclude index b6b0a14a7..9da66a5a9 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/_Common.ttinclude +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/_Common.ttinclude @@ -104,10 +104,10 @@ using SixLabors.ImageSharp.PixelFormats.Utils; ref <#=fromPixelType#> sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref <#=toPixelType#> destRef = ref MemoryMarshal.GetReference(destinationPixels); - for (int i = 0; i < sourcePixels.Length; i++) + for (nint i = 0; i < sourcePixels.Length; i++) { - ref <#=fromPixelType#> sp = ref Unsafe.Add(ref sourceRef, i); - ref <#=toPixelType#> dp = ref Unsafe.Add(ref destRef, i); + ref <#=fromPixelType#> sp = ref Unsafe.Add(ref sourceRef, (int)i); + ref <#=toPixelType#> dp = ref Unsafe.Add(ref destRef, (int)i); dp.From<#=fromPixelType#>(sp); } From 1ce4429001258ab7d548f7f88eedfa3a60bd474b Mon Sep 17 00:00:00 2001 From: Ynse Hoornenborg Date: Sat, 11 Dec 2021 23:24:27 +0100 Subject: [PATCH 071/121] Optimizing native integer usage --- .../Common/Helpers/BitOperations.cs | 2 +- .../Helpers/Shuffle/IComponentShuffle.cs | 40 ++++++++-------- .../Abgr32.PixelOperations.Generated.cs | 28 +++++------ .../Argb32.PixelOperations.Generated.cs | 28 +++++------ .../Bgr24.PixelOperations.Generated.cs | 28 +++++------ .../Bgra32.PixelOperations.Generated.cs | 28 +++++------ .../Bgra5551.PixelOperations.Generated.cs | 48 +++++++++---------- .../L16.PixelOperations.Generated.cs | 48 +++++++++---------- .../Generated/L8.PixelOperations.Generated.cs | 48 +++++++++---------- .../La16.PixelOperations.Generated.cs | 48 +++++++++---------- .../La32.PixelOperations.Generated.cs | 48 +++++++++---------- .../Rgb24.PixelOperations.Generated.cs | 28 +++++------ .../Rgb48.PixelOperations.Generated.cs | 48 +++++++++---------- .../Rgba32.PixelOperations.Generated.cs | 28 +++++------ .../Rgba64.PixelOperations.Generated.cs | 48 +++++++++---------- .../Generated/_Common.ttinclude | 4 +- 16 files changed, 275 insertions(+), 275 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/BitOperations.cs b/src/ImageSharp/Common/Helpers/BitOperations.cs index b4b6c890c..af56efd56 100644 --- a/src/ImageSharp/Common/Helpers/BitOperations.cs +++ b/src/ImageSharp/Common/Helpers/BitOperations.cs @@ -3,7 +3,7 @@ using System.Runtime.CompilerServices; -#if !NETCOREAPP3_1 +#if !NETCOREAPP3_1_OR_GREATER namespace SixLabors.ImageSharp.Common.Helpers { /// diff --git a/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs b/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs index 89bac8e10..1922c787c 100644 --- a/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs +++ b/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs @@ -99,15 +99,15 @@ namespace SixLabors.ImageSharp { ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); - nuint n = (nuint)(uint)source.Length / 4; + nint n = (nint)source.Length / 4; - for (nuint i = 0; i < n; i++) + for (nint i = 0; i < n; i++) { - uint packed = Unsafe.Add(ref sBase, (int)i); + uint packed = Unsafe.Add(ref sBase, i); // packed = [W Z Y X] // ROTL(8, packed) = [Z Y X W] - Unsafe.Add(ref dBase, (int)i) = (packed << 8) | (packed >> 24); + Unsafe.Add(ref dBase, i) = (packed << 8) | (packed >> 24); } } } @@ -125,15 +125,15 @@ namespace SixLabors.ImageSharp { ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); - nuint n = (nuint)(uint)source.Length / 4; + nint n = (nint)source.Length / 4; - for (nuint i = 0; i < n; i++) + for (nint i = 0; i < n; i++) { - uint packed = Unsafe.Add(ref sBase, (int)i); + uint packed = Unsafe.Add(ref sBase, i); // packed = [W Z Y X] // REVERSE(packedArgb) = [X Y Z W] - Unsafe.Add(ref dBase, (int)i) = BinaryPrimitives.ReverseEndianness(packed); + Unsafe.Add(ref dBase, i) = BinaryPrimitives.ReverseEndianness(packed); } } } @@ -151,15 +151,15 @@ namespace SixLabors.ImageSharp { ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); - nuint n = (nuint)(uint)source.Length / 4; + nint n = (nint)source.Length / 4; - for (nuint i = 0; i < n; i++) + for (nint i = 0; i < n; i++) { - uint packed = Unsafe.Add(ref sBase, (int)i); + uint packed = Unsafe.Add(ref sBase, i); // packed = [W Z Y X] // ROTR(8, packedArgb) = [Y Z W X] - Unsafe.Add(ref dBase, (int)i) = (packed >> 8) | (packed << 24); + Unsafe.Add(ref dBase, i) = (packed >> 8) | (packed << 24); } } } @@ -177,11 +177,11 @@ namespace SixLabors.ImageSharp { ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); - nuint n = (nuint)(uint)source.Length / 4; + nint n = (nint)source.Length / 4; - for (nuint i = 0; i < n; i++) + for (nint i = 0; i < n; i++) { - uint packed = Unsafe.Add(ref sBase, (int)i); + uint packed = Unsafe.Add(ref sBase, i); // packed = [W Z Y X] // tmp1 = [W 0 Y 0] @@ -192,7 +192,7 @@ namespace SixLabors.ImageSharp uint tmp2 = packed & 0x00FF00FF; uint tmp3 = BitOperations.RotateLeft(tmp2, 16); - Unsafe.Add(ref dBase, (int)i) = tmp1 + tmp3; + Unsafe.Add(ref dBase, i) = tmp1 + tmp3; } } } @@ -210,11 +210,11 @@ namespace SixLabors.ImageSharp { ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); - nuint n = (nuint)(uint)source.Length / 4; + nint n = (nint)source.Length / 4; - for (nuint i = 0; i < n; i++) + for (nint i = 0; i < n; i++) { - uint packed = Unsafe.Add(ref sBase, (int)i); + uint packed = Unsafe.Add(ref sBase, i); // packed = [W Z Y X] // tmp1 = [0 Z 0 X] @@ -225,7 +225,7 @@ namespace SixLabors.ImageSharp uint tmp2 = packed & 0xFF00FF00; uint tmp3 = BitOperations.RotateLeft(tmp2, 16); - Unsafe.Add(ref dBase, (int)i) = tmp1 + tmp3; + Unsafe.Add(ref dBase, i) = tmp1 + tmp3; } } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Abgr32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Abgr32.PixelOperations.Generated.cs index 1333fbb6a..026025f76 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Abgr32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Abgr32.PixelOperations.Generated.cs @@ -206,8 +206,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref L8 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, i); + ref L8 dp = ref Unsafe.Add(ref destRef, i); dp.FromAbgr32(sp); } @@ -226,8 +226,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref L16 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, i); + ref L16 dp = ref Unsafe.Add(ref destRef, i); dp.FromAbgr32(sp); } @@ -246,8 +246,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref La16 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, i); + ref La16 dp = ref Unsafe.Add(ref destRef, i); dp.FromAbgr32(sp); } @@ -266,8 +266,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref La32 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, i); + ref La32 dp = ref Unsafe.Add(ref destRef, i); dp.FromAbgr32(sp); } @@ -286,8 +286,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Rgb48 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); dp.FromAbgr32(sp); } @@ -306,8 +306,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Rgba64 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); dp.FromAbgr32(sp); } @@ -326,8 +326,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Bgra5551 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i); dp.FromAbgr32(sp); } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Argb32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Argb32.PixelOperations.Generated.cs index fa646512d..4b9f68a68 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Argb32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Argb32.PixelOperations.Generated.cs @@ -206,8 +206,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Argb32 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref L8 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); + ref L8 dp = ref Unsafe.Add(ref destRef, i); dp.FromArgb32(sp); } @@ -226,8 +226,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Argb32 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref L16 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); + ref L16 dp = ref Unsafe.Add(ref destRef, i); dp.FromArgb32(sp); } @@ -246,8 +246,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Argb32 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref La16 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); + ref La16 dp = ref Unsafe.Add(ref destRef, i); dp.FromArgb32(sp); } @@ -266,8 +266,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Argb32 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref La32 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); + ref La32 dp = ref Unsafe.Add(ref destRef, i); dp.FromArgb32(sp); } @@ -286,8 +286,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Argb32 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Rgb48 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); dp.FromArgb32(sp); } @@ -306,8 +306,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Argb32 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Rgba64 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); dp.FromArgb32(sp); } @@ -326,8 +326,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Argb32 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Bgra5551 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i); dp.FromArgb32(sp); } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgr24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgr24.PixelOperations.Generated.cs index b193251ce..c85e4ee3b 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgr24.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgr24.PixelOperations.Generated.cs @@ -206,8 +206,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref L8 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); + ref L8 dp = ref Unsafe.Add(ref destRef, i); dp.FromBgr24(sp); } @@ -226,8 +226,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref L16 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); + ref L16 dp = ref Unsafe.Add(ref destRef, i); dp.FromBgr24(sp); } @@ -246,8 +246,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref La16 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); + ref La16 dp = ref Unsafe.Add(ref destRef, i); dp.FromBgr24(sp); } @@ -266,8 +266,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref La32 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); + ref La32 dp = ref Unsafe.Add(ref destRef, i); dp.FromBgr24(sp); } @@ -286,8 +286,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Rgb48 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); dp.FromBgr24(sp); } @@ -306,8 +306,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Rgba64 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); dp.FromBgr24(sp); } @@ -326,8 +326,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Bgra5551 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i); dp.FromBgr24(sp); } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgra32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgra32.PixelOperations.Generated.cs index 4426bc0d9..ed1366b0a 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgra32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgra32.PixelOperations.Generated.cs @@ -206,8 +206,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref L8 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); + ref L8 dp = ref Unsafe.Add(ref destRef, i); dp.FromBgra32(sp); } @@ -226,8 +226,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref L16 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); + ref L16 dp = ref Unsafe.Add(ref destRef, i); dp.FromBgra32(sp); } @@ -246,8 +246,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref La16 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); + ref La16 dp = ref Unsafe.Add(ref destRef, i); dp.FromBgra32(sp); } @@ -266,8 +266,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref La32 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); + ref La32 dp = ref Unsafe.Add(ref destRef, i); dp.FromBgra32(sp); } @@ -286,8 +286,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Rgb48 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); dp.FromBgra32(sp); } @@ -306,8 +306,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Rgba64 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); dp.FromBgra32(sp); } @@ -326,8 +326,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Bgra5551 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i); dp.FromBgra32(sp); } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgra5551.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgra5551.PixelOperations.Generated.cs index 90ace9181..0dfa46c14 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgra5551.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgra5551.PixelOperations.Generated.cs @@ -52,8 +52,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Argb32 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, i); + ref Argb32 dp = ref Unsafe.Add(ref destRef, i); dp.FromBgra5551(sp); } @@ -72,8 +72,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Abgr32 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, i); + ref Abgr32 dp = ref Unsafe.Add(ref destRef, i); dp.FromBgra5551(sp); } @@ -92,8 +92,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Bgr24 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); dp.FromBgra5551(sp); } @@ -112,8 +112,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Bgra32 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); dp.FromBgra5551(sp); } @@ -132,8 +132,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref L8 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, i); + ref L8 dp = ref Unsafe.Add(ref destRef, i); dp.FromBgra5551(sp); } @@ -152,8 +152,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref L16 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, i); + ref L16 dp = ref Unsafe.Add(ref destRef, i); dp.FromBgra5551(sp); } @@ -172,8 +172,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref La16 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, i); + ref La16 dp = ref Unsafe.Add(ref destRef, i); dp.FromBgra5551(sp); } @@ -192,8 +192,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref La32 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, i); + ref La32 dp = ref Unsafe.Add(ref destRef, i); dp.FromBgra5551(sp); } @@ -212,8 +212,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Rgb24 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); dp.FromBgra5551(sp); } @@ -232,8 +232,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Rgba32 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); dp.FromBgra5551(sp); } @@ -252,8 +252,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Rgb48 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); dp.FromBgra5551(sp); } @@ -272,8 +272,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Rgba64 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); dp.FromBgra5551(sp); } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/L16.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/L16.PixelOperations.Generated.cs index 8c5b2e99a..19e0548ae 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/L16.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/L16.PixelOperations.Generated.cs @@ -52,8 +52,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref L16 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Argb32 dp = ref Unsafe.Add(ref destRef, (int)i); + ref L16 sp = ref Unsafe.Add(ref sourceRef, i); + ref Argb32 dp = ref Unsafe.Add(ref destRef, i); dp.FromL16(sp); } @@ -72,8 +72,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref L16 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Abgr32 dp = ref Unsafe.Add(ref destRef, (int)i); + ref L16 sp = ref Unsafe.Add(ref sourceRef, i); + ref Abgr32 dp = ref Unsafe.Add(ref destRef, i); dp.FromL16(sp); } @@ -92,8 +92,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref L16 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Bgr24 dp = ref Unsafe.Add(ref destRef, (int)i); + ref L16 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); dp.FromL16(sp); } @@ -112,8 +112,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref L16 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Bgra32 dp = ref Unsafe.Add(ref destRef, (int)i); + ref L16 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); dp.FromL16(sp); } @@ -132,8 +132,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref L16 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref L8 dp = ref Unsafe.Add(ref destRef, (int)i); + ref L16 sp = ref Unsafe.Add(ref sourceRef, i); + ref L8 dp = ref Unsafe.Add(ref destRef, i); dp.FromL16(sp); } @@ -152,8 +152,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref L16 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref La16 dp = ref Unsafe.Add(ref destRef, (int)i); + ref L16 sp = ref Unsafe.Add(ref sourceRef, i); + ref La16 dp = ref Unsafe.Add(ref destRef, i); dp.FromL16(sp); } @@ -172,8 +172,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref L16 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref La32 dp = ref Unsafe.Add(ref destRef, (int)i); + ref L16 sp = ref Unsafe.Add(ref sourceRef, i); + ref La32 dp = ref Unsafe.Add(ref destRef, i); dp.FromL16(sp); } @@ -192,8 +192,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref L16 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Rgb24 dp = ref Unsafe.Add(ref destRef, (int)i); + ref L16 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); dp.FromL16(sp); } @@ -212,8 +212,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref L16 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Rgba32 dp = ref Unsafe.Add(ref destRef, (int)i); + ref L16 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); dp.FromL16(sp); } @@ -232,8 +232,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref L16 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Rgb48 dp = ref Unsafe.Add(ref destRef, (int)i); + ref L16 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); dp.FromL16(sp); } @@ -252,8 +252,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref L16 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Rgba64 dp = ref Unsafe.Add(ref destRef, (int)i); + ref L16 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); dp.FromL16(sp); } @@ -272,8 +272,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref L16 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Bgra5551 dp = ref Unsafe.Add(ref destRef, (int)i); + ref L16 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i); dp.FromL16(sp); } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/L8.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/L8.PixelOperations.Generated.cs index f61dc25ec..8997449d3 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/L8.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/L8.PixelOperations.Generated.cs @@ -52,8 +52,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref L8 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Argb32 dp = ref Unsafe.Add(ref destRef, (int)i); + ref L8 sp = ref Unsafe.Add(ref sourceRef, i); + ref Argb32 dp = ref Unsafe.Add(ref destRef, i); dp.FromL8(sp); } @@ -72,8 +72,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref L8 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Abgr32 dp = ref Unsafe.Add(ref destRef, (int)i); + ref L8 sp = ref Unsafe.Add(ref sourceRef, i); + ref Abgr32 dp = ref Unsafe.Add(ref destRef, i); dp.FromL8(sp); } @@ -92,8 +92,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref L8 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Bgr24 dp = ref Unsafe.Add(ref destRef, (int)i); + ref L8 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); dp.FromL8(sp); } @@ -112,8 +112,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref L8 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Bgra32 dp = ref Unsafe.Add(ref destRef, (int)i); + ref L8 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); dp.FromL8(sp); } @@ -132,8 +132,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref L8 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref L16 dp = ref Unsafe.Add(ref destRef, (int)i); + ref L8 sp = ref Unsafe.Add(ref sourceRef, i); + ref L16 dp = ref Unsafe.Add(ref destRef, i); dp.FromL8(sp); } @@ -152,8 +152,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref L8 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref La16 dp = ref Unsafe.Add(ref destRef, (int)i); + ref L8 sp = ref Unsafe.Add(ref sourceRef, i); + ref La16 dp = ref Unsafe.Add(ref destRef, i); dp.FromL8(sp); } @@ -172,8 +172,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref L8 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref La32 dp = ref Unsafe.Add(ref destRef, (int)i); + ref L8 sp = ref Unsafe.Add(ref sourceRef, i); + ref La32 dp = ref Unsafe.Add(ref destRef, i); dp.FromL8(sp); } @@ -192,8 +192,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref L8 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Rgb24 dp = ref Unsafe.Add(ref destRef, (int)i); + ref L8 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); dp.FromL8(sp); } @@ -212,8 +212,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref L8 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Rgba32 dp = ref Unsafe.Add(ref destRef, (int)i); + ref L8 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); dp.FromL8(sp); } @@ -232,8 +232,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref L8 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Rgb48 dp = ref Unsafe.Add(ref destRef, (int)i); + ref L8 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); dp.FromL8(sp); } @@ -252,8 +252,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref L8 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Rgba64 dp = ref Unsafe.Add(ref destRef, (int)i); + ref L8 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); dp.FromL8(sp); } @@ -272,8 +272,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref L8 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Bgra5551 dp = ref Unsafe.Add(ref destRef, (int)i); + ref L8 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i); dp.FromL8(sp); } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/La16.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/La16.PixelOperations.Generated.cs index feec77618..8166862fe 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/La16.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/La16.PixelOperations.Generated.cs @@ -52,8 +52,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref La16 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Argb32 dp = ref Unsafe.Add(ref destRef, (int)i); + ref La16 sp = ref Unsafe.Add(ref sourceRef, i); + ref Argb32 dp = ref Unsafe.Add(ref destRef, i); dp.FromLa16(sp); } @@ -72,8 +72,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref La16 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Abgr32 dp = ref Unsafe.Add(ref destRef, (int)i); + ref La16 sp = ref Unsafe.Add(ref sourceRef, i); + ref Abgr32 dp = ref Unsafe.Add(ref destRef, i); dp.FromLa16(sp); } @@ -92,8 +92,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref La16 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Bgr24 dp = ref Unsafe.Add(ref destRef, (int)i); + ref La16 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); dp.FromLa16(sp); } @@ -112,8 +112,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref La16 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Bgra32 dp = ref Unsafe.Add(ref destRef, (int)i); + ref La16 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); dp.FromLa16(sp); } @@ -132,8 +132,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref La16 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref L8 dp = ref Unsafe.Add(ref destRef, (int)i); + ref La16 sp = ref Unsafe.Add(ref sourceRef, i); + ref L8 dp = ref Unsafe.Add(ref destRef, i); dp.FromLa16(sp); } @@ -152,8 +152,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref La16 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref L16 dp = ref Unsafe.Add(ref destRef, (int)i); + ref La16 sp = ref Unsafe.Add(ref sourceRef, i); + ref L16 dp = ref Unsafe.Add(ref destRef, i); dp.FromLa16(sp); } @@ -172,8 +172,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref La16 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref La32 dp = ref Unsafe.Add(ref destRef, (int)i); + ref La16 sp = ref Unsafe.Add(ref sourceRef, i); + ref La32 dp = ref Unsafe.Add(ref destRef, i); dp.FromLa16(sp); } @@ -192,8 +192,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref La16 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Rgb24 dp = ref Unsafe.Add(ref destRef, (int)i); + ref La16 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); dp.FromLa16(sp); } @@ -212,8 +212,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref La16 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Rgba32 dp = ref Unsafe.Add(ref destRef, (int)i); + ref La16 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); dp.FromLa16(sp); } @@ -232,8 +232,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref La16 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Rgb48 dp = ref Unsafe.Add(ref destRef, (int)i); + ref La16 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); dp.FromLa16(sp); } @@ -252,8 +252,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref La16 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Rgba64 dp = ref Unsafe.Add(ref destRef, (int)i); + ref La16 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); dp.FromLa16(sp); } @@ -272,8 +272,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref La16 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Bgra5551 dp = ref Unsafe.Add(ref destRef, (int)i); + ref La16 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i); dp.FromLa16(sp); } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/La32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/La32.PixelOperations.Generated.cs index ddf94261e..32a0f24e3 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/La32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/La32.PixelOperations.Generated.cs @@ -52,8 +52,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref La32 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Argb32 dp = ref Unsafe.Add(ref destRef, (int)i); + ref La32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Argb32 dp = ref Unsafe.Add(ref destRef, i); dp.FromLa32(sp); } @@ -72,8 +72,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref La32 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Abgr32 dp = ref Unsafe.Add(ref destRef, (int)i); + ref La32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Abgr32 dp = ref Unsafe.Add(ref destRef, i); dp.FromLa32(sp); } @@ -92,8 +92,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref La32 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Bgr24 dp = ref Unsafe.Add(ref destRef, (int)i); + ref La32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); dp.FromLa32(sp); } @@ -112,8 +112,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref La32 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Bgra32 dp = ref Unsafe.Add(ref destRef, (int)i); + ref La32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); dp.FromLa32(sp); } @@ -132,8 +132,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref La32 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref L8 dp = ref Unsafe.Add(ref destRef, (int)i); + ref La32 sp = ref Unsafe.Add(ref sourceRef, i); + ref L8 dp = ref Unsafe.Add(ref destRef, i); dp.FromLa32(sp); } @@ -152,8 +152,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref La32 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref L16 dp = ref Unsafe.Add(ref destRef, (int)i); + ref La32 sp = ref Unsafe.Add(ref sourceRef, i); + ref L16 dp = ref Unsafe.Add(ref destRef, i); dp.FromLa32(sp); } @@ -172,8 +172,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref La32 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref La16 dp = ref Unsafe.Add(ref destRef, (int)i); + ref La32 sp = ref Unsafe.Add(ref sourceRef, i); + ref La16 dp = ref Unsafe.Add(ref destRef, i); dp.FromLa32(sp); } @@ -192,8 +192,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref La32 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Rgb24 dp = ref Unsafe.Add(ref destRef, (int)i); + ref La32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); dp.FromLa32(sp); } @@ -212,8 +212,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref La32 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Rgba32 dp = ref Unsafe.Add(ref destRef, (int)i); + ref La32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); dp.FromLa32(sp); } @@ -232,8 +232,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref La32 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Rgb48 dp = ref Unsafe.Add(ref destRef, (int)i); + ref La32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); dp.FromLa32(sp); } @@ -252,8 +252,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref La32 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Rgba64 dp = ref Unsafe.Add(ref destRef, (int)i); + ref La32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); dp.FromLa32(sp); } @@ -272,8 +272,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref La32 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Bgra5551 dp = ref Unsafe.Add(ref destRef, (int)i); + ref La32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i); dp.FromLa32(sp); } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgb24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgb24.PixelOperations.Generated.cs index e89b17f72..53a82989d 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgb24.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgb24.PixelOperations.Generated.cs @@ -206,8 +206,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref L8 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); + ref L8 dp = ref Unsafe.Add(ref destRef, i); dp.FromRgb24(sp); } @@ -226,8 +226,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref L16 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); + ref L16 dp = ref Unsafe.Add(ref destRef, i); dp.FromRgb24(sp); } @@ -246,8 +246,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref La16 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); + ref La16 dp = ref Unsafe.Add(ref destRef, i); dp.FromRgb24(sp); } @@ -266,8 +266,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref La32 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); + ref La32 dp = ref Unsafe.Add(ref destRef, i); dp.FromRgb24(sp); } @@ -286,8 +286,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Rgb48 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); dp.FromRgb24(sp); } @@ -306,8 +306,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Rgba64 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); dp.FromRgb24(sp); } @@ -326,8 +326,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Bgra5551 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i); dp.FromRgb24(sp); } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgb48.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgb48.PixelOperations.Generated.cs index 017124ef1..d1c5ab2e3 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgb48.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgb48.PixelOperations.Generated.cs @@ -52,8 +52,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Argb32 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); + ref Argb32 dp = ref Unsafe.Add(ref destRef, i); dp.FromRgb48(sp); } @@ -72,8 +72,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Abgr32 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); + ref Abgr32 dp = ref Unsafe.Add(ref destRef, i); dp.FromRgb48(sp); } @@ -92,8 +92,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Bgr24 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); dp.FromRgb48(sp); } @@ -112,8 +112,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Bgra32 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); dp.FromRgb48(sp); } @@ -132,8 +132,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref L8 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); + ref L8 dp = ref Unsafe.Add(ref destRef, i); dp.FromRgb48(sp); } @@ -152,8 +152,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref L16 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); + ref L16 dp = ref Unsafe.Add(ref destRef, i); dp.FromRgb48(sp); } @@ -172,8 +172,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref La16 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); + ref La16 dp = ref Unsafe.Add(ref destRef, i); dp.FromRgb48(sp); } @@ -192,8 +192,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref La32 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); + ref La32 dp = ref Unsafe.Add(ref destRef, i); dp.FromRgb48(sp); } @@ -212,8 +212,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Rgb24 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); dp.FromRgb48(sp); } @@ -232,8 +232,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Rgba32 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); dp.FromRgb48(sp); } @@ -252,8 +252,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Rgba64 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); dp.FromRgb48(sp); } @@ -272,8 +272,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Bgra5551 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i); dp.FromRgb48(sp); } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgba32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgba32.PixelOperations.Generated.cs index 483c3f69c..2608a74fc 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgba32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgba32.PixelOperations.Generated.cs @@ -187,8 +187,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref L8 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); + ref L8 dp = ref Unsafe.Add(ref destRef, i); dp.FromRgba32(sp); } @@ -207,8 +207,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref L16 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); + ref L16 dp = ref Unsafe.Add(ref destRef, i); dp.FromRgba32(sp); } @@ -227,8 +227,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref La16 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); + ref La16 dp = ref Unsafe.Add(ref destRef, i); dp.FromRgba32(sp); } @@ -247,8 +247,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref La32 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); + ref La32 dp = ref Unsafe.Add(ref destRef, i); dp.FromRgba32(sp); } @@ -267,8 +267,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Rgb48 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); dp.FromRgba32(sp); } @@ -287,8 +287,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Rgba64 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); dp.FromRgba32(sp); } @@ -307,8 +307,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Bgra5551 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i); dp.FromRgba32(sp); } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgba64.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgba64.PixelOperations.Generated.cs index a82fb26b4..f6445039a 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgba64.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgba64.PixelOperations.Generated.cs @@ -52,8 +52,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Argb32 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); + ref Argb32 dp = ref Unsafe.Add(ref destRef, i); dp.FromRgba64(sp); } @@ -72,8 +72,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Abgr32 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); + ref Abgr32 dp = ref Unsafe.Add(ref destRef, i); dp.FromRgba64(sp); } @@ -92,8 +92,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Bgr24 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); dp.FromRgba64(sp); } @@ -112,8 +112,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Bgra32 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); dp.FromRgba64(sp); } @@ -132,8 +132,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref L8 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); + ref L8 dp = ref Unsafe.Add(ref destRef, i); dp.FromRgba64(sp); } @@ -152,8 +152,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref L16 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); + ref L16 dp = ref Unsafe.Add(ref destRef, i); dp.FromRgba64(sp); } @@ -172,8 +172,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref La16 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); + ref La16 dp = ref Unsafe.Add(ref destRef, i); dp.FromRgba64(sp); } @@ -192,8 +192,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref La32 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); + ref La32 dp = ref Unsafe.Add(ref destRef, i); dp.FromRgba64(sp); } @@ -212,8 +212,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Rgb24 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); dp.FromRgba64(sp); } @@ -232,8 +232,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Rgba32 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); dp.FromRgba64(sp); } @@ -252,8 +252,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Rgb48 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); dp.FromRgba64(sp); } @@ -272,8 +272,8 @@ namespace SixLabors.ImageSharp.PixelFormats for (nint i = 0; i < sourcePixels.Length; i++) { - ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref Bgra5551 dp = ref Unsafe.Add(ref destRef, (int)i); + ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i); dp.FromRgba64(sp); } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/_Common.ttinclude b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/_Common.ttinclude index 9da66a5a9..9a6ddd7d4 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/_Common.ttinclude +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/_Common.ttinclude @@ -106,8 +106,8 @@ using SixLabors.ImageSharp.PixelFormats.Utils; for (nint i = 0; i < sourcePixels.Length; i++) { - ref <#=fromPixelType#> sp = ref Unsafe.Add(ref sourceRef, (int)i); - ref <#=toPixelType#> dp = ref Unsafe.Add(ref destRef, (int)i); + ref <#=fromPixelType#> sp = ref Unsafe.Add(ref sourceRef, i); + ref <#=toPixelType#> dp = ref Unsafe.Add(ref destRef, i); dp.From<#=fromPixelType#>(sp); } From e04ea46df19e47513d9cbffa87c4f0c43aae561a Mon Sep 17 00:00:00 2001 From: Ynse Hoornenborg Date: Sun, 12 Dec 2021 13:41:16 +0100 Subject: [PATCH 072/121] Use Numerics class as polyfill for BitOperations --- .../Common/Helpers/BitOperations.cs | 26 ----------------- src/ImageSharp/Common/Helpers/Numerics.cs | 28 +++++++++++++++++++ .../Helpers/Shuffle/IComponentShuffle.cs | 4 +-- 3 files changed, 30 insertions(+), 28 deletions(-) delete mode 100644 src/ImageSharp/Common/Helpers/BitOperations.cs diff --git a/src/ImageSharp/Common/Helpers/BitOperations.cs b/src/ImageSharp/Common/Helpers/BitOperations.cs deleted file mode 100644 index af56efd56..000000000 --- a/src/ImageSharp/Common/Helpers/BitOperations.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Apache License, Version 2.0. - -using System.Runtime.CompilerServices; - -#if !NETCOREAPP3_1_OR_GREATER -namespace SixLabors.ImageSharp.Common.Helpers -{ - /// - /// Polyfill for System.Numerics.BitOperations class, introduced in .NET Core 3.0. - /// - /// - public static class BitOperations - { - /// - /// Rotates the specified value left by the specified number of bits. - /// - /// The value to rotate. - /// The number of bits to roate with. - /// The rotated value. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static uint RotateLeft(uint value, int offset) - => (value << offset) | (value >> (32 - offset)); - } -} -#endif diff --git a/src/ImageSharp/Common/Helpers/Numerics.cs b/src/ImageSharp/Common/Helpers/Numerics.cs index fa0af823d..df81c39e7 100644 --- a/src/ImageSharp/Common/Helpers/Numerics.cs +++ b/src/ImageSharp/Common/Helpers/Numerics.cs @@ -907,5 +907,33 @@ namespace SixLabors.ImageSharp /// Divisor value. /// Ceiled division result. public static uint DivideCeil(uint value, uint divisor) => (value + divisor - 1) / divisor; + + /// + /// Rotates the specified value left by the specified number of bits. + /// + /// The value to rotate. + /// The number of bits to roate with. + /// The rotated value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static uint RotateLeft(uint value, int offset) + { +#if SUPPORTS_BITOPERATIONS + return BitOperations.RotateLeft(value, offset); +#else + return RotateLeftSoftwareFallback(value, offset); +#endif + } + +#if !SUPPORTS_BITOPERATIONS + /// + /// Rotates the specified value left by the specified number of bits. + /// + /// The value to rotate. + /// The number of bits to roate with. + /// The rotated value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static uint RotateLeftSoftwareFallback(uint value, int offset) + => (value << offset) | (value >> (32 - offset)); +#endif } } diff --git a/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs b/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs index 1922c787c..da60928d3 100644 --- a/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs +++ b/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs @@ -190,7 +190,7 @@ namespace SixLabors.ImageSharp // tmp1 + tmp3 = [W X Y Z] uint tmp1 = packed & 0xFF00FF00; uint tmp2 = packed & 0x00FF00FF; - uint tmp3 = BitOperations.RotateLeft(tmp2, 16); + uint tmp3 = Numerics.RotateLeft(tmp2, 16); Unsafe.Add(ref dBase, i) = tmp1 + tmp3; } @@ -223,7 +223,7 @@ namespace SixLabors.ImageSharp // tmp1 + tmp3 = [Y Z W X] uint tmp1 = packed & 0x00FF00FF; uint tmp2 = packed & 0xFF00FF00; - uint tmp3 = BitOperations.RotateLeft(tmp2, 16); + uint tmp3 = Numerics.RotateLeft(tmp2, 16); Unsafe.Add(ref dBase, i) = tmp1 + tmp3; } From ed611ca48cb11f6421c1a4603c8eacf43f4fa22e Mon Sep 17 00:00:00 2001 From: Ynse Hoornenborg Date: Sun, 12 Dec 2021 16:51:11 +0100 Subject: [PATCH 073/121] Revert submodule changes --- .gitattributes | 8 ++++++-- shared-infrastructure | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/.gitattributes b/.gitattributes index 70ced6903..355b64dce 100644 --- a/.gitattributes +++ b/.gitattributes @@ -87,7 +87,6 @@ *.eot binary *.exe binary *.otf binary -*.pbm binary *.pdf binary *.ppt binary *.pptx binary @@ -95,7 +94,6 @@ *.snk binary *.ttc binary *.ttf binary -*.wbmp binary *.woff binary *.woff2 binary *.xls binary @@ -126,3 +124,9 @@ *.dds filter=lfs diff=lfs merge=lfs -text *.ktx filter=lfs diff=lfs merge=lfs -text *.ktx2 filter=lfs diff=lfs merge=lfs -text +*.pam filter=lfs diff=lfs merge=lfs -text +*.pbm filter=lfs diff=lfs merge=lfs -text +*.pgm filter=lfs diff=lfs merge=lfs -text +*.ppm filter=lfs diff=lfs merge=lfs -text +*.pnm filter=lfs diff=lfs merge=lfs -text +*.wbmp filter=lfs diff=lfs merge=lfs -text diff --git a/shared-infrastructure b/shared-infrastructure index a042aba17..59ce17f5a 160000 --- a/shared-infrastructure +++ b/shared-infrastructure @@ -1 +1 @@ -Subproject commit a042aba176cdb840d800c6ed4cfe41a54fb7b1e3 +Subproject commit 59ce17f5a4e1f956811133f41add7638e74c2836 From 752520cf08119897e3b05b22d36c780d39006a32 Mon Sep 17 00:00:00 2001 From: Ynse Hoornenborg Date: Mon, 13 Dec 2021 01:36:35 +0100 Subject: [PATCH 074/121] Use nuint in IComponentShuffle again --- src/ImageSharp/Common/Helpers/Numerics.cs | 32 +++++++++++++- .../Helpers/Shuffle/IComponentShuffle.cs | 42 +++++++++---------- 2 files changed, 50 insertions(+), 24 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/Numerics.cs b/src/ImageSharp/Common/Helpers/Numerics.cs index df81c39e7..513db0c44 100644 --- a/src/ImageSharp/Common/Helpers/Numerics.cs +++ b/src/ImageSharp/Common/Helpers/Numerics.cs @@ -912,7 +912,7 @@ namespace SixLabors.ImageSharp /// Rotates the specified value left by the specified number of bits. /// /// The value to rotate. - /// The number of bits to roate with. + /// The number of bits to rotate with. /// The rotated value. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint RotateLeft(uint value, int offset) @@ -929,11 +929,39 @@ namespace SixLabors.ImageSharp /// Rotates the specified value left by the specified number of bits. /// /// The value to rotate. - /// The number of bits to roate with. + /// The number of bits to rotate with. /// The rotated value. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint RotateLeftSoftwareFallback(uint value, int offset) => (value << offset) | (value >> (32 - offset)); #endif + + /// + /// Rotates the specified value right by the specified number of bits. + /// + /// The value to rotate. + /// The number of bits to rotate with. + /// The rotated value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static uint RotateRight(uint value, int offset) + { +#if SUPPORTS_BITOPERATIONS + return BitOperations.RotateRight(value, offset); +#else + return RotateRightSoftwareFallback(value, offset); +#endif + } + +#if !SUPPORTS_BITOPERATIONS + /// + /// Rotates the specified value right by the specified number of bits. + /// + /// The value to rotate. + /// The number of bits to rotate with. + /// The rotated value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static uint RotateRightSoftwareFallback(uint value, int offset) + => (value >> offset) | (value << (32 - offset)); +#endif } } diff --git a/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs b/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs index da60928d3..a1224a767 100644 --- a/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs +++ b/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs @@ -3,10 +3,8 @@ using System; using System.Buffers.Binary; -using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.Common.Helpers; // The JIT can detect and optimize rotation idioms ROTL (Rotate Left) // and ROTR (Rotate Right) emitting efficient CPU instructions: @@ -99,15 +97,15 @@ namespace SixLabors.ImageSharp { ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); - nint n = (nint)source.Length / 4; + nuint n = (nuint)(uint)source.Length / 4; - for (nint i = 0; i < n; i++) + for (nuint i = 0; i < n; i++) { - uint packed = Unsafe.Add(ref sBase, i); + uint packed = Unsafe.Add(ref sBase, (IntPtr)(uint)i); // packed = [W Z Y X] // ROTL(8, packed) = [Z Y X W] - Unsafe.Add(ref dBase, i) = (packed << 8) | (packed >> 24); + Unsafe.Add(ref dBase, (IntPtr)(uint)i) = (packed << 8) | (packed >> 24); } } } @@ -125,15 +123,15 @@ namespace SixLabors.ImageSharp { ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); - nint n = (nint)source.Length / 4; + nuint n = (nuint)(uint)source.Length / 4; - for (nint i = 0; i < n; i++) + for (nuint i = 0; i < n; i++) { - uint packed = Unsafe.Add(ref sBase, i); + uint packed = Unsafe.Add(ref sBase, (IntPtr)(uint)i); // packed = [W Z Y X] // REVERSE(packedArgb) = [X Y Z W] - Unsafe.Add(ref dBase, i) = BinaryPrimitives.ReverseEndianness(packed); + Unsafe.Add(ref dBase, (IntPtr)(uint)i) = BinaryPrimitives.ReverseEndianness(packed); } } } @@ -151,15 +149,15 @@ namespace SixLabors.ImageSharp { ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); - nint n = (nint)source.Length / 4; + nuint n = (nuint)(uint)source.Length / 4; - for (nint i = 0; i < n; i++) + for (nuint i = 0; i < n; i++) { - uint packed = Unsafe.Add(ref sBase, i); + uint packed = Unsafe.Add(ref sBase, (IntPtr)(uint)i); // packed = [W Z Y X] // ROTR(8, packedArgb) = [Y Z W X] - Unsafe.Add(ref dBase, i) = (packed >> 8) | (packed << 24); + Unsafe.Add(ref dBase, (IntPtr)(uint)i) = Numerics.RotateRight(packed, 8); } } } @@ -177,11 +175,11 @@ namespace SixLabors.ImageSharp { ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); - nint n = (nint)source.Length / 4; + nuint n = (nuint)(uint)source.Length / 4; - for (nint i = 0; i < n; i++) + for (nuint i = 0; i < n; i++) { - uint packed = Unsafe.Add(ref sBase, i); + uint packed = Unsafe.Add(ref sBase, (IntPtr)(uint)i); // packed = [W Z Y X] // tmp1 = [W 0 Y 0] @@ -192,7 +190,7 @@ namespace SixLabors.ImageSharp uint tmp2 = packed & 0x00FF00FF; uint tmp3 = Numerics.RotateLeft(tmp2, 16); - Unsafe.Add(ref dBase, i) = tmp1 + tmp3; + Unsafe.Add(ref dBase, (IntPtr)(uint)i) = tmp1 + tmp3; } } } @@ -210,11 +208,11 @@ namespace SixLabors.ImageSharp { ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); - nint n = (nint)source.Length / 4; + nuint n = (nuint)(uint)source.Length / 4; - for (nint i = 0; i < n; i++) + for (nuint i = 0; i < n; i++) { - uint packed = Unsafe.Add(ref sBase, i); + uint packed = Unsafe.Add(ref sBase, (IntPtr)(uint)i); // packed = [W Z Y X] // tmp1 = [0 Z 0 X] @@ -225,7 +223,7 @@ namespace SixLabors.ImageSharp uint tmp2 = packed & 0xFF00FF00; uint tmp3 = Numerics.RotateLeft(tmp2, 16); - Unsafe.Add(ref dBase, i) = tmp1 + tmp3; + Unsafe.Add(ref dBase, (IntPtr)(uint)i) = tmp1 + tmp3; } } } From 8ea98385cef8e68317f9249f3e85ee2d6b40f352 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Thu, 16 Dec 2021 13:13:06 +0100 Subject: [PATCH 075/121] Verify CRC of IDAT chunk is correct --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index ffaa9d567..f81cbca21 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -1206,16 +1206,16 @@ namespace SixLabors.ImageSharp.Formats.Png PngChunkType type = this.ReadChunkType(); - // NOTE: Reading the Data chunk is the responsible of the caller // If we're reading color metadata only we're only interested in the IHDR and tRNS chunks. // We can skip all other chunk data in the stream for better performance. - if (type == PngChunkType.Data || (this.colorMetadataOnly && type != PngChunkType.Header && type != PngChunkType.Transparency)) + if (this.colorMetadataOnly && type != PngChunkType.Header && type != PngChunkType.Transparency) { chunk = new PngChunk(length, type); return true; } + long pos = this.currentStream.Position; chunk = new PngChunk( length: length, type: type, @@ -1223,6 +1223,13 @@ namespace SixLabors.ImageSharp.Formats.Png this.ValidateChunk(chunk); + // Restore the stream position for IDAT chunks, because it will be decoded later and + // was only read to verifying the CRC is correct. + if (type == PngChunkType.Data) + { + this.currentStream.Position = pos; + } + return true; } From 3310fa6ffdfd283b834c91cdfa76436bdf07332e Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Thu, 16 Dec 2021 13:21:27 +0100 Subject: [PATCH 076/121] Add test for wrong CRC in IDAT chunk --- .../Formats/Png/PngDecoderTests.cs | 33 ++++++++++++++----- tests/ImageSharp.Tests/TestImages.cs | 1 + tests/Images/Input/Png/xcsn0g01.png | 3 ++ 3 files changed, 28 insertions(+), 9 deletions(-) create mode 100644 tests/Images/Input/Png/xcsn0g01.png diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs index d63dad8d4..de1c47d41 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs @@ -255,7 +255,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png public void Decode_MissingDataChunk_ThrowsException(TestImageProvider provider) where TPixel : unmanaged, IPixel { - System.Exception ex = Record.Exception( + Exception ex = Record.Exception( () => { using Image image = provider.GetImage(PngDecoder); @@ -271,7 +271,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png public void Decode_InvalidBitDepth_ThrowsException(TestImageProvider provider) where TPixel : unmanaged, IPixel { - System.Exception ex = Record.Exception( + Exception ex = Record.Exception( () => { using Image image = provider.GetImage(PngDecoder); @@ -287,7 +287,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png public void Decode_InvalidColorType_ThrowsException(TestImageProvider provider) where TPixel : unmanaged, IPixel { - System.Exception ex = Record.Exception( + Exception ex = Record.Exception( () => { using Image image = provider.GetImage(PngDecoder); @@ -297,13 +297,28 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png Assert.Contains("Invalid or unsupported color type", ex.Message); } + [Theory] + [WithFile(TestImages.Png.Bad.WrongCrcDataChunk, PixelTypes.Rgba32)] + public void Decode_InvalidDataChunkCrc_ThrowsException(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + Exception ex = Record.Exception( + () => + { + using Image image = provider.GetImage(PngDecoder); + image.DebugSave(provider); + }); + Assert.NotNull(ex); + Assert.Contains("CRC Error. PNG IDAT chunk is corrupt!", ex.Message); + } + // https://github.com/SixLabors/ImageSharp/issues/1014 [Theory] [WithFileCollection(nameof(TestImagesIssue1014), PixelTypes.Rgba32)] public void Issue1014_DataSplitOverMultipleIDatChunks(TestImageProvider provider) where TPixel : unmanaged, IPixel { - System.Exception ex = Record.Exception( + Exception ex = Record.Exception( () => { using Image image = provider.GetImage(PngDecoder); @@ -319,7 +334,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png public void Issue1177_CRC_Omitted(TestImageProvider provider) where TPixel : unmanaged, IPixel { - System.Exception ex = Record.Exception( + Exception ex = Record.Exception( () => { using Image image = provider.GetImage(PngDecoder); @@ -335,7 +350,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png public void Issue1127(TestImageProvider provider) where TPixel : unmanaged, IPixel { - System.Exception ex = Record.Exception( + Exception ex = Record.Exception( () => { using Image image = provider.GetImage(PngDecoder); @@ -351,7 +366,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png public void Issue1047(TestImageProvider provider) where TPixel : unmanaged, IPixel { - System.Exception ex = Record.Exception( + Exception ex = Record.Exception( () => { using Image image = provider.GetImage(PngDecoder); @@ -372,7 +387,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png public void Issue1765(TestImageProvider provider) where TPixel : unmanaged, IPixel { - System.Exception ex = Record.Exception( + Exception ex = Record.Exception( () => { using Image image = provider.GetImage(PngDecoder); @@ -388,7 +403,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png public void Issue410_MalformedApplePng(TestImageProvider provider) where TPixel : unmanaged, IPixel { - System.Exception ex = Record.Exception( + Exception ex = Record.Exception( () => { using Image image = provider.GetImage(PngDecoder); diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index f43c0c9bd..b87ffc742 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -120,6 +120,7 @@ namespace SixLabors.ImageSharp.Tests public static class Bad { public const string MissingDataChunk = "Png/xdtn0g01.png"; + public const string WrongCrcDataChunk = "Png/xcsn0g01.png"; public const string CorruptedChunk = "Png/big-corrupted-chunk.png"; // Zlib errors. diff --git a/tests/Images/Input/Png/xcsn0g01.png b/tests/Images/Input/Png/xcsn0g01.png new file mode 100644 index 000000000..6908a107c --- /dev/null +++ b/tests/Images/Input/Png/xcsn0g01.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:71e4b2826f61556eda39f3a93c8769b14d3ac90f135177b9373061199dbef39a +size 164 From f3a5ba0b4d94b2e8422416a733e3d7d272fa0786 Mon Sep 17 00:00:00 2001 From: Brian Popow <38701097+brianpopow@users.noreply.github.com> Date: Thu, 16 Dec 2021 15:45:23 +0100 Subject: [PATCH 077/121] Review suggestion Co-authored-by: Anton Firszov --- tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs index de1c47d41..c29f8c589 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs @@ -302,11 +302,10 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png public void Decode_InvalidDataChunkCrc_ThrowsException(TestImageProvider provider) where TPixel : unmanaged, IPixel { - Exception ex = Record.Exception( + InvalidImageContentException ex = Assert.Throws( () => { using Image image = provider.GetImage(PngDecoder); - image.DebugSave(provider); }); Assert.NotNull(ex); Assert.Contains("CRC Error. PNG IDAT chunk is corrupt!", ex.Message); From 3ee73a89c535e379ec36e6edf032332a7d466bf5 Mon Sep 17 00:00:00 2001 From: Ynse Hoornenborg Date: Thu, 16 Dec 2021 17:50:55 +0100 Subject: [PATCH 078/121] Update IComponentShuffle back to int again --- .../Helpers/Shuffle/IComponentShuffle.cs | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs b/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs index a1224a767..049c61185 100644 --- a/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs +++ b/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs @@ -97,15 +97,15 @@ namespace SixLabors.ImageSharp { ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); - nuint n = (nuint)(uint)source.Length / 4; + int n = source.Length / 4; - for (nuint i = 0; i < n; i++) + for (int i = 0; i < n; i++) { - uint packed = Unsafe.Add(ref sBase, (IntPtr)(uint)i); + uint packed = Unsafe.Add(ref sBase, i); // packed = [W Z Y X] // ROTL(8, packed) = [Z Y X W] - Unsafe.Add(ref dBase, (IntPtr)(uint)i) = (packed << 8) | (packed >> 24); + Unsafe.Add(ref dBase, i) = (packed << 8) | (packed >> 24); } } } @@ -123,15 +123,15 @@ namespace SixLabors.ImageSharp { ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); - nuint n = (nuint)(uint)source.Length / 4; + int n = source.Length / 4; - for (nuint i = 0; i < n; i++) + for (int i = 0; i < n; i++) { - uint packed = Unsafe.Add(ref sBase, (IntPtr)(uint)i); + uint packed = Unsafe.Add(ref sBase, i); // packed = [W Z Y X] // REVERSE(packedArgb) = [X Y Z W] - Unsafe.Add(ref dBase, (IntPtr)(uint)i) = BinaryPrimitives.ReverseEndianness(packed); + Unsafe.Add(ref dBase, i) = BinaryPrimitives.ReverseEndianness(packed); } } } @@ -149,15 +149,15 @@ namespace SixLabors.ImageSharp { ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); - nuint n = (nuint)(uint)source.Length / 4; + int n = source.Length / 4; - for (nuint i = 0; i < n; i++) + for (int i = 0; i < n; i++) { - uint packed = Unsafe.Add(ref sBase, (IntPtr)(uint)i); + uint packed = Unsafe.Add(ref sBase, i); // packed = [W Z Y X] // ROTR(8, packedArgb) = [Y Z W X] - Unsafe.Add(ref dBase, (IntPtr)(uint)i) = Numerics.RotateRight(packed, 8); + Unsafe.Add(ref dBase, i) = Numerics.RotateRight(packed, 8); } } } @@ -175,11 +175,11 @@ namespace SixLabors.ImageSharp { ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); - nuint n = (nuint)(uint)source.Length / 4; + int n = source.Length / 4; - for (nuint i = 0; i < n; i++) + for (int i = 0; i < n; i++) { - uint packed = Unsafe.Add(ref sBase, (IntPtr)(uint)i); + uint packed = Unsafe.Add(ref sBase, i); // packed = [W Z Y X] // tmp1 = [W 0 Y 0] @@ -190,7 +190,7 @@ namespace SixLabors.ImageSharp uint tmp2 = packed & 0x00FF00FF; uint tmp3 = Numerics.RotateLeft(tmp2, 16); - Unsafe.Add(ref dBase, (IntPtr)(uint)i) = tmp1 + tmp3; + Unsafe.Add(ref dBase, i) = tmp1 + tmp3; } } } @@ -208,11 +208,11 @@ namespace SixLabors.ImageSharp { ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); - nuint n = (nuint)(uint)source.Length / 4; + int n = source.Length / 4; - for (nuint i = 0; i < n; i++) + for (int i = 0; i < n; i++) { - uint packed = Unsafe.Add(ref sBase, (IntPtr)(uint)i); + uint packed = Unsafe.Add(ref sBase, i); // packed = [W Z Y X] // tmp1 = [0 Z 0 X] @@ -223,7 +223,7 @@ namespace SixLabors.ImageSharp uint tmp2 = packed & 0xFF00FF00; uint tmp3 = Numerics.RotateLeft(tmp2, 16); - Unsafe.Add(ref dBase, (IntPtr)(uint)i) = tmp1 + tmp3; + Unsafe.Add(ref dBase, i) = tmp1 + tmp3; } } } From e045fbb023b561f9b327e434e7aae319772372b6 Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Fri, 17 Dec 2021 13:53:46 +0300 Subject: [PATCH 079/121] Sampling factor validation --- .../Jpeg/Components/Decoder/JpegComponent.cs | 11 ------- .../Formats/Jpeg/JpegDecoderCore.cs | 29 +++++++++++++++++-- .../Formats/Jpg/JpegDecoderTests.Images.cs | 6 ++-- 3 files changed, 29 insertions(+), 17 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponent.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponent.cs index 4da422e7f..3804e1c6c 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponent.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponent.cs @@ -19,21 +19,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder this.Frame = frame; this.Id = id; - // Validate sampling factors. - if (horizontalFactor == 0 || verticalFactor == 0) - { - JpegThrowHelper.ThrowBadSampling(); - } - this.HorizontalSamplingFactor = horizontalFactor; this.VerticalSamplingFactor = verticalFactor; this.SamplingFactors = new Size(this.HorizontalSamplingFactor, this.VerticalSamplingFactor); - if (quantizationTableIndex > 3) - { - JpegThrowHelper.ThrowBadQuantizationTableIndex(quantizationTableIndex); - } - this.QuantizationTableIndex = quantizationTableIndex; this.Index = index; } diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index 4be6731cc..bd221a357 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -1022,10 +1022,26 @@ namespace SixLabors.ImageSharp.Formats.Jpeg int index = 0; for (int i = 0; i < componentCount; i++) { + // 1 byte: component identifier + byte componentId = this.temp[index]; + + // 1 byte: component sampling factors byte hv = this.temp[index + 1]; int h = (hv >> 4) & 15; int v = hv & 15; + // Validate: 1-4 range + if (h is < 1 or > 4) + { + JpegThrowHelper.ThrowInvalidImageContentException($"Bad horizontal sampling factor: {h}"); + } + + // Validate: 1-4 range + if (v is < 1 or > 4) + { + JpegThrowHelper.ThrowInvalidImageContentException($"Bad vertical sampling factor: {v}"); + } + if (maxH < h) { maxH = h; @@ -1036,10 +1052,19 @@ namespace SixLabors.ImageSharp.Formats.Jpeg maxV = v; } - var component = new JpegComponent(this.Configuration.MemoryAllocator, this.Frame, this.temp[index], h, v, this.temp[index + 2], i); + // 1 byte: quantization table destination selector + byte quantTableIndex = this.temp[index + 2]; + + // Validate: 0-3 range + if (quantTableIndex > 3) + { + JpegThrowHelper.ThrowBadQuantizationTableIndex(quantTableIndex); + } + + var component = new JpegComponent(this.Configuration.MemoryAllocator, this.Frame, componentId, h, v, quantTableIndex, i); this.Frame.Components[i] = component; - this.Frame.ComponentIds[i] = component.Id; + this.Frame.ComponentIds[i] = componentId; index += componentBytes; } diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs index ef817154d..d82359e61 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs @@ -40,9 +40,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg // LibJpeg can open this despite incorrect colorspace metadata. TestImages.Jpeg.Issues.IncorrectColorspace855, - // LibJpeg can open this despite the invalid subsampling units. - TestImages.Jpeg.Issues.Fuzz.IndexOutOfRangeException824C, - // High depth images TestImages.Jpeg.Baseline.Testorig12bit, }; @@ -90,7 +87,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg TestImages.Jpeg.Issues.Fuzz.AccessViolationException827, TestImages.Jpeg.Issues.Fuzz.ExecutionEngineException839, TestImages.Jpeg.Issues.Fuzz.IndexOutOfRangeException1693A, - TestImages.Jpeg.Issues.Fuzz.IndexOutOfRangeException1693B + TestImages.Jpeg.Issues.Fuzz.IndexOutOfRangeException1693B, + TestImages.Jpeg.Issues.Fuzz.IndexOutOfRangeException824C, }; private static readonly Dictionary CustomToleranceValues = From 1f9ef3e926372325ebc8d342729f03cb782e880a Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Sat, 18 Dec 2021 11:13:39 +0300 Subject: [PATCH 080/121] Removed unused methods, added new throw helper method --- .../Formats/Jpeg/JpegDecoderCore.cs | 4 ++-- .../Formats/Jpeg/JpegThrowHelper.cs | 20 +++---------------- 2 files changed, 5 insertions(+), 19 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index bd221a357..4543153de 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -1033,13 +1033,13 @@ namespace SixLabors.ImageSharp.Formats.Jpeg // Validate: 1-4 range if (h is < 1 or > 4) { - JpegThrowHelper.ThrowInvalidImageContentException($"Bad horizontal sampling factor: {h}"); + JpegThrowHelper.ThrowBadSampling(h); } // Validate: 1-4 range if (v is < 1 or > 4) { - JpegThrowHelper.ThrowInvalidImageContentException($"Bad vertical sampling factor: {v}"); + JpegThrowHelper.ThrowBadSampling(v); } if (maxH < h) diff --git a/src/ImageSharp/Formats/Jpeg/JpegThrowHelper.cs b/src/ImageSharp/Formats/Jpeg/JpegThrowHelper.cs index b6c7e7626..0292fbcab 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegThrowHelper.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegThrowHelper.cs @@ -22,23 +22,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg [MethodImpl(InliningOptions.ColdPath)] public static void ThrowInvalidImageContentException(string errorMessage) => throw new InvalidImageContentException(errorMessage); - /// - /// Cold path optimization for throwing 's. - /// - /// The error message for the exception. - /// The exception that is the cause of the current exception, or a null reference - /// if no inner exception is specified. - [MethodImpl(InliningOptions.ColdPath)] - public static void ThrowInvalidImageContentException(string errorMessage, Exception innerException) => throw new InvalidImageContentException(errorMessage, innerException); - - /// - /// Cold path optimization for throwing 's - /// - /// The error message for the exception. - [MethodImpl(InliningOptions.ColdPath)] - public static void ThrowNotImplementedException(string errorMessage) - => throw new NotImplementedException(errorMessage); - [MethodImpl(InliningOptions.ColdPath)] public static void ThrowBadMarker(string marker, int length) => throw new InvalidImageContentException($"Marker {marker} has bad length {length}."); @@ -51,6 +34,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg [MethodImpl(InliningOptions.ColdPath)] public static void ThrowBadSampling() => throw new InvalidImageContentException("Bad sampling factor."); + [MethodImpl(InliningOptions.ColdPath)] + public static void ThrowBadSampling(int factor) => throw new InvalidImageContentException($"Bad sampling factor: {factor}"); + [MethodImpl(InliningOptions.ColdPath)] public static void ThrowBadProgressiveScan(int ss, int se, int ah, int al) => throw new InvalidImageContentException($"Invalid progressive parameters Ss={ss} Se={se} Ah={ah} Al={al}."); From f3b8e5cd8d1e00492367b40498de1a67f6da2375 Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Sat, 18 Dec 2021 15:42:13 +0300 Subject: [PATCH 081/121] gfoidl IsOutOfRange --- src/ImageSharp/Common/Helpers/Numerics.cs | 9 +++++++++ .../Formats/Jpeg/JpegDecoderCore.cs | 4 ++-- .../ImageSharp.Tests/Common/NumericsTests.cs | 20 +++++++++++++++++++ 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/Numerics.cs b/src/ImageSharp/Common/Helpers/Numerics.cs index 513db0c44..8f82476e1 100644 --- a/src/ImageSharp/Common/Helpers/Numerics.cs +++ b/src/ImageSharp/Common/Helpers/Numerics.cs @@ -963,5 +963,14 @@ namespace SixLabors.ImageSharp public static uint RotateRightSoftwareFallback(uint value, int offset) => (value >> offset) | (value << (32 - offset)); #endif + + /// + /// Tells whether input value is outside of the given range. + /// + /// Value. + /// Mininum value, inclusive. + /// Maximum value, inclusive. + public static bool IsOutOfRange(int value, int min, int max) + => (uint)(value - min) > (uint)(max - min); } } diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index 4543153de..4b68c39ea 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -1031,13 +1031,13 @@ namespace SixLabors.ImageSharp.Formats.Jpeg int v = hv & 15; // Validate: 1-4 range - if (h is < 1 or > 4) + if (Numerics.IsOutOfRange(h, 1, 4)) { JpegThrowHelper.ThrowBadSampling(h); } // Validate: 1-4 range - if (v is < 1 or > 4) + if (Numerics.IsOutOfRange(v, 1, 4)) { JpegThrowHelper.ThrowBadSampling(v); } diff --git a/tests/ImageSharp.Tests/Common/NumericsTests.cs b/tests/ImageSharp.Tests/Common/NumericsTests.cs index 62819af49..2a43b06a9 100644 --- a/tests/ImageSharp.Tests/Common/NumericsTests.cs +++ b/tests/ImageSharp.Tests/Common/NumericsTests.cs @@ -97,5 +97,25 @@ namespace SixLabors.ImageSharp.Tests.Common Assert.True(expected == actual, $"Expected: {expected}\nActual: {actual}\n{value} / {divisor} = {expected}"); } } + + private static bool IsOutOfRange_ReferenceImplementation(int value, int min, int max) => value < min || value > max; + + [Theory] + [InlineData(1, 100)] + public void IsOutOfRange(int seed, int count) + { + var rng = new Random(seed); + for (int i = 0; i < count; i++) + { + int value = rng.Next(); + int min = rng.Next(); + int max = rng.Next(min, int.MaxValue); + + bool expected = IsOutOfRange_ReferenceImplementation(value, min, max); + bool actual = Numerics.IsOutOfRange(value, min, max); + + Assert.True(expected == actual, $"IsOutOfRange({value}, {min}, {max})"); + } + } } } From d2500953f766281f7df571215f3a49923d49225c Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Sat, 18 Dec 2021 16:56:41 +0300 Subject: [PATCH 082/121] universal format detector --- .../Formats/Tiff/TiffConfigurationModule.cs | 4 +- .../Formats/Tiff/TiffImageFormatDetector.cs | 45 +++++++------------ 2 files changed, 16 insertions(+), 33 deletions(-) diff --git a/src/ImageSharp/Formats/Tiff/TiffConfigurationModule.cs b/src/ImageSharp/Formats/Tiff/TiffConfigurationModule.cs index 656483435..cc97da5bb 100644 --- a/src/ImageSharp/Formats/Tiff/TiffConfigurationModule.cs +++ b/src/ImageSharp/Formats/Tiff/TiffConfigurationModule.cs @@ -13,9 +13,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff { configuration.ImageFormatsManager.SetEncoder(TiffFormat.Instance, new TiffEncoder()); configuration.ImageFormatsManager.SetDecoder(TiffFormat.Instance, new TiffDecoder()); - configuration.ImageFormatsManager.AddImageFormatDetector(new TiffImageFormatDetector(false)); - - configuration.ImageFormatsManager.AddImageFormatDetector(new TiffImageFormatDetector(true)); + configuration.ImageFormatsManager.AddImageFormatDetector(new TiffImageFormatDetector()); } } } diff --git a/src/ImageSharp/Formats/Tiff/TiffImageFormatDetector.cs b/src/ImageSharp/Formats/Tiff/TiffImageFormatDetector.cs index 5755b306a..51280b4bf 100644 --- a/src/ImageSharp/Formats/Tiff/TiffImageFormatDetector.cs +++ b/src/ImageSharp/Formats/Tiff/TiffImageFormatDetector.cs @@ -10,16 +10,8 @@ namespace SixLabors.ImageSharp.Formats.Tiff /// public sealed class TiffImageFormatDetector : IImageFormatDetector { - private readonly bool isBigTiff; - - /// - /// Initializes a new instance of the class. - /// - /// if set to true is BigTiff. - public TiffImageFormatDetector(bool isBigTiff) => this.isBigTiff = isBigTiff; - /// - public int HeaderSize => this.isBigTiff ? 8 : 4; + public int HeaderSize => 8; /// public IImageFormat DetectFormat(ReadOnlySpan header) @@ -39,39 +31,32 @@ namespace SixLabors.ImageSharp.Formats.Tiff if (header[0] == 0x49 && header[1] == 0x49) { // Little-endian - if (this.isBigTiff is false) + if (header[2] == 0x2A && header[3] == 0x00) { - if (header[2] == 0x2A && header[3] == 0x00) - { - return true; - } + // tiff + return true; } - else + else if (header[2] == 0x2B && header[3] == 0x00 + && header[4] == 8 && header[5] == 0 && header[6] == 0 && header[7] == 0) { - if (header[2] == 0x2B && header[3] == 0x00 - && header[4] == 8 && header[5] == 0 && header[6] == 0 && header[7] == 0) - { - return true; - } + // big tiff + return true; } } else if (header[0] == 0x4D && header[1] == 0x4D) { // Big-endian - if (this.isBigTiff is false) + if (header[2] == 0 && header[3] == 0x2A) { - if (header[2] == 0 && header[3] == 0x2A) - { - return true; - } + // tiff + return true; } else + if (header[2] == 0 && header[3] == 0x2B + && header[4] == 0 && header[5] == 8 && header[6] == 0 && header[7] == 0) { - if (header[2] == 0 && header[3] == 0x2B - && header[4] == 0 && header[5] == 8 && header[6] == 0 && header[7] == 0) - { - return true; - } + // big tiff + return true; } } } From 7df7d0dbec9cbfb598d9814a107b865789d1e27c Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Sat, 18 Dec 2021 17:05:43 +0300 Subject: [PATCH 083/121] add TiffFormatType enum --- .../Tiff/TiffDecoderMetadataCreator.cs | 2 +- src/ImageSharp/Formats/Tiff/TiffFormatType.cs | 21 +++++++++++++++++++ src/ImageSharp/Formats/Tiff/TiffMetadata.cs | 7 ++----- .../Formats/Tiff/BigTiffDecoderTests.cs | 5 +++-- 4 files changed, 27 insertions(+), 8 deletions(-) create mode 100644 src/ImageSharp/Formats/Tiff/TiffFormatType.cs diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderMetadataCreator.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderMetadataCreator.cs index ddaf6fa96..4c4023ace 100644 --- a/src/ImageSharp/Formats/Tiff/TiffDecoderMetadataCreator.cs +++ b/src/ImageSharp/Formats/Tiff/TiffDecoderMetadataCreator.cs @@ -57,7 +57,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff TiffMetadata tiffMetadata = imageMetaData.GetTiffMetadata(); tiffMetadata.ByteOrder = byteOrder; - tiffMetadata.IsBigTiff = isBigTiff; + tiffMetadata.FormatType = isBigTiff ? TiffFormatType.BigTIFF : TiffFormatType.Default; return imageMetaData; } diff --git a/src/ImageSharp/Formats/Tiff/TiffFormatType.cs b/src/ImageSharp/Formats/Tiff/TiffFormatType.cs new file mode 100644 index 000000000..320386e4c --- /dev/null +++ b/src/ImageSharp/Formats/Tiff/TiffFormatType.cs @@ -0,0 +1,21 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.Formats.Tiff +{ + /// + /// The TIFF format type enum. + /// + public enum TiffFormatType + { + /// + /// The TIFF file format type. + /// + Default, + + /// + /// The BigTIFF format type. + /// + BigTIFF + } +} diff --git a/src/ImageSharp/Formats/Tiff/TiffMetadata.cs b/src/ImageSharp/Formats/Tiff/TiffMetadata.cs index d537981db..f5124a78a 100644 --- a/src/ImageSharp/Formats/Tiff/TiffMetadata.cs +++ b/src/ImageSharp/Formats/Tiff/TiffMetadata.cs @@ -27,12 +27,9 @@ namespace SixLabors.ImageSharp.Formats.Tiff public ByteOrder ByteOrder { get; set; } /// - /// Gets or sets a value indicating whether this instance is BigTiff format. + /// Gets or sets the format type. /// - /// - /// true if this instance BigTiff format; otherwise, false. - /// - public bool IsBigTiff { get; set; } + public TiffFormatType FormatType { get; set; } /// public IDeepCloneable DeepClone() => new TiffMetadata(this); diff --git a/tests/ImageSharp.Tests/Formats/Tiff/BigTiffDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/BigTiffDecoderTests.cs index 24fce1d0d..7a02c91b8 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/BigTiffDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/BigTiffDecoderTests.cs @@ -5,6 +5,7 @@ using System; using System.IO; using System.Linq; +using SixLabors.ImageSharp.Formats.Tiff; using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.Metadata.Profiles.Exif; using SixLabors.ImageSharp.PixelFormats; @@ -80,9 +81,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff Assert.Equal(expectedVResolution, info.Metadata.VerticalResolution); Assert.Equal(expectedResolutionUnit, info.Metadata.ResolutionUnits); - ImageSharp.Formats.Tiff.TiffMetadata tiffmeta = info.Metadata.GetTiffMetadata(); + TiffMetadata tiffmeta = info.Metadata.GetTiffMetadata(); Assert.NotNull(tiffmeta); - Assert.True(tiffmeta.IsBigTiff); + Assert.Equal(TiffFormatType.BigTIFF, tiffmeta.FormatType); } } From 7ced49747e84744c93b6dca6138257e0d9395a11 Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Sat, 18 Dec 2021 23:41:55 +0300 Subject: [PATCH 084/121] Fixed tests --- .../ImageSharp.Tests/Common/NumericsTests.cs | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/tests/ImageSharp.Tests/Common/NumericsTests.cs b/tests/ImageSharp.Tests/Common/NumericsTests.cs index 2a43b06a9..a82997477 100644 --- a/tests/ImageSharp.Tests/Common/NumericsTests.cs +++ b/tests/ImageSharp.Tests/Common/NumericsTests.cs @@ -16,6 +16,8 @@ namespace SixLabors.ImageSharp.Tests.Common this.Output = output; } + public static TheoryData IsOutOfRangeTestData = new() { int.MinValue, -1, 0, 1, 6, 7, 8, 91, 92, 93, int.MaxValue }; + private static int Log2_ReferenceImplementation(uint value) { int n = 0; @@ -101,21 +103,16 @@ namespace SixLabors.ImageSharp.Tests.Common private static bool IsOutOfRange_ReferenceImplementation(int value, int min, int max) => value < min || value > max; [Theory] - [InlineData(1, 100)] - public void IsOutOfRange(int seed, int count) + [MemberData(nameof(IsOutOfRangeTestData))] + public void IsOutOfRange(int value) { - var rng = new Random(seed); - for (int i = 0; i < count; i++) - { - int value = rng.Next(); - int min = rng.Next(); - int max = rng.Next(min, int.MaxValue); + const int min = 7; + const int max = 92; - bool expected = IsOutOfRange_ReferenceImplementation(value, min, max); - bool actual = Numerics.IsOutOfRange(value, min, max); + bool expected = IsOutOfRange_ReferenceImplementation(value, min, max); + bool actual = Numerics.IsOutOfRange(value, min, max); - Assert.True(expected == actual, $"IsOutOfRange({value}, {min}, {max})"); - } + Assert.True(expected == actual, $"IsOutOfRange({value}, {min}, {max})"); } } } From 8e05f5dba1f9dde0b94f144f30b03a5dc540e531 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Sun, 19 Dec 2021 20:12:01 +0100 Subject: [PATCH 085/121] Add SSE2 version of GetResidualCost --- .../Formats/Webp/Lossy/Vp8Residual.cs | 102 +++++++++++++++--- 1 file changed, 86 insertions(+), 16 deletions(-) diff --git a/src/ImageSharp/Formats/Webp/Lossy/Vp8Residual.cs b/src/ImageSharp/Formats/Webp/Lossy/Vp8Residual.cs index 4eeeedd37..8da176e77 100644 --- a/src/ImageSharp/Formats/Webp/Lossy/Vp8Residual.cs +++ b/src/ImageSharp/Formats/Webp/Lossy/Vp8Residual.cs @@ -3,6 +3,11 @@ using System; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if SUPPORTS_RUNTIME_INTRINSICS +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; +#endif namespace SixLabors.ImageSharp.Formats.Webp.Lossy { @@ -11,6 +16,16 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy /// internal class Vp8Residual { +#if SUPPORTS_RUNTIME_INTRINSICS + private static readonly Vector128 Cst2 = Vector128.Create((byte)2); + + private static readonly Vector128 Cst67 = Vector128.Create((byte)67); +#endif + + private readonly byte[] scratch = new byte[32]; + + private readonly ushort[] scratchUShort = new ushort[16]; + public int First { get; set; } public int Last { get; set; } @@ -129,27 +144,82 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy return LossyUtils.Vp8BitCost(0, (byte)p0); } - int v; - for (; n < this.Last; ++n) +#if SUPPORTS_RUNTIME_INTRINSICS + if (Sse2.IsSupported) { + Span ctxs = this.scratch.AsSpan(0, 16); + Span levels = this.scratch.AsSpan(16, 16); + Span absLevels = this.scratchUShort.AsSpan(); + + // Precompute clamped levels and contexts, packed to 8b. + ref short outputRef = ref MemoryMarshal.GetReference(this.Coeffs); + Vector128 c0 = Unsafe.As>(ref outputRef).AsInt16(); + Vector128 c1 = Unsafe.As>(ref Unsafe.Add(ref outputRef, 8)).AsInt16(); + Vector128 d0 = Sse2.Subtract(Vector128.Zero, c0); + Vector128 d1 = Sse2.Subtract(Vector128.Zero, c1); + Vector128 e0 = Sse2.Max(c0, d0); // abs(v), 16b + Vector128 e1 = Sse2.Max(c1, d1); + Vector128 f = Sse2.PackSignedSaturate(e0, e1); + Vector128 g = Sse2.Min(f.AsByte(), Cst2); + Vector128 h = Sse2.Min(f.AsByte(), Cst67); // clampLevel in [0..67] + + ref byte ctxsRef = ref MemoryMarshal.GetReference(ctxs); + ref byte levelsRef = ref MemoryMarshal.GetReference(levels); + ref ushort absLevelsRef = ref MemoryMarshal.GetReference(absLevels); + Unsafe.As>(ref ctxsRef) = g; + Unsafe.As>(ref levelsRef) = h; + Unsafe.As>(ref absLevelsRef) = e0.AsUInt16(); + Unsafe.As>(ref Unsafe.Add(ref absLevelsRef, 8)) = e1.AsUInt16(); + + int level; + int flevel; + for (; n < this.Last; ++n) + { + int ctx = ctxs[n]; + level = levels[n]; + flevel = absLevels[n]; + cost += WebpLookupTables.Vp8LevelFixedCosts[flevel] + t.Costs[level]; + t = costs[n + 1].Costs[ctx]; + } + + // Last coefficient is always non-zero. + level = levels[n]; + flevel = absLevels[n]; + cost += WebpLookupTables.Vp8LevelFixedCosts[flevel] + t.Costs[level]; + if (n < 15) + { + int b = WebpConstants.Vp8EncBands[n + 1]; + int ctx = ctxs[n]; + int lastP0 = this.Prob[b].Probabilities[ctx].Probabilities[0]; + cost += LossyUtils.Vp8BitCost(0, (byte)lastP0); + } + + return cost; + } +#endif + { + int v; + for (; n < this.Last; ++n) + { + v = Math.Abs(this.Coeffs[n]); + int ctx = v >= 2 ? 2 : v; + cost += LevelCost(t.Costs, v); + t = costs[n + 1].Costs[ctx]; + } + + // Last coefficient is always non-zero v = Math.Abs(this.Coeffs[n]); - int ctx = v >= 2 ? 2 : v; cost += LevelCost(t.Costs, v); - t = costs[n + 1].Costs[ctx]; - } + if (n < 15) + { + int b = WebpConstants.Vp8EncBands[n + 1]; + int ctx = v == 1 ? 1 : 2; + int lastP0 = this.Prob[b].Probabilities[ctx].Probabilities[0]; + cost += LossyUtils.Vp8BitCost(0, (byte)lastP0); + } - // Last coefficient is always non-zero - v = Math.Abs(this.Coeffs[n]); - cost += LevelCost(t.Costs, v); - if (n < 15) - { - int b = WebpConstants.Vp8EncBands[n + 1]; - int ctx = v == 1 ? 1 : 2; - int lastP0 = this.Prob[b].Probabilities[ctx].Probabilities[0]; - cost += LossyUtils.Vp8BitCost(0, (byte)lastP0); + return cost; } - - return cost; } [MethodImpl(InliningOptions.ShortMethod)] From 7eb6b238b30bec1781d96a90959c42cb5151f69a Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Sun, 19 Dec 2021 20:23:52 +0100 Subject: [PATCH 086/121] Add AVX2 version of GetResidualCost --- .../Formats/Webp/Lossy/Vp8Residual.cs | 28 ++++++++----------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/src/ImageSharp/Formats/Webp/Lossy/Vp8Residual.cs b/src/ImageSharp/Formats/Webp/Lossy/Vp8Residual.cs index 8da176e77..0c0f9b02a 100644 --- a/src/ImageSharp/Formats/Webp/Lossy/Vp8Residual.cs +++ b/src/ImageSharp/Formats/Webp/Lossy/Vp8Residual.cs @@ -17,9 +17,9 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy internal class Vp8Residual { #if SUPPORTS_RUNTIME_INTRINSICS - private static readonly Vector128 Cst2 = Vector128.Create((byte)2); + private static readonly Vector256 Cst2 = Vector256.Create((byte)2); - private static readonly Vector128 Cst67 = Vector128.Create((byte)67); + private static readonly Vector256 Cst67 = Vector256.Create((byte)67); #endif private readonly byte[] scratch = new byte[32]; @@ -145,7 +145,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy } #if SUPPORTS_RUNTIME_INTRINSICS - if (Sse2.IsSupported) + if (Avx2.IsSupported) { Span ctxs = this.scratch.AsSpan(0, 16); Span levels = this.scratch.AsSpan(16, 16); @@ -153,23 +153,19 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy // Precompute clamped levels and contexts, packed to 8b. ref short outputRef = ref MemoryMarshal.GetReference(this.Coeffs); - Vector128 c0 = Unsafe.As>(ref outputRef).AsInt16(); - Vector128 c1 = Unsafe.As>(ref Unsafe.Add(ref outputRef, 8)).AsInt16(); - Vector128 d0 = Sse2.Subtract(Vector128.Zero, c0); - Vector128 d1 = Sse2.Subtract(Vector128.Zero, c1); - Vector128 e0 = Sse2.Max(c0, d0); // abs(v), 16b - Vector128 e1 = Sse2.Max(c1, d1); - Vector128 f = Sse2.PackSignedSaturate(e0, e1); - Vector128 g = Sse2.Min(f.AsByte(), Cst2); - Vector128 h = Sse2.Min(f.AsByte(), Cst67); // clampLevel in [0..67] + Vector256 c0 = Unsafe.As>(ref outputRef).AsInt16(); + Vector256 d0 = Avx2.Subtract(Vector256.Zero, c0); + Vector256 e0 = Avx2.Max(c0, d0); // abs(v), 16b + Vector256 f = Avx2.PackSignedSaturate(e0, e0); + Vector256 g = Avx2.Min(f.AsByte(), Cst2); + Vector256 h = Avx2.Min(f.AsByte(), Cst67); // clampLevel in [0..67] ref byte ctxsRef = ref MemoryMarshal.GetReference(ctxs); ref byte levelsRef = ref MemoryMarshal.GetReference(levels); ref ushort absLevelsRef = ref MemoryMarshal.GetReference(absLevels); - Unsafe.As>(ref ctxsRef) = g; - Unsafe.As>(ref levelsRef) = h; - Unsafe.As>(ref absLevelsRef) = e0.AsUInt16(); - Unsafe.As>(ref Unsafe.Add(ref absLevelsRef, 8)) = e1.AsUInt16(); + Unsafe.As>(ref ctxsRef) = g.GetLower(); + Unsafe.As>(ref levelsRef) = h.GetLower(); + Unsafe.As>(ref absLevelsRef) = e0.AsUInt16(); int level; int flevel; From 0740ee7802251f25f352f9a4c0b3d9fa2ac40348 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Sun, 19 Dec 2021 21:07:22 +0100 Subject: [PATCH 087/121] Add SSE2 version of SetCoeffs --- .../Formats/Webp/Lossy/Vp8Residual.cs | 37 ++++++++++++++++--- 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/src/ImageSharp/Formats/Webp/Lossy/Vp8Residual.cs b/src/ImageSharp/Formats/Webp/Lossy/Vp8Residual.cs index 0c0f9b02a..5e4591894 100644 --- a/src/ImageSharp/Formats/Webp/Lossy/Vp8Residual.cs +++ b/src/ImageSharp/Formats/Webp/Lossy/Vp8Residual.cs @@ -52,14 +52,39 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy public void SetCoeffs(Span coeffs) { - int n; - this.Last = -1; - for (n = 15; n >= 0; --n) +#if SUPPORTS_RUNTIME_INTRINSICS + if (Sse2.IsSupported) + { + ref short coeffsRef = ref MemoryMarshal.GetReference(coeffs); + Vector128 c0 = Unsafe.As>(ref coeffsRef); + Vector128 c1 = Unsafe.As>(ref Unsafe.Add(ref coeffsRef, 8)); + + // Use SSE2 to compare 16 values with a single instruction. + Vector128 m0 = Sse2.PackSignedSaturate(c0.AsInt16(), c1.AsInt16()); + Vector128 m1 = Sse2.CompareEqual(m0, Vector128.Zero); + + // Get the comparison results as a bitmask into 16bits. Negate the mask to get + // the position of entries that are not equal to zero. We don't need to mask + // out least significant bits according to res->first, since coeffs[0] is 0 + // if res->first > 0. + uint mask = 0x0000ffffu ^ (uint)Sse2.MoveMask(m1); + + // The position of the most significant non-zero bit indicates the position of + // the last non-zero value. + this.Last = mask != 0 ? Numerics.Log2(mask) : -1; + } + else +#endif { - if (coeffs[n] != 0) + int n; + this.Last = -1; + for (n = 15; n >= 0; --n) { - this.Last = n; - break; + if (coeffs[n] != 0) + { + this.Last = n; + break; + } } } From 8a4b5c6ed5d05a18ca7c10b9f512c29c7b015021 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 19 Dec 2021 21:32:26 +0100 Subject: [PATCH 088/121] moved SwapOrCopyContent responsibility entirely to Buffer2D --- src/ImageSharp/Memory/Buffer2D{T}.cs | 41 +++-- .../MemoryGroup{T}.Owned.cs | 6 + .../DiscontiguousBuffers/MemoryGroup{T}.cs | 27 +-- .../Memory/Buffer2DTests.SwapOrCopyContent.cs | 160 ++++++++++++++++++ .../ImageSharp.Tests/Memory/Buffer2DTests.cs | 53 +----- .../MemoryGroupTests.SwapOrCopyContent.cs | 107 ------------ 6 files changed, 196 insertions(+), 198 deletions(-) create mode 100644 tests/ImageSharp.Tests/Memory/Buffer2DTests.SwapOrCopyContent.cs delete mode 100644 tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTests.SwapOrCopyContent.cs diff --git a/src/ImageSharp/Memory/Buffer2D{T}.cs b/src/ImageSharp/Memory/Buffer2D{T}.cs index ba39a924e..42dce2def 100644 --- a/src/ImageSharp/Memory/Buffer2D{T}.cs +++ b/src/ImageSharp/Memory/Buffer2D{T}.cs @@ -56,7 +56,7 @@ namespace SixLabors.ImageSharp.Memory /// It's public counterpart is , /// which only exposes the view of the MemoryGroup. /// - internal MemoryGroup FastMemoryGroup { get; } + internal MemoryGroup FastMemoryGroup { get; private set; } /// /// Gets a reference to the element at the specified position. @@ -168,25 +168,34 @@ namespace SixLabors.ImageSharp.Memory /// Swaps the contents of 'destination' with 'source' if the buffers are owned (1), /// copies the contents of 'source' to 'destination' otherwise (2). Buffers should be of same size in case 2! /// - internal static void SwapOrCopyContent(Buffer2D destination, Buffer2D source) + internal static bool SwapOrCopyContent(Buffer2D destination, Buffer2D source) { - MemoryGroup.SwapOrCopyContent(destination.FastMemoryGroup, source.FastMemoryGroup); - SwapOwnData(destination, source); + bool swapped = false; + if (MemoryGroup.CanSwapContent(destination.FastMemoryGroup, source.FastMemoryGroup)) + { + (destination.FastMemoryGroup, source.FastMemoryGroup) = + (source.FastMemoryGroup, destination.FastMemoryGroup); + destination.FastMemoryGroup.RecreateViewAfterSwap(); + source.FastMemoryGroup.RecreateViewAfterSwap(); + swapped = true; + } + else + { + if (destination.FastMemoryGroup.TotalLength != source.FastMemoryGroup.TotalLength) + { + throw new InvalidMemoryOperationException( + "Trying to copy/swap incompatible buffers. This is most likely caused by applying an unsupported processor to wrapped-memory images."); + } + + source.FastMemoryGroup.CopyTo(destination.MemoryGroup); + } + + (destination.Width, source.Width) = (source.Width, destination.Width); + (destination.Height, source.Height) = (source.Height, destination.Height); + return swapped; } [MethodImpl(InliningOptions.ShortMethod)] private Memory GetRowMemoryCore(int y) => this.FastMemoryGroup.GetBoundedSlice(y * (long)this.Width, this.Width); - - private static void SwapOwnData(Buffer2D a, Buffer2D b) - { - Size aSize = a.Size(); - Size bSize = b.Size(); - - b.Width = aSize.Width; - b.Height = aSize.Height; - - a.Width = bSize.Width; - a.Height = bSize.Height; - } } } diff --git a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Owned.cs b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Owned.cs index 3b9241383..b578b417f 100644 --- a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Owned.cs +++ b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Owned.cs @@ -122,6 +122,12 @@ namespace SixLabors.ImageSharp.Memory } } + public override void RecreateViewAfterSwap() + { + this.View.Invalidate(); + this.View = new MemoryGroupView(this); + } + /// IEnumerator> IEnumerable>.GetEnumerator() { diff --git a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs index cdd8e6a75..1f18d9169 100644 --- a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs +++ b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs @@ -241,30 +241,11 @@ namespace SixLabors.ImageSharp.Memory return new Owned(source, bufferLength, totalLength, false); } - /// - /// Swaps the contents of 'target' with 'source' if the buffers are allocated (1), - /// copies the contents of 'source' to 'target' otherwise (2). - /// Groups should be of same TotalLength in case 2. - /// - public static bool SwapOrCopyContent(MemoryGroup target, MemoryGroup source) - { - if (source is Owned ownedSrc && ownedSrc.Swappable && - target is Owned ownedTarget && ownedTarget.Swappable) - { - Owned.SwapContents(ownedTarget, ownedSrc); - return true; - } - else - { - if (target.TotalLength != source.TotalLength) - { - throw new InvalidMemoryOperationException( - "Trying to copy/swap incompatible buffers. This is most likely caused by applying an unsupported processor to wrapped-memory images."); - } + public static bool CanSwapContent(MemoryGroup target, MemoryGroup source) => + source is Owned { Swappable: true } && target is Owned { Swappable: true }; - source.CopyTo(target); - return false; - } + public virtual void RecreateViewAfterSwap() + { } public virtual void IncreaseRefCounts() diff --git a/tests/ImageSharp.Tests/Memory/Buffer2DTests.SwapOrCopyContent.cs b/tests/ImageSharp.Tests/Memory/Buffer2DTests.SwapOrCopyContent.cs new file mode 100644 index 000000000..f58136f73 --- /dev/null +++ b/tests/ImageSharp.Tests/Memory/Buffer2DTests.SwapOrCopyContent.cs @@ -0,0 +1,160 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Linq; +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Memory +{ + public partial class Buffer2DTests + { + public class SwapOrCopyContent + { + private readonly TestMemoryAllocator MemoryAllocator = new TestMemoryAllocator(); + + [Fact] + public void SwapOrCopyContent_WhenBothAllocated() + { + using (Buffer2D a = this.MemoryAllocator.Allocate2D(10, 5, AllocationOptions.Clean)) + using (Buffer2D b = this.MemoryAllocator.Allocate2D(3, 7, AllocationOptions.Clean)) + { + a[1, 3] = 666; + b[1, 3] = 444; + + Memory aa = a.FastMemoryGroup.Single(); + Memory bb = b.FastMemoryGroup.Single(); + + Buffer2D.SwapOrCopyContent(a, b); + + Assert.Equal(bb, a.FastMemoryGroup.Single()); + Assert.Equal(aa, b.FastMemoryGroup.Single()); + + Assert.Equal(new Size(3, 7), a.Size()); + Assert.Equal(new Size(10, 5), b.Size()); + + Assert.Equal(666, b[1, 3]); + Assert.Equal(444, a[1, 3]); + } + } + + [Fact] + public void SwapOrCopyContent_WhenDestinationIsOwned_ShouldNotSwapInDisposedSourceBuffer() + { + using var destData = MemoryGroup.Wrap(new int[100]); + using var dest = new Buffer2D(destData, 10, 10); + + using (Buffer2D source = this.MemoryAllocator.Allocate2D(10, 10, AllocationOptions.Clean)) + { + source[0, 0] = 1; + dest[0, 0] = 2; + + Buffer2D.SwapOrCopyContent(dest, source); + } + + int actual1 = dest.DangerousGetRowSpan(0)[0]; + int actual2 = dest.DangerousGetRowSpan(0)[0]; + int actual3 = dest.GetSafeRowMemory(0).Span[0]; + int actual5 = dest[0, 0]; + + Assert.Equal(1, actual1); + Assert.Equal(1, actual2); + Assert.Equal(1, actual3); + Assert.Equal(1, actual5); + } + + [Fact] + public void WhenBothAreMemoryOwners_ShouldSwap() + { + this.MemoryAllocator.BufferCapacityInBytes = sizeof(int) * 50; + using Buffer2D a = this.MemoryAllocator.Allocate2D(48, 2); + using Buffer2D b = this.MemoryAllocator.Allocate2D(50, 2); + + Memory a0 = a.FastMemoryGroup[0]; + Memory a1 = a.FastMemoryGroup[1]; + Memory b0 = b.FastMemoryGroup[0]; + Memory b1 = b.FastMemoryGroup[1]; + + bool swap = Buffer2D.SwapOrCopyContent(a, b); + Assert.True(swap); + + Assert.Equal(b0, a.FastMemoryGroup[0]); + Assert.Equal(b1, a.FastMemoryGroup[1]); + Assert.Equal(a0, b.FastMemoryGroup[0]); + Assert.Equal(a1, b.FastMemoryGroup[1]); + Assert.NotEqual(a.FastMemoryGroup[0], b.FastMemoryGroup[0]); + } + + [Fact] + public void WhenBothAreMemoryOwners_ShouldReplaceViews() + { + using Buffer2D a = this.MemoryAllocator.Allocate2D(100, 1); + using Buffer2D b = this.MemoryAllocator.Allocate2D(100, 2); + + a.FastMemoryGroup[0].Span[42] = 1; + b.FastMemoryGroup[0].Span[33] = 2; + MemoryGroupView aView0 = (MemoryGroupView)a.MemoryGroup; + MemoryGroupView bView0 = (MemoryGroupView)b.MemoryGroup; + + Buffer2D.SwapOrCopyContent(a, b); + Assert.False(aView0.IsValid); + Assert.False(bView0.IsValid); + Assert.ThrowsAny(() => _ = aView0[0].Span); + Assert.ThrowsAny(() => _ = bView0[0].Span); + + Assert.True(a.MemoryGroup.IsValid); + Assert.True(b.MemoryGroup.IsValid); + Assert.Equal(2, a.MemoryGroup[0].Span[33]); + Assert.Equal(1, b.MemoryGroup[0].Span[42]); + } + + [Theory] + [InlineData(false)] + [InlineData(true)] + public void WhenDestIsNotAllocated_SameSize_ShouldCopy(bool sourceIsAllocated) + { + var data = new Rgba32[21]; + var color = new Rgba32(1, 2, 3, 4); + + using var destOwner = new TestMemoryManager(data); + using var dest = new Buffer2D(MemoryGroup.Wrap(destOwner.Memory), 21, 1); + + using Buffer2D source = this.MemoryAllocator.Allocate2D(21, 1); + + source.FastMemoryGroup[0].Span[10] = color; + + // Act: + bool swap = Buffer2D.SwapOrCopyContent(dest, source); + + // Assert: + Assert.False(swap); + Assert.Equal(color, dest.MemoryGroup[0].Span[10]); + Assert.NotEqual(source.FastMemoryGroup[0], dest.FastMemoryGroup[0]); + } + + [Theory] + [InlineData(false)] + [InlineData(true)] + public void WhenDestIsNotMemoryOwner_DifferentSize_Throws(bool sourceIsOwner) + { + var data = new Rgba32[21]; + var color = new Rgba32(1, 2, 3, 4); + + using var destOwner = new TestMemoryManager(data); + using var dest = new Buffer2D(MemoryGroup.Wrap(destOwner.Memory), 21, 1); + + using Buffer2D source = this.MemoryAllocator.Allocate2D(22, 1); + + source.FastMemoryGroup[0].Span[10] = color; + + // Act: + Assert.ThrowsAny(() => Buffer2D.SwapOrCopyContent(dest, source)); + + Assert.Equal(color, source.MemoryGroup[0].Span[10]); + Assert.NotEqual(color, dest.MemoryGroup[0].Span[10]); + } + } + } +} diff --git a/tests/ImageSharp.Tests/Memory/Buffer2DTests.cs b/tests/ImageSharp.Tests/Memory/Buffer2DTests.cs index 73a0f4d60..72b4ccadf 100644 --- a/tests/ImageSharp.Tests/Memory/Buffer2DTests.cs +++ b/tests/ImageSharp.Tests/Memory/Buffer2DTests.cs @@ -4,7 +4,6 @@ using System; using System.Buffers; using System.Diagnostics; -using System.Linq; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using SixLabors.ImageSharp.Memory; @@ -14,7 +13,7 @@ using Xunit; // ReSharper disable InconsistentNaming namespace SixLabors.ImageSharp.Tests.Memory { - public class Buffer2DTests + public partial class Buffer2DTests { // ReSharper disable once ClassNeverInstantiated.Local private class Assert : Xunit.Assert @@ -229,56 +228,6 @@ namespace SixLabors.ImageSharp.Tests.Memory } } - [Fact] - public void SwapOrCopyContent_WhenBothAllocated() - { - using (Buffer2D a = this.MemoryAllocator.Allocate2D(10, 5, AllocationOptions.Clean)) - using (Buffer2D b = this.MemoryAllocator.Allocate2D(3, 7, AllocationOptions.Clean)) - { - a[1, 3] = 666; - b[1, 3] = 444; - - Memory aa = a.FastMemoryGroup.Single(); - Memory bb = b.FastMemoryGroup.Single(); - - Buffer2D.SwapOrCopyContent(a, b); - - Assert.Equal(bb, a.FastMemoryGroup.Single()); - Assert.Equal(aa, b.FastMemoryGroup.Single()); - - Assert.Equal(new Size(3, 7), a.Size()); - Assert.Equal(new Size(10, 5), b.Size()); - - Assert.Equal(666, b[1, 3]); - Assert.Equal(444, a[1, 3]); - } - } - - [Fact] - public void SwapOrCopyContent_WhenDestinationIsOwned_ShouldNotSwapInDisposedSourceBuffer() - { - using var destData = MemoryGroup.Wrap(new int[100]); - using var dest = new Buffer2D(destData, 10, 10); - - using (Buffer2D source = this.MemoryAllocator.Allocate2D(10, 10, AllocationOptions.Clean)) - { - source[0, 0] = 1; - dest[0, 0] = 2; - - Buffer2D.SwapOrCopyContent(dest, source); - } - - int actual1 = dest.DangerousGetRowSpan(0)[0]; - int actual2 = dest.DangerousGetRowSpan(0)[0]; - int actual3 = dest.GetSafeRowMemory(0).Span[0]; - int actual5 = dest[0, 0]; - - Assert.Equal(1, actual1); - Assert.Equal(1, actual2); - Assert.Equal(1, actual3); - Assert.Equal(1, actual5); - } - [Theory] [InlineData(100, 20, 0, 90, 10)] [InlineData(100, 3, 0, 50, 50)] diff --git a/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTests.SwapOrCopyContent.cs b/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTests.SwapOrCopyContent.cs deleted file mode 100644 index 61b9f7a89..000000000 --- a/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTests.SwapOrCopyContent.cs +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Apache License, Version 2.0. - -using System; -using SixLabors.ImageSharp.Memory; -using SixLabors.ImageSharp.PixelFormats; -using Xunit; - -namespace SixLabors.ImageSharp.Tests.Memory.DiscontiguousBuffers -{ - public partial class MemoryGroupTests - { - public class SwapOrCopyContent : MemoryGroupTestsBase - { - [Fact] - public void WhenBothAreMemoryOwners_ShouldSwap() - { - this.MemoryAllocator.BufferCapacityInBytes = sizeof(int) * 50; - using MemoryGroup a = this.MemoryAllocator.AllocateGroup(100, 50); - using MemoryGroup b = this.MemoryAllocator.AllocateGroup(120, 50); - - Memory a0 = a[0]; - Memory a1 = a[1]; - Memory b0 = b[0]; - Memory b1 = b[1]; - - bool swap = MemoryGroup.SwapOrCopyContent(a, b); - - Assert.True(swap); - Assert.Equal(b0, a[0]); - Assert.Equal(b1, a[1]); - Assert.Equal(a0, b[0]); - Assert.Equal(a1, b[1]); - Assert.NotEqual(a[0], b[0]); - } - - [Fact] - public void WhenBothAreMemoryOwners_ShouldReplaceViews() - { - using MemoryGroup a = this.MemoryAllocator.AllocateGroup(100, 100); - using MemoryGroup b = this.MemoryAllocator.AllocateGroup(120, 100); - - a[0].Span[42] = 1; - b[0].Span[33] = 2; - MemoryGroupView aView0 = a.View; - MemoryGroupView bView0 = b.View; - - MemoryGroup.SwapOrCopyContent(a, b); - Assert.False(aView0.IsValid); - Assert.False(bView0.IsValid); - Assert.ThrowsAny(() => _ = aView0[0].Span); - Assert.ThrowsAny(() => _ = bView0[0].Span); - - Assert.True(a.View.IsValid); - Assert.True(b.View.IsValid); - Assert.Equal(2, a.View[0].Span[33]); - Assert.Equal(1, b.View[0].Span[42]); - } - - [Theory] - [InlineData(false)] - [InlineData(true)] - public void WhenDestIsNotAllocated_SameSize_ShouldCopy(bool sourceIsAllocated) - { - var data = new Rgba32[21]; - var color = new Rgba32(1, 2, 3, 4); - - using var destOwner = new TestMemoryManager(data); - using var dest = MemoryGroup.Wrap(destOwner.Memory); - - using MemoryGroup source = this.MemoryAllocator.AllocateGroup(21, 30); - - source[0].Span[10] = color; - - // Act: - bool swap = MemoryGroup.SwapOrCopyContent(dest, source); - - // Assert: - Assert.False(swap); - Assert.Equal(color, dest[0].Span[10]); - Assert.NotEqual(source[0], dest[0]); - } - - [Theory] - [InlineData(false)] - [InlineData(true)] - public void WhenDestIsNotMemoryOwner_DifferentSize_Throws(bool sourceIsOwner) - { - var data = new Rgba32[21]; - var color = new Rgba32(1, 2, 3, 4); - - using var destOwner = new TestMemoryManager(data); - var dest = MemoryGroup.Wrap(destOwner.Memory); - - using MemoryGroup source = this.MemoryAllocator.AllocateGroup(22, 30); - - source[0].Span[10] = color; - - // Act: - Assert.ThrowsAny(() => MemoryGroup.SwapOrCopyContent(dest, source)); - - Assert.Equal(color, source[0].Span[10]); - Assert.NotEqual(color, dest[0].Span[10]); - } - } - } -} From 3f4e05c811fe272439609f765b460d8e2236713e Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 19 Dec 2021 21:57:57 +0100 Subject: [PATCH 089/121] Buffer2D_DangerousGetRowSpan benchmark --- .../General/Buffer2D_DangerousGetRowSpan.cs | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 tests/ImageSharp.Benchmarks/General/Buffer2D_DangerousGetRowSpan.cs diff --git a/tests/ImageSharp.Benchmarks/General/Buffer2D_DangerousGetRowSpan.cs b/tests/ImageSharp.Benchmarks/General/Buffer2D_DangerousGetRowSpan.cs new file mode 100644 index 000000000..84f035583 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/Buffer2D_DangerousGetRowSpan.cs @@ -0,0 +1,42 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +using BenchmarkDotNet.Attributes; +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Benchmarks.General +{ + public class Buffer2D_DangerousGetRowSpan + { + [Params(true, false)] + public bool IsDiscontiguousBuffer { get; set; } + + private Buffer2D buffer; + + [GlobalSetup] + public void Setup() + { + MemoryAllocator allocator = Configuration.Default.MemoryAllocator; + this.buffer = this.IsDiscontiguousBuffer + ? allocator.Allocate2D(4000, 1000) + : allocator.Allocate2D(500, 1000); + } + + [GlobalCleanup] + public void Cleanup() => this.buffer.Dispose(); + + [Benchmark] + public int DangerousGetRowSpan() => + this.buffer.DangerousGetRowSpan(1).Length + + this.buffer.DangerousGetRowSpan(999).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 | IsDiscontiguousBuffer | Mean | Error | StdDev | + // |-------------------- |---------------------- |---------:|---------:|---------:| + // | DangerousGetRowSpan | False | 74.96 ns | 1.505 ns | 1.478 ns | + // | DangerousGetRowSpan | True | 71.49 ns | 1.446 ns | 2.120 ns | + } +} From 0f7f1373fceb388369faa5433e57bbd041c3b06d Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 20 Dec 2021 01:19:31 +0100 Subject: [PATCH 090/121] Speed up DangerousGetRowSpan with SpanCache --- .../Internals/SharedArrayPoolBuffer{T}.cs | 17 +++--- .../Internals/UniformUnmanagedMemoryPool.cs | 10 ++-- .../Internals/UnmanagedBuffer{T}.cs | 2 +- src/ImageSharp/Memory/Buffer2D{T}.cs | 18 ++++--- .../MemoryGroupExtensions.cs | 2 +- .../MemoryGroupSpanCache.cs | 50 +++++++++++++++++ .../MemoryGroup{T}.Owned.cs | 27 +--------- .../DiscontiguousBuffers/MemoryGroup{T}.cs | 50 ++++++++++++++++- .../DiscontiguousBuffers/SpanCacheMode.cs | 13 +++++ .../General/Buffer2D_DangerousGetRowSpan.cs | 18 ++++--- .../ImageSharp.Tests/Memory/Buffer2DTests.cs | 53 ++++++++++++++++++- .../DiscontiguousBuffers/MemoryGroupTests.cs | 4 +- 12 files changed, 203 insertions(+), 61 deletions(-) create mode 100644 src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupSpanCache.cs create mode 100644 src/ImageSharp/Memory/DiscontiguousBuffers/SpanCacheMode.cs diff --git a/src/ImageSharp/Memory/Allocators/Internals/SharedArrayPoolBuffer{T}.cs b/src/ImageSharp/Memory/Allocators/Internals/SharedArrayPoolBuffer{T}.cs index 21673215a..9302c67e7 100644 --- a/src/ImageSharp/Memory/Allocators/Internals/SharedArrayPoolBuffer{T}.cs +++ b/src/ImageSharp/Memory/Allocators/Internals/SharedArrayPoolBuffer{T}.cs @@ -13,34 +13,35 @@ namespace SixLabors.ImageSharp.Memory.Internals where T : struct { private readonly int lengthInBytes; - private byte[] array; private LifetimeGuard lifetimeGuard; public SharedArrayPoolBuffer(int lengthInElements) { this.lengthInBytes = lengthInElements * Unsafe.SizeOf(); - this.array = ArrayPool.Shared.Rent(this.lengthInBytes); - this.lifetimeGuard = new LifetimeGuard(this.array); + this.Array = ArrayPool.Shared.Rent(this.lengthInBytes); + this.lifetimeGuard = new LifetimeGuard(this.Array); } + public byte[] Array { get; private set; } + protected override void Dispose(bool disposing) { - if (this.array == null) + if (this.Array == null) { return; } this.lifetimeGuard.Dispose(); - this.array = null; + this.Array = null; } public override Span GetSpan() { this.CheckDisposed(); - return MemoryMarshal.Cast(this.array.AsSpan(0, this.lengthInBytes)); + return MemoryMarshal.Cast(this.Array.AsSpan(0, this.lengthInBytes)); } - protected override object GetPinnableObject() => this.array; + protected override object GetPinnableObject() => this.Array; public void AddRef() { @@ -53,7 +54,7 @@ namespace SixLabors.ImageSharp.Memory.Internals [Conditional("DEBUG")] private void CheckDisposed() { - if (this.array == null) + if (this.Array == null) { throw new ObjectDisposedException("SharedArrayPoolBuffer"); } diff --git a/src/ImageSharp/Memory/Allocators/Internals/UniformUnmanagedMemoryPool.cs b/src/ImageSharp/Memory/Allocators/Internals/UniformUnmanagedMemoryPool.cs index 6504787a8..584de4464 100644 --- a/src/ImageSharp/Memory/Allocators/Internals/UniformUnmanagedMemoryPool.cs +++ b/src/ImageSharp/Memory/Allocators/Internals/UniformUnmanagedMemoryPool.cs @@ -8,12 +8,10 @@ using System.Threading; namespace SixLabors.ImageSharp.Memory.Internals { - internal partial class UniformUnmanagedMemoryPool -#if !NETSTANDARD1_3 - // In case UniformUnmanagedMemoryPool is finalized, we prefer to run its finalizer after the guard finalizers, - // but we should not rely on this. - : System.Runtime.ConstrainedExecution.CriticalFinalizerObject -#endif + // CriticalFinalizerObject: + // In case UniformUnmanagedMemoryPool is finalized, we prefer to run its finalizer after the guard finalizers, + // but we should not rely on this. + internal partial class UniformUnmanagedMemoryPool : System.Runtime.ConstrainedExecution.CriticalFinalizerObject { private static int minTrimPeriodMilliseconds = int.MaxValue; private static readonly List> AllPools = new(); diff --git a/src/ImageSharp/Memory/Allocators/Internals/UnmanagedBuffer{T}.cs b/src/ImageSharp/Memory/Allocators/Internals/UnmanagedBuffer{T}.cs index 5d0c6dd61..a948bf848 100644 --- a/src/ImageSharp/Memory/Allocators/Internals/UnmanagedBuffer{T}.cs +++ b/src/ImageSharp/Memory/Allocators/Internals/UnmanagedBuffer{T}.cs @@ -31,7 +31,7 @@ namespace SixLabors.ImageSharp.Memory.Internals this.lifetimeGuard = lifetimeGuard; } - private void* Pointer => this.lifetimeGuard.Handle.Pointer; + public void* Pointer => this.lifetimeGuard.Handle.Pointer; public override Span GetSpan() { diff --git a/src/ImageSharp/Memory/Buffer2D{T}.cs b/src/ImageSharp/Memory/Buffer2D{T}.cs index 42dce2def..ea4b8031e 100644 --- a/src/ImageSharp/Memory/Buffer2D{T}.cs +++ b/src/ImageSharp/Memory/Buffer2D{T}.cs @@ -97,10 +97,12 @@ namespace SixLabors.ImageSharp.Memory [MethodImpl(InliningOptions.ShortMethod)] public Span DangerousGetRowSpan(int y) { - DebugGuard.MustBeGreaterThanOrEqualTo(y, 0, nameof(y)); - DebugGuard.MustBeLessThan(y, this.Height, nameof(y)); + if (y < 0 || y >= this.Height) + { + this.ThrowYOutOfRangeException(y); + } - return this.GetRowMemoryCore(y).Span; + return this.FastMemoryGroup.GetRowSpanCoreUnsafe(y, this.Width); } internal bool TryGetPaddedRowSpan(int y, int padding, out Span paddedSpan) @@ -125,7 +127,7 @@ namespace SixLabors.ImageSharp.Memory [MethodImpl(InliningOptions.ShortMethod)] internal ref T GetElementUnsafe(int x, int y) { - Span span = this.GetRowMemoryCore(y).Span; + Span span = this.FastMemoryGroup.GetRowSpanCoreUnsafe(y, this.Width); return ref span[x]; } @@ -139,7 +141,7 @@ namespace SixLabors.ImageSharp.Memory { DebugGuard.MustBeGreaterThanOrEqualTo(y, 0, nameof(y)); DebugGuard.MustBeLessThan(y, this.Height, nameof(y)); - return this.FastMemoryGroup.View.GetBoundedSlice(y * (long)this.Width, this.Width); + return this.FastMemoryGroup.View.GetBoundedMemorySlice(y * (long)this.Width, this.Width); } /// @@ -195,7 +197,9 @@ namespace SixLabors.ImageSharp.Memory return swapped; } - [MethodImpl(InliningOptions.ShortMethod)] - private Memory GetRowMemoryCore(int y) => this.FastMemoryGroup.GetBoundedSlice(y * (long)this.Width, this.Width); + [MethodImpl(InliningOptions.ColdPath)] + private void ThrowYOutOfRangeException(int y) => + throw new ArgumentOutOfRangeException( + $"DangerousGetRowSpan({y}). Y was out of range. Height={this.Height}"); } } diff --git a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupExtensions.cs b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupExtensions.cs index 8e6f38d14..571ffc98d 100644 --- a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupExtensions.cs +++ b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupExtensions.cs @@ -29,7 +29,7 @@ namespace SixLabors.ImageSharp.Memory /// Returns a slice that is expected to be within the bounds of a single buffer. /// Otherwise is thrown. /// - internal static Memory GetBoundedSlice(this IMemoryGroup group, long start, int length) + internal static Memory GetBoundedMemorySlice(this IMemoryGroup group, long start, int length) where T : struct { Guard.NotNull(group, nameof(group)); diff --git a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupSpanCache.cs b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupSpanCache.cs new file mode 100644 index 000000000..fbaf2dcf0 --- /dev/null +++ b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupSpanCache.cs @@ -0,0 +1,50 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +using System.Buffers; +using SixLabors.ImageSharp.Memory.Internals; + +namespace SixLabors.ImageSharp.Memory +{ + internal unsafe struct MemoryGroupSpanCache + { + public SpanCacheMode Mode; + public byte[] SingleArray; + public void* SinglePointer; + public void*[] MultiPointer; + + public static MemoryGroupSpanCache Create(IMemoryOwner[] memoryOwners) + where T : struct + { + IMemoryOwner owner0 = memoryOwners[0]; + MemoryGroupSpanCache memoryGroupSpanCache = default; + if (memoryOwners.Length == 1) + { + if (owner0 is SharedArrayPoolBuffer sharedPoolBuffer) + { + memoryGroupSpanCache.Mode = SpanCacheMode.SingleArray; + memoryGroupSpanCache.SingleArray = sharedPoolBuffer.Array; + } + else if (owner0 is UnmanagedBuffer unmanagedBuffer) + { + memoryGroupSpanCache.Mode = SpanCacheMode.SinglePointer; + memoryGroupSpanCache.SinglePointer = unmanagedBuffer.Pointer; + } + } + else + { + if (owner0 is UnmanagedBuffer) + { + memoryGroupSpanCache.Mode = SpanCacheMode.MultiPointer; + memoryGroupSpanCache.MultiPointer = new void*[memoryOwners.Length]; + for (int i = 0; i < memoryOwners.Length; i++) + { + memoryGroupSpanCache.MultiPointer[i] = ((UnmanagedBuffer)memoryOwners[i]).Pointer; + } + } + } + + return memoryGroupSpanCache; + } + } +} diff --git a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Owned.cs b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Owned.cs index b578b417f..21faf8e56 100644 --- a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Owned.cs +++ b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Owned.cs @@ -26,6 +26,7 @@ namespace SixLabors.ImageSharp.Memory this.memoryOwners = memoryOwners; this.Swappable = swappable; this.View = new MemoryGroupView(this); + this.memoryGroupSpanCache = MemoryGroupSpanCache.Create(memoryOwners); } public Owned( @@ -173,32 +174,6 @@ namespace SixLabors.ImageSharp.Memory [MethodImpl(MethodImplOptions.NoInlining)] private static void ThrowObjectDisposedException() => throw new ObjectDisposedException(nameof(MemoryGroup)); - internal static void SwapContents(Owned a, Owned b) - { - a.EnsureNotDisposed(); - b.EnsureNotDisposed(); - - IMemoryOwner[] tempOwners = a.memoryOwners; - long tempTotalLength = a.TotalLength; - int tempBufferLength = a.BufferLength; - RefCountedLifetimeGuard tempGroupOwner = a.groupLifetimeGuard; - - a.memoryOwners = b.memoryOwners; - a.TotalLength = b.TotalLength; - a.BufferLength = b.BufferLength; - a.groupLifetimeGuard = b.groupLifetimeGuard; - - b.memoryOwners = tempOwners; - b.TotalLength = tempTotalLength; - b.BufferLength = tempBufferLength; - b.groupLifetimeGuard = tempGroupOwner; - - a.View.Invalidate(); - b.View.Invalidate(); - a.View = new MemoryGroupView(a); - b.View = new MemoryGroupView(b); - } - // When the MemoryGroup points to multiple buffers via `groupLifetimeGuard`, // the lifetime of the individual buffers is managed by the guard. // Group buffer IMemoryOwner-s d not manage ownership. diff --git a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs index 1f18d9169..a324f55e4 100644 --- a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs +++ b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs @@ -6,6 +6,8 @@ using System.Buffers; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Threading; using SixLabors.ImageSharp.Memory.Internals; namespace SixLabors.ImageSharp.Memory @@ -21,6 +23,8 @@ namespace SixLabors.ImageSharp.Memory { private static readonly int ElementSize = Unsafe.SizeOf(); + private MemoryGroupSpanCache memoryGroupSpanCache; + private MemoryGroup(int bufferLength, long totalLength) { this.BufferLength = bufferLength; @@ -31,10 +35,10 @@ namespace SixLabors.ImageSharp.Memory public abstract int Count { get; } /// - public int BufferLength { get; private set; } + public int BufferLength { get; } /// - public long TotalLength { get; private set; } + public long TotalLength { get; } /// public bool IsValid { get; private set; } = true; @@ -241,6 +245,40 @@ namespace SixLabors.ImageSharp.Memory return new Owned(source, bufferLength, totalLength, false); } + [MethodImpl(InliningOptions.ShortMethod)] + public unsafe Span GetRowSpanCoreUnsafe(int y, int width) + { + switch (this.memoryGroupSpanCache.Mode) + { + case SpanCacheMode.SingleArray: + { + ref byte b0 = ref MemoryMarshal.GetReference(this.memoryGroupSpanCache.SingleArray); + ref T e0 = ref Unsafe.As(ref b0); + e0 = ref Unsafe.Add(ref e0, y * width); + return MemoryMarshal.CreateSpan(ref e0, width); + } + + case SpanCacheMode.SinglePointer: + { + void* start = Unsafe.Add(this.memoryGroupSpanCache.SinglePointer, y * width); + return new Span(start, width); + } + + case SpanCacheMode.MultiPointer: + { + this.GetMultiBufferPosition(y, width, out int bufferIdx, out int bufferStart); + void* start = Unsafe.Add(this.memoryGroupSpanCache.MultiPointer[bufferIdx], bufferStart); + return new Span(start, width); + } + + default: + { + this.GetMultiBufferPosition(y, width, out int bufferIdx, out int bufferStart); + return this[bufferIdx].Span.Slice(bufferStart, width); + } + } + } + public static bool CanSwapContent(MemoryGroup target, MemoryGroup source) => source is Owned { Swappable: true } && target is Owned { Swappable: true }; @@ -255,5 +293,13 @@ namespace SixLabors.ImageSharp.Memory public virtual void DecreaseRefCounts() { } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void GetMultiBufferPosition(int y, int width, out int bufferIdx, out int bufferStart) + { + long start = y * (long)width; + bufferIdx = (int)(start / this.BufferLength); + bufferStart = (int)(start % this.BufferLength); + } } } diff --git a/src/ImageSharp/Memory/DiscontiguousBuffers/SpanCacheMode.cs b/src/ImageSharp/Memory/DiscontiguousBuffers/SpanCacheMode.cs new file mode 100644 index 000000000..6ab8db0ca --- /dev/null +++ b/src/ImageSharp/Memory/DiscontiguousBuffers/SpanCacheMode.cs @@ -0,0 +1,13 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.Memory +{ + internal enum SpanCacheMode + { + Default = default, + SingleArray, + SinglePointer, + MultiPointer + } +} diff --git a/tests/ImageSharp.Benchmarks/General/Buffer2D_DangerousGetRowSpan.cs b/tests/ImageSharp.Benchmarks/General/Buffer2D_DangerousGetRowSpan.cs index 84f035583..1a130147a 100644 --- a/tests/ImageSharp.Benchmarks/General/Buffer2D_DangerousGetRowSpan.cs +++ b/tests/ImageSharp.Benchmarks/General/Buffer2D_DangerousGetRowSpan.cs @@ -1,6 +1,7 @@ // 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; @@ -9,18 +10,21 @@ namespace SixLabors.ImageSharp.Benchmarks.General { public class Buffer2D_DangerousGetRowSpan { - [Params(true, false)] - public bool IsDiscontiguousBuffer { get; set; } + private const int Height = 1024; + + [Params(0.5, 2.0, 10.0)] + public double SizeMegaBytes { get; set; } private Buffer2D buffer; [GlobalSetup] - public void Setup() + public unsafe void Setup() { + int totalElements = (int)(1024 * 1024 * this.SizeMegaBytes) / sizeof(Rgba32); + + int width = totalElements / Height; MemoryAllocator allocator = Configuration.Default.MemoryAllocator; - this.buffer = this.IsDiscontiguousBuffer - ? allocator.Allocate2D(4000, 1000) - : allocator.Allocate2D(500, 1000); + this.buffer = allocator.Allocate2D(width, Height); } [GlobalCleanup] @@ -29,7 +33,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General [Benchmark] public int DangerousGetRowSpan() => this.buffer.DangerousGetRowSpan(1).Length + - this.buffer.DangerousGetRowSpan(999).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 diff --git a/tests/ImageSharp.Tests/Memory/Buffer2DTests.cs b/tests/ImageSharp.Tests/Memory/Buffer2DTests.cs index 72b4ccadf..0fee2c878 100644 --- a/tests/ImageSharp.Tests/Memory/Buffer2DTests.cs +++ b/tests/ImageSharp.Tests/Memory/Buffer2DTests.cs @@ -120,7 +120,7 @@ namespace SixLabors.ImageSharp.Tests.Memory [InlineData(200, 100, 30, 1, 0)] [InlineData(200, 100, 30, 2, 1)] [InlineData(200, 100, 30, 4, 2)] - public unsafe void GetRowSpanY(int bufferCapacity, int width, int height, int y, int expectedBufferIndex) + public unsafe void DangerousGetRowSpan_TestAllocator(int bufferCapacity, int width, int height, int y, int expectedBufferIndex) { this.MemoryAllocator.BufferCapacityInBytes = sizeof(TestStructs.Foo) * bufferCapacity; @@ -135,6 +135,57 @@ namespace SixLabors.ImageSharp.Tests.Memory } } + [Theory] + [InlineData(100, 5)] // Within shared pool + [InlineData(77, 11)] // Within shared pool + [InlineData(100, 19)] // Single unmanaged pooled buffer + [InlineData(103, 17)] // Single unmanaged pooled buffer + [InlineData(100, 22)] // 2 unmanaged pooled buffers + [InlineData(100, 99)] // 9 unmanaged pooled buffers + [InlineData(100, 120)] // 2 unpooled buffers + public unsafe void DangerousGetRowSpan_UnmanagedAllocator(int width, int height) + { + const int sharedPoolThreshold = 1_000; + const int poolBufferSize = 2_000; + const int maxPoolSize = 10_000; + const int unpooledBufferSize = 8_000; + + int elementSize = sizeof(TestStructs.Foo); + var allocator = new UniformUnmanagedMemoryPoolMemoryAllocator( + sharedPoolThreshold * elementSize, + poolBufferSize * elementSize, + maxPoolSize * elementSize, + unpooledBufferSize * elementSize); + + using Buffer2D buffer = allocator.Allocate2D(width, height); + + var rnd = new Random(42); + + for (int y = 0; y < buffer.Height; y++) + { + Span span = buffer.DangerousGetRowSpan(y); + for (int x = 0; x < span.Length; x++) + { + ref TestStructs.Foo e = ref span[x]; + e.A = rnd.Next(); + e.B = rnd.NextDouble(); + } + } + + // Re-seed + rnd = new Random(42); + for (int y = 0; y < buffer.Height; y++) + { + Span span = buffer.GetSafeRowMemory(y).Span; + for (int x = 0; x < span.Length; x++) + { + ref TestStructs.Foo e = ref span[x]; + Assert.True(rnd.Next() == e.A, $"Mismatch @ y={y} x={x}"); + Assert.True(rnd.NextDouble() == e.B, $"Mismatch @ y={y} x={x}"); + } + } + } + [Theory] [InlineData(10, 0, 0, 0)] [InlineData(10, 0, 2, 0)] diff --git a/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTests.cs b/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTests.cs index 13e47bdee..cb6c34b77 100644 --- a/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTests.cs +++ b/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTests.cs @@ -146,7 +146,7 @@ namespace SixLabors.ImageSharp.Tests.Memory.DiscontiguousBuffers { using MemoryGroup group = this.CreateTestGroup(totalLength, bufferLength, true); - Memory slice = group.GetBoundedSlice(start, length); + Memory slice = group.GetBoundedMemorySlice(start, length); Assert.Equal(length, slice.Length); @@ -172,7 +172,7 @@ namespace SixLabors.ImageSharp.Tests.Memory.DiscontiguousBuffers public void GetBoundedSlice_WhenOverlapsBuffers_Throws(long totalLength, int bufferLength, long start, int length) { using MemoryGroup group = this.CreateTestGroup(totalLength, bufferLength, true); - Assert.ThrowsAny(() => group.GetBoundedSlice(start, length)); + Assert.ThrowsAny(() => group.GetBoundedMemorySlice(start, length)); } [Fact] From 8d651ebc710b7fede6633cb4ebb240fba4972804 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 20 Dec 2021 01:45:15 +0100 Subject: [PATCH 091/121] simplify TryGetPaddedRowSpan() --- .../Decoder/SpectralConverter{TPixel}.cs | 2 +- src/ImageSharp/Memory/Buffer2D{T}.cs | 8 +++--- .../MemoryGroupExtensions.cs | 25 ------------------- .../MemoryGroupSpanCache.cs | 18 +++++++------ .../DiscontiguousBuffers/MemoryGroup{T}.cs | 11 ++++++++ .../ImageSharp.Tests/Memory/Buffer2DTests.cs | 2 +- 6 files changed, 27 insertions(+), 39 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs index 87f11a085..40411ef28 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs @@ -179,7 +179,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder // PackFromRgbPlanes expects the destination to be padded, so try to get padded span containing extra elements from the next row. // If we can't get such a padded row because we are on a MemoryGroup boundary or at the last row, // pack pixels to a temporary, padded proxy buffer, then copy the relevant values to the destination row. - if (this.pixelBuffer.TryGetPaddedRowSpan(yy, 3, out Span destRow)) + if (this.pixelBuffer.DangerousTryGetPaddedRowSpan(yy, 3, out Span destRow)) { PixelOperations.Instance.PackFromRgbPlanes(this.configuration, r, g, b, destRow); } diff --git a/src/ImageSharp/Memory/Buffer2D{T}.cs b/src/ImageSharp/Memory/Buffer2D{T}.cs index ea4b8031e..03d708d75 100644 --- a/src/ImageSharp/Memory/Buffer2D{T}.cs +++ b/src/ImageSharp/Memory/Buffer2D{T}.cs @@ -105,22 +105,22 @@ namespace SixLabors.ImageSharp.Memory return this.FastMemoryGroup.GetRowSpanCoreUnsafe(y, this.Width); } - internal bool TryGetPaddedRowSpan(int y, int padding, out Span paddedSpan) + internal bool DangerousTryGetPaddedRowSpan(int y, int padding, out Span paddedSpan) { DebugGuard.MustBeGreaterThanOrEqualTo(y, 0, nameof(y)); DebugGuard.MustBeLessThan(y, this.Height, nameof(y)); int stride = this.Width + padding; - Memory memory = this.FastMemoryGroup.GetRemainingSliceOfBuffer(y * (long)this.Width); + Span slice = this.FastMemoryGroup.GetRemainingSliceOfBuffer(y * (long)this.Width); - if (memory.Length < stride) + if (slice.Length < stride) { paddedSpan = default; return false; } - paddedSpan = memory.Span.Slice(0, stride); + paddedSpan = slice.Slice(0, stride); return true; } diff --git a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupExtensions.cs b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupExtensions.cs index 571ffc98d..0df1080e5 100644 --- a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupExtensions.cs +++ b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupExtensions.cs @@ -57,31 +57,6 @@ namespace SixLabors.ImageSharp.Memory return memory.Slice(bufferStart, length); } - /// - /// Returns the slice of the buffer starting at global index that goes until the end of the buffer. - /// - internal static Memory GetRemainingSliceOfBuffer(this IMemoryGroup group, long start) - where T : struct - { - Guard.NotNull(group, nameof(group)); - Guard.IsTrue(group.IsValid, nameof(group), "Group must be valid!"); - Guard.MustBeLessThan(start, group.TotalLength, nameof(start)); - - int bufferIdx = (int)(start / group.BufferLength); - - // if (bufferIdx < 0 || bufferIdx >= group.Count) - if ((uint)bufferIdx >= group.Count) - { - throw new ArgumentOutOfRangeException(nameof(start)); - } - - int bufferStart = (int)(start % group.BufferLength); - - Memory memory = group[bufferIdx]; - - return memory.Slice(bufferStart); - } - internal static void CopyTo(this IMemoryGroup source, Span target) where T : struct { diff --git a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupSpanCache.cs b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupSpanCache.cs index fbaf2dcf0..2ec8f97e1 100644 --- a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupSpanCache.cs +++ b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupSpanCache.cs @@ -1,11 +1,16 @@ // 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 { + /// + /// Cached pointer or array data enabling fast from + /// known implementations. + /// internal unsafe struct MemoryGroupSpanCache { public SpanCacheMode Mode; @@ -31,16 +36,13 @@ namespace SixLabors.ImageSharp.Memory memoryGroupSpanCache.SinglePointer = unmanagedBuffer.Pointer; } } - else + else if (owner0 is UnmanagedBuffer) { - if (owner0 is UnmanagedBuffer) + memoryGroupSpanCache.Mode = SpanCacheMode.MultiPointer; + memoryGroupSpanCache.MultiPointer = new void*[memoryOwners.Length]; + for (int i = 0; i < memoryOwners.Length; i++) { - memoryGroupSpanCache.Mode = SpanCacheMode.MultiPointer; - memoryGroupSpanCache.MultiPointer = new void*[memoryOwners.Length]; - for (int i = 0; i < memoryOwners.Length; i++) - { - memoryGroupSpanCache.MultiPointer[i] = ((UnmanagedBuffer)memoryOwners[i]).Pointer; - } + memoryGroupSpanCache.MultiPointer[i] = ((UnmanagedBuffer)memoryOwners[i]).Pointer; } } diff --git a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs index a324f55e4..560f4d4b4 100644 --- a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs +++ b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs @@ -279,6 +279,17 @@ namespace SixLabors.ImageSharp.Memory } } + /// + /// Returns the slice of the buffer starting at global index that goes until the end of the buffer. + /// + public Span GetRemainingSliceOfBuffer(long start) + { + int bufferIdx = (int)(start / this.BufferLength); + int bufferStart = (int)(start % this.BufferLength); + Memory memory = this[bufferIdx]; + return memory.Span.Slice(bufferStart); + } + public static bool CanSwapContent(MemoryGroup target, MemoryGroup source) => source is Owned { Swappable: true } && target is Owned { Swappable: true }; diff --git a/tests/ImageSharp.Tests/Memory/Buffer2DTests.cs b/tests/ImageSharp.Tests/Memory/Buffer2DTests.cs index 0fee2c878..486fbe464 100644 --- a/tests/ImageSharp.Tests/Memory/Buffer2DTests.cs +++ b/tests/ImageSharp.Tests/Memory/Buffer2DTests.cs @@ -203,7 +203,7 @@ namespace SixLabors.ImageSharp.Tests.Memory using Buffer2D buffer = this.MemoryAllocator.Allocate2D(3, 5); bool expectSuccess = expectedBufferIndex >= 0; - bool success = buffer.TryGetPaddedRowSpan(y, padding, out Span paddedSpan); + bool success = buffer.DangerousTryGetPaddedRowSpan(y, padding, out Span paddedSpan); Xunit.Assert.Equal(expectSuccess, success); if (success) { From bce450ce257b8bf00a1c044277c67eee969239a0 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 20 Dec 2021 01:53:09 +0100 Subject: [PATCH 092/121] watch SUPPORTS_CREATESPAN --- src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs index 560f4d4b4..153dd05e5 100644 --- a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs +++ b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs @@ -252,10 +252,15 @@ namespace SixLabors.ImageSharp.Memory { case SpanCacheMode.SingleArray: { +#if SUPPORTS_CREATESPAN ref byte b0 = ref MemoryMarshal.GetReference(this.memoryGroupSpanCache.SingleArray); ref T e0 = ref Unsafe.As(ref b0); e0 = ref Unsafe.Add(ref e0, y * width); return MemoryMarshal.CreateSpan(ref e0, width); +#else + return MemoryMarshal.Cast(this.memoryGroupSpanCache.SingleArray).Slice(y * width, width); +#endif + } case SpanCacheMode.SinglePointer: From d9f4dc607b44946a085211ff7eef9f761b38d17f Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 20 Dec 2021 02:01:31 +0100 Subject: [PATCH 093/121] update benchmark results --- .../General/Buffer2D_DangerousGetRowSpan.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/ImageSharp.Benchmarks/General/Buffer2D_DangerousGetRowSpan.cs b/tests/ImageSharp.Benchmarks/General/Buffer2D_DangerousGetRowSpan.cs index 1a130147a..87fa85250 100644 --- a/tests/ImageSharp.Benchmarks/General/Buffer2D_DangerousGetRowSpan.cs +++ b/tests/ImageSharp.Benchmarks/General/Buffer2D_DangerousGetRowSpan.cs @@ -38,9 +38,10 @@ namespace SixLabors.ImageSharp.Benchmarks.General // 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 | IsDiscontiguousBuffer | Mean | Error | StdDev | - // |-------------------- |---------------------- |---------:|---------:|---------:| - // | DangerousGetRowSpan | False | 74.96 ns | 1.505 ns | 1.478 ns | - // | DangerousGetRowSpan | True | 71.49 ns | 1.446 ns | 2.120 ns | + // | Method | SizeMegaBytes | Mean | Error | StdDev | + // |-------------------- |-------------- |----------:|----------:|----------:| + // | DangerousGetRowSpan | 0.5 | 7.760 ns | 0.0444 ns | 0.0347 ns | + // | DangerousGetRowSpan | 2 | 6.551 ns | 0.0693 ns | 0.0579 ns | + // | DangerousGetRowSpan | 10 | 45.839 ns | 0.9090 ns | 1.0468 ns | } } From ace4fbc229e98f29fb84576b4e8e020f793a8550 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 20 Dec 2021 02:19:13 +0100 Subject: [PATCH 094/121] Numerics.IsOutOfRangeZeroToMax --- src/ImageSharp/Common/Helpers/Numerics.cs | 10 ++++++++++ src/ImageSharp/ImageFrame{TPixel}.cs | 4 ++-- src/ImageSharp/Image{TPixel}.cs | 4 ++-- src/ImageSharp/Memory/Buffer2D{T}.cs | 2 +- 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/Numerics.cs b/src/ImageSharp/Common/Helpers/Numerics.cs index 8f82476e1..f88c54f0d 100644 --- a/src/ImageSharp/Common/Helpers/Numerics.cs +++ b/src/ImageSharp/Common/Helpers/Numerics.cs @@ -970,7 +970,17 @@ namespace SixLabors.ImageSharp /// Value. /// Mininum value, inclusive. /// Maximum value, inclusive. + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsOutOfRange(int value, int min, int max) => (uint)(value - min) > (uint)(max - min); + + /// + /// Tells whether input value is outside of the 0..max range. + /// + /// Value. + /// Maximum value, inclusive. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IsOutOfRangeZeroToMax(int value, int max) + => (uint)value > (uint)max; } } diff --git a/src/ImageSharp/ImageFrame{TPixel}.cs b/src/ImageSharp/ImageFrame{TPixel}.cs index 4753e90e0..fe026b3eb 100644 --- a/src/ImageSharp/ImageFrame{TPixel}.cs +++ b/src/ImageSharp/ImageFrame{TPixel}.cs @@ -443,12 +443,12 @@ namespace SixLabors.ImageSharp [MethodImpl(InliningOptions.ShortMethod)] private void VerifyCoords(int x, int y) { - if (x < 0 || x >= this.Width) + if (Numerics.IsOutOfRangeZeroToMax(x, this.Width)) { ThrowArgumentOutOfRangeException(nameof(x)); } - if (y < 0 || y >= this.Height) + if (Numerics.IsOutOfRangeZeroToMax(y, this.Height)) { ThrowArgumentOutOfRangeException(nameof(y)); } diff --git a/src/ImageSharp/Image{TPixel}.cs b/src/ImageSharp/Image{TPixel}.cs index d01706b01..b25fa0d6a 100644 --- a/src/ImageSharp/Image{TPixel}.cs +++ b/src/ImageSharp/Image{TPixel}.cs @@ -452,12 +452,12 @@ namespace SixLabors.ImageSharp [MethodImpl(InliningOptions.ShortMethod)] private void VerifyCoords(int x, int y) { - if (x < 0 || x >= this.Width) + if (Numerics.IsOutOfRangeZeroToMax(x, this.Width)) { ThrowArgumentOutOfRangeException(nameof(x)); } - if (y < 0 || y >= this.Height) + if (Numerics.IsOutOfRangeZeroToMax(y, this.Height)) { ThrowArgumentOutOfRangeException(nameof(y)); } diff --git a/src/ImageSharp/Memory/Buffer2D{T}.cs b/src/ImageSharp/Memory/Buffer2D{T}.cs index 03d708d75..bc97add5c 100644 --- a/src/ImageSharp/Memory/Buffer2D{T}.cs +++ b/src/ImageSharp/Memory/Buffer2D{T}.cs @@ -97,7 +97,7 @@ namespace SixLabors.ImageSharp.Memory [MethodImpl(InliningOptions.ShortMethod)] public Span DangerousGetRowSpan(int y) { - if (y < 0 || y >= this.Height) + if (Numerics.IsOutOfRangeZeroToMax(y, this.Height)) { this.ThrowYOutOfRangeException(y); } From 4c0dde1b815e2fd86f9d17213a138c69e526346d Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 20 Dec 2021 02:29:23 +0100 Subject: [PATCH 095/121] fix range check --- src/ImageSharp/Common/Helpers/Numerics.cs | 6 +++--- src/ImageSharp/ImageFrame{TPixel}.cs | 4 ++-- src/ImageSharp/Image{TPixel}.cs | 4 ++-- src/ImageSharp/Memory/Buffer2D{T}.cs | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/Numerics.cs b/src/ImageSharp/Common/Helpers/Numerics.cs index f88c54f0d..f271f6e5d 100644 --- a/src/ImageSharp/Common/Helpers/Numerics.cs +++ b/src/ImageSharp/Common/Helpers/Numerics.cs @@ -978,9 +978,9 @@ namespace SixLabors.ImageSharp /// Tells whether input value is outside of the 0..max range. /// /// Value. - /// Maximum value, inclusive. + /// Maximum value, exclusive. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool IsOutOfRangeZeroToMax(int value, int max) - => (uint)value > (uint)max; + public static bool IsOutOfRangeZeroToExclusiveMax(int value, int max) + => (uint)value >= (uint)max; } } diff --git a/src/ImageSharp/ImageFrame{TPixel}.cs b/src/ImageSharp/ImageFrame{TPixel}.cs index fe026b3eb..b43cf7a82 100644 --- a/src/ImageSharp/ImageFrame{TPixel}.cs +++ b/src/ImageSharp/ImageFrame{TPixel}.cs @@ -443,12 +443,12 @@ namespace SixLabors.ImageSharp [MethodImpl(InliningOptions.ShortMethod)] private void VerifyCoords(int x, int y) { - if (Numerics.IsOutOfRangeZeroToMax(x, this.Width)) + if (Numerics.IsOutOfRangeZeroToExclusiveMax(x, this.Width)) { ThrowArgumentOutOfRangeException(nameof(x)); } - if (Numerics.IsOutOfRangeZeroToMax(y, this.Height)) + if (Numerics.IsOutOfRangeZeroToExclusiveMax(y, this.Height)) { ThrowArgumentOutOfRangeException(nameof(y)); } diff --git a/src/ImageSharp/Image{TPixel}.cs b/src/ImageSharp/Image{TPixel}.cs index b25fa0d6a..e1016aa97 100644 --- a/src/ImageSharp/Image{TPixel}.cs +++ b/src/ImageSharp/Image{TPixel}.cs @@ -452,12 +452,12 @@ namespace SixLabors.ImageSharp [MethodImpl(InliningOptions.ShortMethod)] private void VerifyCoords(int x, int y) { - if (Numerics.IsOutOfRangeZeroToMax(x, this.Width)) + if (Numerics.IsOutOfRangeZeroToExclusiveMax(x, this.Width)) { ThrowArgumentOutOfRangeException(nameof(x)); } - if (Numerics.IsOutOfRangeZeroToMax(y, this.Height)) + if (Numerics.IsOutOfRangeZeroToExclusiveMax(y, this.Height)) { ThrowArgumentOutOfRangeException(nameof(y)); } diff --git a/src/ImageSharp/Memory/Buffer2D{T}.cs b/src/ImageSharp/Memory/Buffer2D{T}.cs index bc97add5c..0d9d444e0 100644 --- a/src/ImageSharp/Memory/Buffer2D{T}.cs +++ b/src/ImageSharp/Memory/Buffer2D{T}.cs @@ -97,7 +97,7 @@ namespace SixLabors.ImageSharp.Memory [MethodImpl(InliningOptions.ShortMethod)] public Span DangerousGetRowSpan(int y) { - if (Numerics.IsOutOfRangeZeroToMax(y, this.Height)) + if (Numerics.IsOutOfRangeZeroToExclusiveMax(y, this.Height)) { this.ThrowYOutOfRangeException(y); } From b0a45f6c08f830273a65ea5a0609c82dafe5c4c0 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 20 Dec 2021 02:44:03 +0100 Subject: [PATCH 096/121] inline IsOutOfRangeZeroToExclusiveMax --- src/ImageSharp/Common/Helpers/Numerics.cs | 9 --------- src/ImageSharp/ImageFrame{TPixel}.cs | 4 ++-- src/ImageSharp/Image{TPixel}.cs | 4 ++-- src/ImageSharp/Memory/Buffer2D{T}.cs | 2 +- 4 files changed, 5 insertions(+), 14 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/Numerics.cs b/src/ImageSharp/Common/Helpers/Numerics.cs index f271f6e5d..7de838bc9 100644 --- a/src/ImageSharp/Common/Helpers/Numerics.cs +++ b/src/ImageSharp/Common/Helpers/Numerics.cs @@ -973,14 +973,5 @@ namespace SixLabors.ImageSharp [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsOutOfRange(int value, int min, int max) => (uint)(value - min) > (uint)(max - min); - - /// - /// Tells whether input value is outside of the 0..max range. - /// - /// Value. - /// Maximum value, exclusive. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool IsOutOfRangeZeroToExclusiveMax(int value, int max) - => (uint)value >= (uint)max; } } diff --git a/src/ImageSharp/ImageFrame{TPixel}.cs b/src/ImageSharp/ImageFrame{TPixel}.cs index b43cf7a82..cc1b01ff7 100644 --- a/src/ImageSharp/ImageFrame{TPixel}.cs +++ b/src/ImageSharp/ImageFrame{TPixel}.cs @@ -443,12 +443,12 @@ namespace SixLabors.ImageSharp [MethodImpl(InliningOptions.ShortMethod)] private void VerifyCoords(int x, int y) { - if (Numerics.IsOutOfRangeZeroToExclusiveMax(x, this.Width)) + if ((uint)x >= (uint)this.Width) { ThrowArgumentOutOfRangeException(nameof(x)); } - if (Numerics.IsOutOfRangeZeroToExclusiveMax(y, this.Height)) + if ((uint)y >= (uint)this.Height) { ThrowArgumentOutOfRangeException(nameof(y)); } diff --git a/src/ImageSharp/Image{TPixel}.cs b/src/ImageSharp/Image{TPixel}.cs index e1016aa97..403a0f7ea 100644 --- a/src/ImageSharp/Image{TPixel}.cs +++ b/src/ImageSharp/Image{TPixel}.cs @@ -452,12 +452,12 @@ namespace SixLabors.ImageSharp [MethodImpl(InliningOptions.ShortMethod)] private void VerifyCoords(int x, int y) { - if (Numerics.IsOutOfRangeZeroToExclusiveMax(x, this.Width)) + if ((uint)x >= (uint)this.Width) { ThrowArgumentOutOfRangeException(nameof(x)); } - if (Numerics.IsOutOfRangeZeroToExclusiveMax(y, this.Height)) + if ((uint)y >= (uint)this.Height) { ThrowArgumentOutOfRangeException(nameof(y)); } diff --git a/src/ImageSharp/Memory/Buffer2D{T}.cs b/src/ImageSharp/Memory/Buffer2D{T}.cs index 0d9d444e0..7ffaae312 100644 --- a/src/ImageSharp/Memory/Buffer2D{T}.cs +++ b/src/ImageSharp/Memory/Buffer2D{T}.cs @@ -97,7 +97,7 @@ namespace SixLabors.ImageSharp.Memory [MethodImpl(InliningOptions.ShortMethod)] public Span DangerousGetRowSpan(int y) { - if (Numerics.IsOutOfRangeZeroToExclusiveMax(y, this.Height)) + if ((uint)y >= (uint)this.Height) { this.ThrowYOutOfRangeException(y); } From 4694be382aff9100b210945c5effdf090743d4d3 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Mon, 20 Dec 2021 14:33:25 +0100 Subject: [PATCH 097/121] Add Vp8Residual tests --- .../Formats/WebP/Vp8ResidualTests.cs | 37 +++++++++++++++++++ .../Formats/WebP/WebpEncoderTests.cs | 20 ++++++++++ 2 files changed, 57 insertions(+) create mode 100644 tests/ImageSharp.Tests/Formats/WebP/Vp8ResidualTests.cs diff --git a/tests/ImageSharp.Tests/Formats/WebP/Vp8ResidualTests.cs b/tests/ImageSharp.Tests/Formats/WebP/Vp8ResidualTests.cs new file mode 100644 index 000000000..2bca632db --- /dev/null +++ b/tests/ImageSharp.Tests/Formats/WebP/Vp8ResidualTests.cs @@ -0,0 +1,37 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.Formats.Webp.Lossy; +using SixLabors.ImageSharp.Tests.TestUtilities; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Formats.WebP +{ + [Trait("Format", "Webp")] + public class Vp8ResidualTests + { + private static void RunSetCoeffsTest() + { + // arrange + var residual = new Vp8Residual(); + short[] coeffs = { 110, 0, -2, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0 }; + + // act + residual.SetCoeffs(coeffs); + + // assert + Assert.Equal(9, residual.Last); + } + + [Fact] + public void RunSetCoeffsTest_Works() => RunSetCoeffsTest(); + +#if SUPPORTS_RUNTIME_INTRINSICS + [Fact] + public void RunSetCoeffsTest_WithHardwareIntrinsics_Works() => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunSetCoeffsTest, HwIntrinsics.AllowAll); + + [Fact] + public void RunSetCoeffsTest_WithoutHardwareIntrinsics_Works() => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunSetCoeffsTest, HwIntrinsics.DisableHWIntrinsic); +#endif + } +} diff --git a/tests/ImageSharp.Tests/Formats/WebP/WebpEncoderTests.cs b/tests/ImageSharp.Tests/Formats/WebP/WebpEncoderTests.cs index 607d4c764..cad39224e 100644 --- a/tests/ImageSharp.Tests/Formats/WebP/WebpEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/WebP/WebpEncoderTests.cs @@ -5,6 +5,7 @@ using System.IO; using SixLabors.ImageSharp.Formats.Webp; using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Tests.TestUtilities; using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; using Xunit; using static SixLabors.ImageSharp.Tests.TestImages.Webp; @@ -14,6 +15,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Webp [Trait("Format", "Webp")] public class WebpEncoderTests { + private static string TestImageLossyFullPath => Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, Lossy.NoFilter06); + [Theory] [WithFile(Flag, PixelTypes.Rgba32, WebpFileFormatType.Lossless)] // if its not a webp input image, it should default to lossless. [WithFile(Lossless.NoTransform1, PixelTypes.Rgba32, WebpFileFormatType.Lossless)] @@ -288,6 +291,23 @@ namespace SixLabors.ImageSharp.Tests.Formats.Webp image.VerifyEncoder(provider, "webp", string.Empty, encoder, ImageComparer.Tolerant(0.04f)); } + public static void RunEncodeLossy_WithPeakImage() + { + var provider = TestImageProvider.File(TestImageLossyFullPath); + using Image image = provider.GetImage(); + + var encoder = new WebpEncoder() { FileFormat = WebpFileFormatType.Lossy }; + image.VerifyEncoder(provider, "webp", string.Empty, encoder, ImageComparer.Tolerant(0.04f)); + } + +#if SUPPORTS_RUNTIME_INTRINSICS + [Fact] + public void RunEncodeLossy_WithPeakImage_WithHardwareIntrinsics_Works() => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunEncodeLossy_WithPeakImage, HwIntrinsics.AllowAll); + + [Fact] + public void RunEncodeLossy_WithPeakImage_WithoutHardwareIntrinsics_Works() => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunEncodeLossy_WithPeakImage, HwIntrinsics.DisableHWIntrinsic); +#endif + private static ImageComparer GetComparer(int quality) { float tolerance = 0.01f; // ~1.0% From a1e932feaaa98ed1d5462aa9a1424f9b30179f85 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 20 Dec 2021 14:51:14 +0100 Subject: [PATCH 098/121] docs --- .../Memory/DiscontiguousBuffers/MemoryGroupSpanCache.cs | 2 +- src/ImageSharp/Memory/DiscontiguousBuffers/SpanCacheMode.cs | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupSpanCache.cs b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupSpanCache.cs index 2ec8f97e1..f2e02bcfe 100644 --- a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupSpanCache.cs +++ b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupSpanCache.cs @@ -8,7 +8,7 @@ using SixLabors.ImageSharp.Memory.Internals; namespace SixLabors.ImageSharp.Memory { /// - /// Cached pointer or array data enabling fast from + /// Cached pointer or array data enabling fast access from /// known implementations. /// internal unsafe struct MemoryGroupSpanCache diff --git a/src/ImageSharp/Memory/DiscontiguousBuffers/SpanCacheMode.cs b/src/ImageSharp/Memory/DiscontiguousBuffers/SpanCacheMode.cs index 6ab8db0ca..8bd32efa9 100644 --- a/src/ImageSharp/Memory/DiscontiguousBuffers/SpanCacheMode.cs +++ b/src/ImageSharp/Memory/DiscontiguousBuffers/SpanCacheMode.cs @@ -3,6 +3,9 @@ namespace SixLabors.ImageSharp.Memory { + /// + /// Selects active values in . + /// internal enum SpanCacheMode { Default = default, From 52f2ce7c17d710a4ef5d45bc3331f8ca3a3a9031 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 20 Dec 2021 17:11:27 +0100 Subject: [PATCH 099/121] use Math.DivRem --- .../DiscontiguousBuffers/MemoryGroupExtensions.cs | 4 ++-- .../Memory/DiscontiguousBuffers/MemoryGroup{T}.cs | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupExtensions.cs b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupExtensions.cs index 0df1080e5..d200b223a 100644 --- a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupExtensions.cs +++ b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupExtensions.cs @@ -37,7 +37,8 @@ namespace SixLabors.ImageSharp.Memory Guard.MustBeGreaterThanOrEqualTo(length, 0, nameof(length)); Guard.MustBeLessThan(start, group.TotalLength, nameof(start)); - int bufferIdx = (int)(start / group.BufferLength); + int bufferIdx = (int)Math.DivRem(start, group.BufferLength, out long bufferStartLong); + int bufferStart = (int)bufferStartLong; // if (bufferIdx < 0 || bufferIdx >= group.Count) if ((uint)bufferIdx >= group.Count) @@ -45,7 +46,6 @@ namespace SixLabors.ImageSharp.Memory throw new ArgumentOutOfRangeException(nameof(start)); } - int bufferStart = (int)(start % group.BufferLength); int bufferEnd = bufferStart + length; Memory memory = group[bufferIdx]; diff --git a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs index 153dd05e5..9844f4a3b 100644 --- a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs +++ b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs @@ -289,10 +289,9 @@ namespace SixLabors.ImageSharp.Memory /// public Span GetRemainingSliceOfBuffer(long start) { - int bufferIdx = (int)(start / this.BufferLength); - int bufferStart = (int)(start % this.BufferLength); - Memory memory = this[bufferIdx]; - return memory.Span.Slice(bufferStart); + long bufferIdx = Math.DivRem(start, this.BufferLength, out long bufferStart); + Memory memory = this[(int)bufferIdx]; + return memory.Span.Slice((int)bufferStart); } public static bool CanSwapContent(MemoryGroup target, MemoryGroup source) => @@ -314,8 +313,9 @@ namespace SixLabors.ImageSharp.Memory private void GetMultiBufferPosition(int y, int width, out int bufferIdx, out int bufferStart) { long start = y * (long)width; - bufferIdx = (int)(start / this.BufferLength); - bufferStart = (int)(start % this.BufferLength); + long bufferIdxLong = Math.DivRem(start, this.BufferLength, out long bufferStartLong); + bufferIdx = (int)bufferIdxLong; + bufferStart = (int)bufferStartLong; } } } From 0d3bd576428e073108b5a19a4bdf81f1b123a741 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 20 Dec 2021 17:14:28 +0100 Subject: [PATCH 100/121] update benchmark results --- .../General/Buffer2D_DangerousGetRowSpan.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/tests/ImageSharp.Benchmarks/General/Buffer2D_DangerousGetRowSpan.cs b/tests/ImageSharp.Benchmarks/General/Buffer2D_DangerousGetRowSpan.cs index 87fa85250..01d06bf75 100644 --- a/tests/ImageSharp.Benchmarks/General/Buffer2D_DangerousGetRowSpan.cs +++ b/tests/ImageSharp.Benchmarks/General/Buffer2D_DangerousGetRowSpan.cs @@ -12,8 +12,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General { private const int Height = 1024; - [Params(0.5, 2.0, 10.0)] - public double SizeMegaBytes { get; set; } + [Params(0.5, 2.0, 10.0)] public double SizeMegaBytes { get; set; } private Buffer2D buffer; @@ -40,8 +39,8 @@ namespace SixLabors.ImageSharp.Benchmarks.General // // | Method | SizeMegaBytes | Mean | Error | StdDev | // |-------------------- |-------------- |----------:|----------:|----------:| - // | DangerousGetRowSpan | 0.5 | 7.760 ns | 0.0444 ns | 0.0347 ns | - // | DangerousGetRowSpan | 2 | 6.551 ns | 0.0693 ns | 0.0579 ns | - // | DangerousGetRowSpan | 10 | 45.839 ns | 0.9090 ns | 1.0468 ns | + // | 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 | } } From 981ff69831d0f34f61c47456789f0ee3520aa338 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 22 Dec 2021 00:12:45 +1100 Subject: [PATCH 101/121] Update ImageFrame{TPixel}.cs --- src/ImageSharp/ImageFrame{TPixel}.cs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/ImageSharp/ImageFrame{TPixel}.cs b/src/ImageSharp/ImageFrame{TPixel}.cs index cc1b01ff7..fe037003e 100644 --- a/src/ImageSharp/ImageFrame{TPixel}.cs +++ b/src/ImageSharp/ImageFrame{TPixel}.cs @@ -145,13 +145,8 @@ namespace SixLabors.ImageSharp source.PixelBuffer.FastMemoryGroup.CopyTo(this.PixelBuffer.FastMemoryGroup); } - /// - /// Gets the image pixels. Not private as Buffer2D requires an array in its constructor. - /// - internal Buffer2D PixelBuffer { get; private set; } - /// - Buffer2D IPixelSource.PixelBuffer => this.PixelBuffer; + public Buffer2D PixelBuffer { get; private set; } /// /// Gets or sets the pixel at the specified position. From c57bf82c4446cf99d688f2b23de563379ffccaeb Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 22 Dec 2021 01:24:36 +1100 Subject: [PATCH 102/121] Don't throw when Position is out of range. Fix #1903 --- src/ImageSharp/IO/ChunkedMemoryStream.cs | 1 - tests/Directory.Build.targets | 1 + .../Image/ImageTests.Identify.cs | 53 +++++++++++++++++++ .../ImageSharp.Tests/ImageSharp.Tests.csproj | 1 + 4 files changed, 55 insertions(+), 1 deletion(-) diff --git a/src/ImageSharp/IO/ChunkedMemoryStream.cs b/src/ImageSharp/IO/ChunkedMemoryStream.cs index e28baf879..e39930def 100644 --- a/src/ImageSharp/IO/ChunkedMemoryStream.cs +++ b/src/ImageSharp/IO/ChunkedMemoryStream.cs @@ -168,7 +168,6 @@ namespace SixLabors.ImageSharp.IO // Position is out of range this.readChunk = backupReadChunk; this.readOffset = backupReadOffset; - ThrowArgumentOutOfRange(nameof(value)); } } } diff --git a/tests/Directory.Build.targets b/tests/Directory.Build.targets index ddceaff1f..525860189 100644 --- a/tests/Directory.Build.targets +++ b/tests/Directory.Build.targets @@ -33,6 +33,7 @@ + diff --git a/tests/ImageSharp.Tests/Image/ImageTests.Identify.cs b/tests/ImageSharp.Tests/Image/ImageTests.Identify.cs index 271aa30cf..93f73c3d3 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.Identify.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.Identify.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System.IO; +using System.IO.Compression; using System.Threading.Tasks; using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Tests.TestUtilities; @@ -138,6 +139,32 @@ namespace SixLabors.ImageSharp.Tests Assert.Null(type); } + [Fact] + public void FromStream_ZeroLength_ReturnsNull() + { + // https://github.com/SixLabors/ImageSharp/issues/1903 + using var zipFile = new ZipArchive(new MemoryStream( + new byte[] + { + 0x50, 0x4B, 0x03, 0x04, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0xAF, + 0x94, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x6D, 0x79, 0x73, 0x74, 0x65, 0x72, + 0x79, 0x50, 0x4B, 0x01, 0x02, 0x3F, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x77, 0xAF, 0x94, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6D, + 0x79, 0x73, 0x74, 0x65, 0x72, 0x79, 0x0A, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x18, 0x00, 0x46, 0x82, 0xFF, 0x91, 0x27, 0xF6, + 0xD7, 0x01, 0x55, 0xA1, 0xF9, 0x91, 0x27, 0xF6, 0xD7, 0x01, 0x55, 0xA1, + 0xF9, 0x91, 0x27, 0xF6, 0xD7, 0x01, 0x50, 0x4B, 0x05, 0x06, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x59, 0x00, 0x00, 0x00, 0x25, 0x00, + 0x00, 0x00, 0x00, 0x00 + })); + using Stream stream = zipFile.Entries[0].Open(); + IImageInfo info = Image.Identify(stream); + Assert.Null(info); + } + [Fact] public async Task FromStreamAsync_GlobalConfiguration_NoFormat() { @@ -188,6 +215,32 @@ namespace SixLabors.ImageSharp.Tests Assert.Equal(ExpectedGlobalFormat, res.Format); } + [Fact] + public async Task FromStreamAsync_ZeroLength_ReturnsNull() + { + // https://github.com/SixLabors/ImageSharp/issues/1903 + using var zipFile = new ZipArchive(new MemoryStream( + new byte[] + { + 0x50, 0x4B, 0x03, 0x04, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0xAF, + 0x94, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x6D, 0x79, 0x73, 0x74, 0x65, 0x72, + 0x79, 0x50, 0x4B, 0x01, 0x02, 0x3F, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x77, 0xAF, 0x94, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6D, + 0x79, 0x73, 0x74, 0x65, 0x72, 0x79, 0x0A, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x18, 0x00, 0x46, 0x82, 0xFF, 0x91, 0x27, 0xF6, + 0xD7, 0x01, 0x55, 0xA1, 0xF9, 0x91, 0x27, 0xF6, 0xD7, 0x01, 0x55, 0xA1, + 0xF9, 0x91, 0x27, 0xF6, 0xD7, 0x01, 0x50, 0x4B, 0x05, 0x06, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x59, 0x00, 0x00, 0x00, 0x25, 0x00, + 0x00, 0x00, 0x00, 0x00 + })); + using Stream stream = zipFile.Entries[0].Open(); + IImageInfo info = await Image.IdentifyAsync(stream); + Assert.Null(info); + } + [Fact] public async Task FromPathAsync_CustomConfiguration() { diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj index 471287006..28c778787 100644 --- a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj +++ b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj @@ -47,6 +47,7 @@ + From 2a7ec5dc66de7387c08f93d678d8e4e84b5b7eed Mon Sep 17 00:00:00 2001 From: "WINDEV2110EVAL\\User" Date: Tue, 28 Dec 2021 03:29:31 -0800 Subject: [PATCH 103/121] Moved ExifHeader to a local variable since it's only used in one function anyway. --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 26 +++++++++----------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 721a05240..cb1fc3e45 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -124,12 +124,6 @@ namespace SixLabors.ImageSharp.Formats.Png this.ignoreMetadata = options.IgnoreMetadata; } - /// - /// Gets the sequence of bytes for the exif header ("Exif" ASCII and two zero bytes). Used for the legacy exif parsing. - /// - // This uses C# compiler's optimization to refer to the static data directly, no intermediate array allocations happen. - private static ReadOnlySpan ExifHeader => new byte[] { 0x45, 0x78, 0x69, 0x66, 0x00, 0x00 }; - /// public Configuration Configuration { get; } @@ -1015,35 +1009,39 @@ namespace SixLabors.ImageSharp.Formats.Png // Skip to the hex-encoded data dataSpan = dataSpan.Slice(dataLengthEnd).Trim(); - if (dataLength < ExifHeader.Length) + // Sequence of bytes for the exif header ("Exif" ASCII and two zero bytes). + // This doesn't actually allocate. + ReadOnlySpan exifHeader = new byte[] { 0x45, 0x78, 0x69, 0x66, 0x00, 0x00 }; + + if (dataLength < exifHeader.Length) { // Not enough room for the required exif header, this data couldn't possibly be valid return false; } // Parse the hex-encoded data into the byte array we are going to hand off to ExifProfile - byte[] exifBlob = new byte[dataLength - ExifHeader.Length]; + byte[] exifBlob = new byte[dataLength - exifHeader.Length]; try { // Check for the presence of the exif header in the hex-encoded binary data byte[] tempExifBuf = exifBlob; - if (exifBlob.Length < ExifHeader.Length) + if (exifBlob.Length < exifHeader.Length) { // Need to allocate a temporary array, this should be an extremely uncommon (TODO: impossible?) case - tempExifBuf = new byte[ExifHeader.Length]; + tempExifBuf = new byte[exifHeader.Length]; } - HexStringToBytes(dataSpan.Slice(0, ExifHeader.Length * 2), tempExifBuf.AsSpan()); - if (!tempExifBuf.AsSpan().Slice(0, ExifHeader.Length).SequenceEqual(ExifHeader)) + HexStringToBytes(dataSpan.Slice(0, exifHeader.Length * 2), tempExifBuf.AsSpan()); + if (!tempExifBuf.AsSpan().Slice(0, exifHeader.Length).SequenceEqual(exifHeader)) { // Exif header in the hex data is not valid return false; } // Skip over the exif header we just tested - dataSpan = dataSpan.Slice(ExifHeader.Length * 2); - dataLength -= ExifHeader.Length; + dataSpan = dataSpan.Slice(exifHeader.Length * 2); + dataLength -= exifHeader.Length; // Load the hex-encoded data, one line at a time for (int i = 0; i < dataLength;) From 82e664aad3a21dac75f07a55df6c95eeed3e3b23 Mon Sep 17 00:00:00 2001 From: "WINDEV2110EVAL\\User" Date: Tue, 28 Dec 2021 04:01:03 -0800 Subject: [PATCH 104/121] New, faster HexStringToBytes implementation based off the reference source implementation of Convert.FromHexString(): https://source.dot.net/#System.Private.CoreLib/Convert.cs,c9e4fbeaca708991 --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 95 ++++++++++++++------ 1 file changed, 67 insertions(+), 28 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index cb1fc3e45..ef133dece 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -1032,7 +1032,7 @@ namespace SixLabors.ImageSharp.Formats.Png tempExifBuf = new byte[exifHeader.Length]; } - HexStringToBytes(dataSpan.Slice(0, exifHeader.Length * 2), tempExifBuf.AsSpan()); + HexStringToBytes(dataSpan.Slice(0, exifHeader.Length * 2), tempExifBuf); if (!tempExifBuf.AsSpan().Slice(0, exifHeader.Length).SequenceEqual(exifHeader)) { // Exif header in the hex data is not valid @@ -1103,51 +1103,90 @@ namespace SixLabors.ImageSharp.Formats.Png } /// - /// Parses a hexadecimal string into a byte array without allocations. - /// Adapted from https://stackoverflow.com/a/9995303/871842 + /// 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. /// - /// The hexadecimal string to parse. - /// The destination for the parsed bytes. Must be at least .Length / 2 bytes long. - /// The number of bytes written to . - private static int HexStringToBytes(ReadOnlySpan hexString, Span outputBytes) + /// The hexadecimal string to parse. + /// The destination for the parsed bytes. Must be at least .Length / 2 bytes long. + /// The number of bytes written to . + private static int HexStringToBytes(ReadOnlySpan chars, Span bytes) { - if ((hexString.Length % 2) != 0) + if ((chars.Length % 2) != 0) { - throw new ArgumentException("Input string length must be a multiple of 2", nameof(hexString)); + throw new ArgumentException("Input string length must be a multiple of 2", nameof(chars)); } - if ((outputBytes.Length * 2) < hexString.Length) + 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); + } - static int GetHexVal(char hexChar) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static int FromChar(int c) { - if (hexChar >= '0' && hexChar <= '9') - { - return hexChar - '0'; - } - else if (hexChar >= 'A' && hexChar <= 'F') + // 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 charToHexLookup = new byte[] { - return 10 + (hexChar - 'A'); - } - else if (hexChar >= 'a' && hexChar <= 'f') - { - return 10 + (hexChar - 'a'); - } - else + 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) { - throw new ArgumentException($"Invalid hexadecimal value {hexChar}"); + break; } + + bytes[j++] = (byte)((byteHi << 4) | byteLo); + i += 2; + } + + if (byteLo == 0xFF) + { + i++; } - int inputByteCount = hexString.Length / 2; - for (int i = 0; i < inputByteCount; i++) + if ((byteLo | byteHi) == 0xFF) { - outputBytes[i] = (byte)((GetHexVal(hexString[i * 2]) << 4) + GetHexVal(hexString[(i * 2) + 1])); + throw new ArgumentException("Input string contained non-hexadecimal characters", nameof(chars)); } - return inputByteCount; + return j; } /// From fe044d131c45d89aa52281e2eb442c82b4424ce1 Mon Sep 17 00:00:00 2001 From: wischi Date: Tue, 28 Dec 2021 19:29:38 +0100 Subject: [PATCH 105/121] Remove return value documentation for void return types. --- src/ImageSharp/Formats/ImageExtensions.Save.cs | 8 -------- src/ImageSharp/Formats/ImageExtensions.Save.tt | 1 - 2 files changed, 9 deletions(-) diff --git a/src/ImageSharp/Formats/ImageExtensions.Save.cs b/src/ImageSharp/Formats/ImageExtensions.Save.cs index a6a65aef6..84f9d69b7 100644 --- a/src/ImageSharp/Formats/ImageExtensions.Save.cs +++ b/src/ImageSharp/Formats/ImageExtensions.Save.cs @@ -105,7 +105,6 @@ namespace SixLabors.ImageSharp /// The stream to save the image to. /// The encoder to save the image with. /// Thrown if the stream is null. - /// A representing the asynchronous operation. public static void SaveAsBmp(this Image source, Stream stream, BmpEncoder encoder) => source.Save( stream, @@ -208,7 +207,6 @@ namespace SixLabors.ImageSharp /// The stream to save the image to. /// The encoder to save the image with. /// Thrown if the stream is null. - /// A representing the asynchronous operation. public static void SaveAsGif(this Image source, Stream stream, GifEncoder encoder) => source.Save( stream, @@ -311,7 +309,6 @@ namespace SixLabors.ImageSharp /// The stream to save the image to. /// The encoder to save the image with. /// Thrown if the stream is null. - /// A representing the asynchronous operation. public static void SaveAsJpeg(this Image source, Stream stream, JpegEncoder encoder) => source.Save( stream, @@ -414,7 +411,6 @@ namespace SixLabors.ImageSharp /// The stream to save the image to. /// The encoder to save the image with. /// Thrown if the stream is null. - /// A representing the asynchronous operation. public static void SaveAsPbm(this Image source, Stream stream, PbmEncoder encoder) => source.Save( stream, @@ -517,7 +513,6 @@ namespace SixLabors.ImageSharp /// The stream to save the image to. /// The encoder to save the image with. /// Thrown if the stream is null. - /// A representing the asynchronous operation. public static void SaveAsPng(this Image source, Stream stream, PngEncoder encoder) => source.Save( stream, @@ -620,7 +615,6 @@ namespace SixLabors.ImageSharp /// The stream to save the image to. /// The encoder to save the image with. /// Thrown if the stream is null. - /// A representing the asynchronous operation. public static void SaveAsTga(this Image source, Stream stream, TgaEncoder encoder) => source.Save( stream, @@ -723,7 +717,6 @@ namespace SixLabors.ImageSharp /// The stream to save the image to. /// The encoder to save the image with. /// Thrown if the stream is null. - /// A representing the asynchronous operation. public static void SaveAsWebp(this Image source, Stream stream, WebpEncoder encoder) => source.Save( stream, @@ -826,7 +819,6 @@ namespace SixLabors.ImageSharp /// The stream to save the image to. /// The encoder to save the image with. /// Thrown if the stream is null. - /// A representing the asynchronous operation. public static void SaveAsTiff(this Image source, Stream stream, TiffEncoder encoder) => source.Save( stream, diff --git a/src/ImageSharp/Formats/ImageExtensions.Save.tt b/src/ImageSharp/Formats/ImageExtensions.Save.tt index c4a00b37c..ae7648522 100644 --- a/src/ImageSharp/Formats/ImageExtensions.Save.tt +++ b/src/ImageSharp/Formats/ImageExtensions.Save.tt @@ -124,7 +124,6 @@ namespace SixLabors.ImageSharp /// The stream to save the image to. /// The encoder to save the image with. /// Thrown if the stream is null. - /// A representing the asynchronous operation. public static void SaveAs<#= fmt #>(this Image source, Stream stream, <#= fmt #>Encoder encoder) => source.Save( stream, From 76261ff808d4b78cee3c392c0d0418c510986909 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 3 Jan 2022 22:23:52 +1100 Subject: [PATCH 106/121] Update shared-infrastructure --- shared-infrastructure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-infrastructure b/shared-infrastructure index a042aba17..59ce17f5a 160000 --- a/shared-infrastructure +++ b/shared-infrastructure @@ -1 +1 @@ -Subproject commit a042aba176cdb840d800c6ed4cfe41a54fb7b1e3 +Subproject commit 59ce17f5a4e1f956811133f41add7638e74c2836 From 6dba6cf1f8fb07847d0e5036557679a202a4d9c6 Mon Sep 17 00:00:00 2001 From: "WINDEV2110EVAL\\User" Date: Mon, 3 Jan 2022 14:45:35 -0800 Subject: [PATCH 107/121] Moved HexStringToBytes into a SixLabors.ImageSharp.Common.Helpers.HexConverter. --- src/ImageSharp/Common/Helpers/HexConverter.cs | 98 +++++++++++++++++++ src/ImageSharp/Formats/Png/PngDecoderCore.cs | 92 +---------------- 2 files changed, 101 insertions(+), 89 deletions(-) create mode 100644 src/ImageSharp/Common/Helpers/HexConverter.cs diff --git a/src/ImageSharp/Common/Helpers/HexConverter.cs b/src/ImageSharp/Common/Helpers/HexConverter.cs new file mode 100644 index 000000000..c55e9bbd9 --- /dev/null +++ b/src/ImageSharp/Common/Helpers/HexConverter.cs @@ -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 + { + /// + /// 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. + /// + /// The hexadecimal string to parse. + /// The destination for the parsed bytes. Must be at least .Length / 2 bytes long. + /// The number of bytes written to . + public static int HexStringToBytes(ReadOnlySpan chars, Span 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 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; + } + } +} diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 182d6e7be..708cd7f5f 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -11,6 +11,7 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; using System.Threading; +using SixLabors.ImageSharp.Common.Helpers; using SixLabors.ImageSharp.Compression.Zlib; using SixLabors.ImageSharp.Formats.Png.Chunks; using SixLabors.ImageSharp.Formats.Png.Filters; @@ -1093,7 +1094,7 @@ namespace SixLabors.ImageSharp.Formats.Png tempExifBuf = new byte[exifHeader.Length]; } - HexStringToBytes(dataSpan.Slice(0, exifHeader.Length * 2), tempExifBuf); + HexConverter.HexStringToBytes(dataSpan.Slice(0, exifHeader.Length * 2), tempExifBuf); if (!tempExifBuf.AsSpan().Slice(0, exifHeader.Length).SequenceEqual(exifHeader)) { // Exif header in the hex data is not valid @@ -1115,7 +1116,7 @@ namespace SixLabors.ImageSharp.Formats.Png lineSpan = dataSpan.Slice(0, newlineIndex); } - i += HexStringToBytes(lineSpan, exifBlob.AsSpan().Slice(i)); + i += HexConverter.HexStringToBytes(lineSpan, exifBlob.AsSpan().Slice(i)); dataSpan = dataSpan.Slice(newlineIndex + 1); } @@ -1163,93 +1164,6 @@ namespace SixLabors.ImageSharp.Formats.Png #pragma warning restore IDE0022 // Use expression body for methods } - /// - /// 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. - /// - /// The hexadecimal string to parse. - /// The destination for the parsed bytes. Must be at least .Length / 2 bytes long. - /// The number of bytes written to . - private static int HexStringToBytes(ReadOnlySpan chars, Span 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 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; - } - /// /// Sets the in to , /// or copies exif tags if already contains an . From bdb69d1027c13d8b3ded75bb83703c1d6fb3d3e6 Mon Sep 17 00:00:00 2001 From: "WINDEV2110EVAL\\User" Date: Mon, 3 Jan 2022 15:03:18 -0800 Subject: [PATCH 108/121] Allow reading legacy exif data from uncompressed text chunks as well. --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 49 ++++++++++++++------ 1 file changed, 34 insertions(+), 15 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 708cd7f5f..2a8f9614b 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -188,7 +188,7 @@ namespace SixLabors.ImageSharp.Formats.Png this.AssignTransparentMarkers(alpha, pngMetadata); break; case PngChunkType.Text: - this.ReadTextChunk(pngMetadata, chunk.Data.GetSpan()); + this.ReadTextChunk(metadata, pngMetadata, chunk.Data.GetSpan()); break; case PngChunkType.CompressedText: this.ReadCompressedTextChunk(metadata, pngMetadata, chunk.Data.GetSpan()); @@ -298,7 +298,7 @@ namespace SixLabors.ImageSharp.Formats.Png break; } - this.ReadTextChunk(pngMetadata, chunk.Data.GetSpan()); + this.ReadTextChunk(metadata, pngMetadata, chunk.Data.GetSpan()); break; case PngChunkType.CompressedText: if (this.colorMetadataOnly) @@ -970,7 +970,7 @@ namespace SixLabors.ImageSharp.Formats.Png /// /// The metadata to decode to. /// The containing the data. - private void ReadTextChunk(PngMetadata metadata, ReadOnlySpan data) + private void ReadTextChunk(ImageMetadata baseMetadata, PngMetadata metadata, ReadOnlySpan data) { if (this.ignoreMetadata) { @@ -993,7 +993,10 @@ namespace SixLabors.ImageSharp.Formats.Png string value = PngConstants.Encoding.GetString(data.Slice(zeroIndex + 1)); - metadata.TextData.Add(new PngTextData(name, value, string.Empty, string.Empty)); + if (!this.TryReadSpecialTextData(baseMetadata, name, value)) + { + metadata.TextData.Add(new PngTextData(name, value, string.Empty, string.Empty)); + } } /// @@ -1030,19 +1033,35 @@ namespace SixLabors.ImageSharp.Formats.Png ReadOnlySpan compressedData = data.Slice(zeroIndex + 2); - if (this.TryUncompressTextData(compressedData, PngConstants.Encoding, out string uncompressed)) + if (this.TryUncompressTextData(compressedData, PngConstants.Encoding, out string uncompressed) && + !this.TryReadSpecialTextData(baseMetadata, name, uncompressed)) { - if (name.Equals("Raw profile type exif", StringComparison.OrdinalIgnoreCase) && - this.TryReadLegacyExifTextChunk(baseMetadata, uncompressed)) - { - // Successfully parsed exif data stored as text in this chunk - } - else - { - // Seems to be regular old text data, or we failed to parse it in any special way - metadata.TextData.Add(new PngTextData(name, uncompressed, string.Empty, string.Empty)); - } + metadata.TextData.Add(new PngTextData(name, uncompressed, string.Empty, string.Empty)); + } + } + + /// + /// Checks if the given text chunk is actually storing parsable metadata. + /// + /// + /// + /// + /// True if metadata was successfully parsed from the text chunk. False if the + /// text chunk was not identified as metadata, and should be stored in the metadata + /// object unmodified. + private bool TryReadSpecialTextData(ImageMetadata baseMetadata, string chunkName, string chunkText) + { + if (chunkName.Equals("Raw profile type exif", StringComparison.OrdinalIgnoreCase) && + this.TryReadLegacyExifTextChunk(baseMetadata, chunkText)) + { + // Successfully parsed legacy exif data from text + return true; } + + // TODO: "Raw profile type iptc", potentially others? + + // No special chunk data identified + return false; } /// From 6cdc595583fa6798c2fec04de8d016a4b13b4047 Mon Sep 17 00:00:00 2001 From: "WINDEV2110EVAL\\User" Date: Mon, 3 Jan 2022 15:04:00 -0800 Subject: [PATCH 109/121] Merge with remote --- shared-infrastructure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-infrastructure b/shared-infrastructure index 59ce17f5a..a042aba17 160000 --- a/shared-infrastructure +++ b/shared-infrastructure @@ -1 +1 @@ -Subproject commit 59ce17f5a4e1f956811133f41add7638e74c2836 +Subproject commit a042aba176cdb840d800c6ed4cfe41a54fb7b1e3 From 7e7ea93882d7721dfcc7a83844e26a343bbd3a3d Mon Sep 17 00:00:00 2001 From: "WINDEV2110EVAL\\User" Date: Mon, 3 Jan 2022 15:12:34 -0800 Subject: [PATCH 110/121] Fixed comments. --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 2a8f9614b..c9f0ce375 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -968,6 +968,7 @@ namespace SixLabors.ImageSharp.Formats.Png /// /// Reads a text chunk containing image properties from the data. /// + /// The object. /// The metadata to decode to. /// The containing the data. private void ReadTextChunk(ImageMetadata baseMetadata, PngMetadata metadata, ReadOnlySpan data) @@ -993,7 +994,7 @@ namespace SixLabors.ImageSharp.Formats.Png string value = PngConstants.Encoding.GetString(data.Slice(zeroIndex + 1)); - if (!this.TryReadSpecialTextData(baseMetadata, name, value)) + if (!this.TryReadTextChunkMetadata(baseMetadata, name, value)) { metadata.TextData.Add(new PngTextData(name, value, string.Empty, string.Empty)); } @@ -1034,7 +1035,7 @@ namespace SixLabors.ImageSharp.Formats.Png ReadOnlySpan compressedData = data.Slice(zeroIndex + 2); if (this.TryUncompressTextData(compressedData, PngConstants.Encoding, out string uncompressed) && - !this.TryReadSpecialTextData(baseMetadata, name, uncompressed)) + !this.TryReadTextChunkMetadata(baseMetadata, name, uncompressed)) { metadata.TextData.Add(new PngTextData(name, uncompressed, string.Empty, string.Empty)); } @@ -1043,13 +1044,13 @@ namespace SixLabors.ImageSharp.Formats.Png /// /// Checks if the given text chunk is actually storing parsable metadata. /// - /// - /// - /// + /// The object to store the parsed metadata in. + /// The name of the text chunk. + /// The contents of the text chunk. /// True if metadata was successfully parsed from the text chunk. False if the /// text chunk was not identified as metadata, and should be stored in the metadata /// object unmodified. - private bool TryReadSpecialTextData(ImageMetadata baseMetadata, string chunkName, string chunkText) + private bool TryReadTextChunkMetadata(ImageMetadata baseMetadata, string chunkName, string chunkText) { if (chunkName.Equals("Raw profile type exif", StringComparison.OrdinalIgnoreCase) && this.TryReadLegacyExifTextChunk(baseMetadata, chunkText)) From c50935f5ca30652437a776642bea2330658f0213 Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Tue, 4 Jan 2022 06:21:26 +0300 Subject: [PATCH 111/121] Fixed runtime error --- .../Formats/Jpeg/Components/FastFloatingPointDCT.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/Components/FastFloatingPointDCT.cs b/src/ImageSharp/Formats/Jpeg/Components/FastFloatingPointDCT.cs index 81bfe2135..c27ad5b82 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/FastFloatingPointDCT.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/FastFloatingPointDCT.cs @@ -146,11 +146,13 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// /// Apply floating point IDCT inplace using API. /// + /// + /// This method can be used even if there's no SIMD intrinsics available + /// as can be compiled to scalar instructions. + /// /// Input block. private static void IDCT_Vector4(ref Block8x8F transposedBlock) { - DebugGuard.IsTrue(Vector.IsHardwareAccelerated, "Scalar implementation should be called for non-accelerated hardware."); - // First pass - process columns IDCT8x4_Vector4(ref transposedBlock.V0L); IDCT8x4_Vector4(ref transposedBlock.V0R); From c719cf2d718e9e58997e947bcaba8e5a2009fda8 Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Tue, 4 Jan 2022 08:21:53 +0300 Subject: [PATCH 112/121] Fixed intrinsic flag in DCT tests --- tests/ImageSharp.Tests/Formats/Jpg/DCTTests.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/ImageSharp.Tests/Formats/Jpg/DCTTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/DCTTests.cs index 85f30d28d..75572b943 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/DCTTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/DCTTests.cs @@ -149,12 +149,12 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg // 4 paths: // 1. AllowAll - call avx/fma implementation // 2. DisableFMA - call avx without fma implementation - // 3. DisableAvx - call sse Vector4 implementation - // 4. DisableHWIntrinsic - call scalar fallback implementation + // 3. DisableAvx - call sse implementation + // 4. DisableSIMD - call Vector4 fallback implementation FeatureTestRunner.RunWithHwIntrinsicsFeature( RunTest, seed, - HwIntrinsics.AllowAll | HwIntrinsics.DisableFMA | HwIntrinsics.DisableAVX | HwIntrinsics.DisableHWIntrinsic); + HwIntrinsics.AllowAll | HwIntrinsics.DisableFMA | HwIntrinsics.DisableAVX | HwIntrinsics.DisableSIMD); } // Forward transform @@ -197,12 +197,12 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg // 4 paths: // 1. AllowAll - call avx/fma implementation // 2. DisableFMA - call avx without fma implementation - // 3. DisableAvx - call sse Vector4 implementation - // 4. DisableHWIntrinsic - call scalar fallback implementation + // 3. DisableAvx - call sse implementation + // 4. DisableSIMD - call Vector4 fallback implementation FeatureTestRunner.RunWithHwIntrinsicsFeature( RunTest, seed, - HwIntrinsics.AllowAll | HwIntrinsics.DisableFMA | HwIntrinsics.DisableAVX | HwIntrinsics.DisableHWIntrinsic); + HwIntrinsics.AllowAll | HwIntrinsics.DisableFMA | HwIntrinsics.DisableAVX | HwIntrinsics.DisableSIMD); } } } From d61b845fd93fff6875638966bcc1b97445ccc3fb Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Tue, 4 Jan 2022 08:22:44 +0300 Subject: [PATCH 113/121] Fixed FDCT test comment --- tests/ImageSharp.Tests/Formats/Jpg/DCTTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ImageSharp.Tests/Formats/Jpg/DCTTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/DCTTests.cs index 75572b943..36570ce55 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/DCTTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/DCTTests.cs @@ -197,8 +197,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg // 4 paths: // 1. AllowAll - call avx/fma implementation // 2. DisableFMA - call avx without fma implementation - // 3. DisableAvx - call sse implementation - // 4. DisableSIMD - call Vector4 fallback implementation + // 3. DisableAvx - call Vector4 implementation + // 4. DisableSIMD - call scalar fallback implementation FeatureTestRunner.RunWithHwIntrinsicsFeature( RunTest, seed, From 95318b1d9d93d84dc295e0f648d8e2bd6f0d7b4d Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 4 Jan 2022 22:55:56 +1100 Subject: [PATCH 114/121] Update shared-infrastructure --- shared-infrastructure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-infrastructure b/shared-infrastructure index a042aba17..59ce17f5a 160000 --- a/shared-infrastructure +++ b/shared-infrastructure @@ -1 +1 @@ -Subproject commit a042aba176cdb840d800c6ed4cfe41a54fb7b1e3 +Subproject commit 59ce17f5a4e1f956811133f41add7638e74c2836 From 7d3921aa74ce04ca4092d4fb1db0925377900cd0 Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Tue, 4 Jan 2022 15:08:49 +0300 Subject: [PATCH 115/121] cleanup --- .../Metadata/Profiles/Exif/ExifReader.cs | 28 ------------------- 1 file changed, 28 deletions(-) diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs index 4fcac5299..2fcd1cc07 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs @@ -224,17 +224,6 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif } } - ////protected void ReadSubIfd64(List values) - ////{ - //// if (this.subIfds is not null) - //// { - //// foreach (ulong subIfdOffset in this.subIfds) - //// { - //// this.ReadValues64(values, subIfdOffset); - //// } - //// } - ////} - private static TDataType[] ToArray(ExifDataType dataType, ReadOnlySpan data, ConverterMethod converter) { int dataTypeSize = (int)ExifDataTypes.GetSize(dataType); @@ -479,15 +468,6 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif case ExifTagValue.TileByteCounts: exifValue = new ExifLong8Array(ExifTagValue.TileByteCounts); break; - ////case ExifTagValue.SubIFDOffset: - //// exifValue = new ExifLong8(ExifTagValue.SubIFDOffset); - //// break; - ////case ExifTagValue.GPSIFDOffset: - //// exifValue = new ExifLong8(ExifTagValue.GPSIFDOffset); - //// break; - ////case ExifTagValue.SubIFDs: - //// exifValue = new ExifLong8Array(ExifTagValue.SubIFDs); - //// break; default: exifValue = ExifValues.Create(tag) ?? ExifValues.Create(tag, dataType, numberOfComponents); break; @@ -543,14 +523,6 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif { this.AddSubIfd(value); } - else if (exif.Tag == ExifTag.SubIFDs) - { - //// didn't find any useful data in SubIFDs - ////foreach (object val in (Array)value) - ////{ - //// this.AddSubIfd(val); - ////} - } else { values.Add(exif); From 46f976a9b6c84b468fe41bc43a42a816dc99bd35 Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Tue, 4 Jan 2022 15:09:11 +0300 Subject: [PATCH 116/121] comment --- tests/ImageSharp.Tests/Formats/Tiff/BigTiffMetadataTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ImageSharp.Tests/Formats/Tiff/BigTiffMetadataTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/BigTiffMetadataTests.cs index 1493060d5..9f5b78cc3 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/BigTiffMetadataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/BigTiffMetadataTests.cs @@ -166,7 +166,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff { { new ExifTag((ExifTagValue)0xdd11), (ExifDataType.Long8, ulong.MaxValue) }, { new ExifTag((ExifTagValue)0xdd12), (ExifDataType.SignedLong8, long.MaxValue) }, - //// WriteIfdTags64Bit: arrays aren't support + //// WriteIfdTags64Bit: arrays aren't support (by our code) ////{ new ExifTag((ExifTagValue)0xdd13), (ExifDataType.Long8, new ulong[] { 0, 1234, 56789UL, ulong.MaxValue }) }, ////{ new ExifTag((ExifTagValue)0xdd14), (ExifDataType.SignedLong8, new long[] { -1234, 56789L, long.MaxValue }) }, }; From 62fc16224e72f558243e6207b22381afe9262ad2 Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Tue, 4 Jan 2022 15:10:03 +0300 Subject: [PATCH 117/121] HTML -> MD --- .../Input/Tiff/BigTiff/BigTIFFSamples.html | 239 ------------------ .../Input/Tiff/BigTiff/BigTIFFSamples.md | 220 ++++++++++++++++ tests/Images/Input/Tiff/BigTiff/readme.md | 6 +- 3 files changed, 224 insertions(+), 241 deletions(-) delete mode 100644 tests/Images/Input/Tiff/BigTiff/BigTIFFSamples.html create mode 100644 tests/Images/Input/Tiff/BigTiff/BigTIFFSamples.md diff --git a/tests/Images/Input/Tiff/BigTiff/BigTIFFSamples.html b/tests/Images/Input/Tiff/BigTiff/BigTIFFSamples.html deleted file mode 100644 index c674e57b5..000000000 --- a/tests/Images/Input/Tiff/BigTiff/BigTIFFSamples.html +++ /dev/null @@ -1,239 +0,0 @@ - - - - -

- These images were created by AWare Systems. -

-

Index

-

- Classic.tif
- BigTIFF.tif
- BigTIFFMotorola.tif
- BigTIFFLong.tif
- BigTIFFLong8.tif
- BigTIFFMotorolaLongStrips.tif
- BigTIFFLong8Tiles.tif
- BigTIFFSubIFD4.tif
- BigTIFFSubIFD8.tif
-

-

Classic.tif

-

- Classic.tif is a basic Classic TIFF file. All files in this package have the same actual image content, - so this TIFF file serves as a reference. -

-

- Format: Classic TIFF
- Byte Order: Intel
- Ifd Offset: 12302
-     ImageWidth (1 Short): 64
-     ImageLength (1 Short): 64
-     BitsPerSample (3 Short): 8, 8, 8
-     PhotometricInterpretation (1 Short): RGB
-     StripOffsets (1 Short): 8
-     SamplesPerPixel (1 Short): 3
-     RowsPerStrip (1 Short): 64
-     StripByteCounts (1 Short): 12288
-

-

BigTIFF.tif

-

- BigTIFF.tif ressembles Classic.tif as close as possible. Except that it's a BigTIFF, that is... -

-

- Format: BigTIFF
- Byte Order: Intel
- Ifd Offset: 12304
-     ImageWidth (1 Short): 64
-     ImageLength (1 Short): 64
-     BitsPerSample (3 Short): 8, 8, 8
-     PhotometricInterpretation (1 Short): RGB
-     StripOffsets (1 Short): 16
-     SamplesPerPixel (1 Short): 3
-     RowsPerStrip (1 Short): 64
-     StripByteCounts (1 Short): 12288
-

-

BigTIFFMotorola.tif

-

- BigTIFFMotorola.tif reverses the byte order. -

-

- Format: BigTIFF
- Byte Order: Motorola
- Ifd Offset: 12304
-     ImageWidth (1 Short): 64
-     ImageLength (1 Short): 64
-     BitsPerSample (3 Short): 8, 8, 8
-     PhotometricInterpretation (1 Short): RGB
-     StripOffsets (1 Short): 16
-     SamplesPerPixel (1 Short): 3
-     RowsPerStrip (1 Short): 64
-     StripByteCounts (1 Short): 12288
-

-

BigTIFFLong.tif

-

- All previous TIFFs specify DataType Short for StripOffsets and StripByteCounts tags. This BigTIFF instead specifies DataType Long, for these tags. -

-

- Format: BigTIFF
- Byte Order: Intel
- Ifd Offset: 12304
-     ImageWidth (1 Short): 64
-     ImageLength (1 Short): 64
-     BitsPerSample (3 Short): 8, 8, 8
-     PhotometricInterpretation (1 Short): RGB
-     StripOffsets (1 Long): 16
-     SamplesPerPixel (1 Short): 3
-     RowsPerStrip (1 Short): 64
-     StripByteCounts (1 Long): 12288
-

-

BigTIFFLong8.tif

-

- This next one specifies DataType Long8, for StripOffsets and StripByteCounts tags. -

-

- Format: BigTIFF
- Byte Order: Intel
- Ifd Offset: 12304
-     ImageWidth (1 Short): 64
-     ImageLength (1 Short): 64
-     BitsPerSample (3 Short): 8, 8, 8
-     PhotometricInterpretation (1 Short): RGB
-     StripOffsets (1 Long8): 16
-     SamplesPerPixel (1 Short): 3
-     RowsPerStrip (1 Short): 64
-     StripByteCounts (1 Long8): 12288
-

-

BigTIFFMotorolaLongStrips.tif

-

- This BigTIFF has Motorola byte order, plus, it's divided over two strips. StripOffsets and StripByteCounts tags have DataType Long, so their actual value fits inside the IFD. -

-

- Format: BigTIFF
- Byte Order: Motorola
- Ifd Offset: 12304
-     ImageWidth (1 Short): 64
-     ImageLength (1 Short): 64
-     BitsPerSample (3 Short): 8, 8, 8
-     PhotometricInterpretation (1 Short): RGB
-     StripOffsets (2 Long): 16, 6160
-     SamplesPerPixel (1 Short): 3
-     RowsPerStrip (1 Short): 32
-     StripByteCounts (2 Long): 6144, 6144
-

-

BigTIFFLong8Tiles.tif

-

- BigTIFFLong8Tiles.tif is a tiled BigTIFF. TileOffsets and TileByteCounts tags specify DataType Long8. -

-

- Format: BigTIFF
- Byte Order: Intel
- Ifd Offset: 12368
-     ImageWidth (1 Short): 64
-     ImageLength (1 Short): 64
-     BitsPerSample (3 Short): 8, 8, 8
-     PhotometricInterpretation (1 Short): RGB
-     SamplesPerPixel (1 Short): 3
-     TileWidth (1 Short): 32
-     TileLength (1 Short): 32
-     TileOffsets (4 Long8): 16, 3088, 6160, 9232
-     TileByteCounts (4 Long8): 3072, 3072, 3072, 3072
-

-

BigTIFFSubIFD4.tif

-

- This BigTIFF contains two pages, the second page showing almost the same image content as the first, except that the black square is white, and text color is black. - Both pages point to a downsample SubIFD, using SubIFDs DataType TIFF_IFD. -

-

- Format: BigTIFF
- Byte Order: Intel
- Ifd Offset: 15572
-     ImageWidth (1 Short): 64
-     ImageLength (1 Short): 64
-     BitsPerSample (3 Short): 8, 8, 8
-     PhotometricInterpretation (1 Short): RGB
-     StripOffsets (1 Short): 3284
-     SamplesPerPixel (1 Short): 3
-     RowsPerStrip (1 Short): 64
-     StripByteCounts (1 Short): 12288
-     SubIFDs (1 IFD): 3088
- SubIfd Offset: 3088
-     NewSubFileType (1 Long): 1
-     ImageWidth (1 Short): 32
-     ImageLength (1 Short): 32
-     BitsPerSample (3 Short): 8, 8, 8
-     PhotometricInterpretation (1 Short): RGB
-     StripOffsets (1 Short): 16
-     SamplesPerPixel (1 Short): 3
-     RowsPerStrip (1 Short): 32
-     StripByteCounts (1 Short): 3072
- Ifd Offset: 31324
-     ImageWidth (1 Short): 64
-     ImageLength (1 Short): 64
-     BitsPerSample (3 Short): 8, 8, 8
-     PhotometricInterpretation (1 Short): RGB
-     StripOffsets (1 Short): 19036
-     SamplesPerPixel (1 Short): 3
-     RowsPerStrip (1 Short): 64
-     StripByteCounts (1 Short): 12288
-     SubIFDs (1 IFD): 18840
- SubIfd Offset: 18840
-     NewSubFileType (1 Long): 1
-     ImageWidth (1 Short): 32
-     ImageLength (1 Short): 32
-     BitsPerSample (3 Short): 8, 8, 8
-     PhotometricInterpretation (1 Short): RGB
-     StripOffsets (1 Short): 15768
-     SamplesPerPixel (1 Short): 3
-     RowsPerStrip (1 Short): 32
-     StripByteCounts (1 Short): 3072
-

-

BigTIFFSubIFD8.tif

-

- BigTIFFSubIFD4.tif is very much the same as BigTIFFSubIFD4.tif, except that the new DataType TIFF_IFD8 is used for the SubIFDs tag. -

-

- Format: BigTIFF
- Byte Order: Intel
- Ifd Offset: 15572
-     ImageWidth (1 Short): 64
-     ImageLength (1 Short): 64
-     BitsPerSample (3 Short): 8, 8, 8
-     PhotometricInterpretation (1 Short): RGB
-     StripOffsets (1 Short): 3284
-     SamplesPerPixel (1 Short): 3
-     RowsPerStrip (1 Short): 64
-     StripByteCounts (1 Short): 12288
-     SubIFDs (1 IFD8): 3088
- SubIfd Offset: 3088
-     NewSubFileType (1 Long): 1
-     ImageWidth (1 Short): 32
-     ImageLength (1 Short): 32
-     BitsPerSample (3 Short): 8, 8, 8
-     PhotometricInterpretation (1 Short): RGB
-     StripOffsets (1 Short): 16
-     SamplesPerPixel (1 Short): 3
-     RowsPerStrip (1 Short): 32
-     StripByteCounts (1 Short): 3072
- Ifd Offset: 31324
-     ImageWidth (1 Short): 64
-     ImageLength (1 Short): 64
-     BitsPerSample (3 Short): 8, 8, 8
-     PhotometricInterpretation (1 Short): RGB
-     StripOffsets (1 Short): 19036
-     SamplesPerPixel (1 Short): 3
-     RowsPerStrip (1 Short): 64
-     StripByteCounts (1 Short): 12288
-     SubIFDs (1 IFD8): 18840
- SubIfd Offset: 18840
-     NewSubFileType (1 Long): 1
-     ImageWidth (1 Short): 32
-     ImageLength (1 Short): 32
-     BitsPerSample (3 Short): 8, 8, 8
-     PhotometricInterpretation (1 Short): RGB
-     StripOffsets (1 Short): 15768
-     SamplesPerPixel (1 Short): 3
-     RowsPerStrip (1 Short): 32
-     StripByteCounts (1 Short): 3072
-

- - diff --git a/tests/Images/Input/Tiff/BigTiff/BigTIFFSamples.md b/tests/Images/Input/Tiff/BigTiff/BigTIFFSamples.md new file mode 100644 index 000000000..c3047009e --- /dev/null +++ b/tests/Images/Input/Tiff/BigTiff/BigTIFFSamples.md @@ -0,0 +1,220 @@ +These images were created by [AWare Systems](http://www.awaresystems.be/). + +# Index + +[Classic.tif](#classic) +[BigTIFF.tif](#bigtiff) +[BigTIFFMotorola.tif](#bigtiffmotorola) +[BigTIFFLong.tif](#bigtifflong) +[BigTIFFLong8.tif](#bigtifflong8) +[BigTIFFMotorolaLongStrips.tif](#bigtiffmotorolalongstrips) +[BigTIFFLong8Tiles.tif](#bigtifflong8tiles) +[BigTIFFSubIFD4.tif](#bigtiffsubifd4) +[BigTIFFSubIFD8.tif](#bigtiffsubifd8) + +# Classic.tif + +Classic.tif is a basic Classic TIFF file. All files in this package have the same actual image content, so this TIFF file serves as a reference. + +Format: Classic TIFF +Byte Order: Intel +Ifd Offset: 12302 +    ImageWidth (1 Short): 64 +    ImageLength (1 Short): 64 +    BitsPerSample (3 Short): 8, 8, 8 +    PhotometricInterpretation (1 Short): RGB +    StripOffsets (1 Short): 8 +    SamplesPerPixel (1 Short): 3 +    RowsPerStrip (1 Short): 64 +    StripByteCounts (1 Short): 12288 + +# BigTIFF.tif + +BigTIFF.tif ressembles Classic.tif as close as possible. Except that it's a BigTIFF, that is... + +Format: BigTIFF +Byte Order: Intel +Ifd Offset: 12304 +    ImageWidth (1 Short): 64 +    ImageLength (1 Short): 64 +    BitsPerSample (3 Short): 8, 8, 8 +    PhotometricInterpretation (1 Short): RGB +    StripOffsets (1 Short): 16 +    SamplesPerPixel (1 Short): 3 +    RowsPerStrip (1 Short): 64 +    StripByteCounts (1 Short): 12288 + +# BigTIFFMotorola.tif + +BigTIFFMotorola.tif reverses the byte order. + +Format: BigTIFF +Byte Order: Motorola +Ifd Offset: 12304 +    ImageWidth (1 Short): 64 +    ImageLength (1 Short): 64 +    BitsPerSample (3 Short): 8, 8, 8 +    PhotometricInterpretation (1 Short): RGB +    StripOffsets (1 Short): 16 +    SamplesPerPixel (1 Short): 3 +    RowsPerStrip (1 Short): 64 +    StripByteCounts (1 Short): 12288 + +# BigTIFFLong.tif + +All previous TIFFs specify DataType Short for StripOffsets and StripByteCounts tags. This BigTIFF instead specifies DataType Long, for these tags. + +Format: BigTIFF +Byte Order: Intel +Ifd Offset: 12304 +    ImageWidth (1 Short): 64 +    ImageLength (1 Short): 64 +    BitsPerSample (3 Short): 8, 8, 8 +    PhotometricInterpretation (1 Short): RGB +    StripOffsets (1 Long): 16 +    SamplesPerPixel (1 Short): 3 +    RowsPerStrip (1 Short): 64 +    StripByteCounts (1 Long): 12288 + +# BigTIFFLong8.tif + +This next one specifies DataType Long8, for StripOffsets and StripByteCounts tags. + +Format: BigTIFF +Byte Order: Intel +Ifd Offset: 12304 +    ImageWidth (1 Short): 64 +    ImageLength (1 Short): 64 +    BitsPerSample (3 Short): 8, 8, 8 +    PhotometricInterpretation (1 Short): RGB +    StripOffsets (1 Long8): 16 +    SamplesPerPixel (1 Short): 3 +    RowsPerStrip (1 Short): 64 +    StripByteCounts (1 Long8): 12288 + +# BigTIFFMotorolaLongStrips.tif + +This BigTIFF has Motorola byte order, plus, it's divided over two strips. StripOffsets and StripByteCounts tags have DataType Long, so their actual value fits inside the IFD. + +Format: BigTIFF +Byte Order: Motorola +Ifd Offset: 12304 +    ImageWidth (1 Short): 64 +    ImageLength (1 Short): 64 +    BitsPerSample (3 Short): 8, 8, 8 +    PhotometricInterpretation (1 Short): RGB +    StripOffsets (2 Long): 16, 6160 +    SamplesPerPixel (1 Short): 3 +    RowsPerStrip (1 Short): 32 +    StripByteCounts (2 Long): 6144, 6144 + +# BigTIFFLong8Tiles.tif + +BigTIFFLong8Tiles.tif is a tiled BigTIFF. TileOffsets and TileByteCounts tags specify DataType Long8. + +Format: BigTIFF +Byte Order: Intel +Ifd Offset: 12368 +    ImageWidth (1 Short): 64 +    ImageLength (1 Short): 64 +    BitsPerSample (3 Short): 8, 8, 8 +    PhotometricInterpretation (1 Short): RGB +    SamplesPerPixel (1 Short): 3 +    TileWidth (1 Short): 32 +    TileLength (1 Short): 32 +    TileOffsets (4 Long8): 16, 3088, 6160, 9232 +    TileByteCounts (4 Long8): 3072, 3072, 3072, 3072 + +# BigTIFFSubIFD4.tif + +This BigTIFF contains two pages, the second page showing almost the same image content as the first, except that the black square is white, and text color is black. Both pages point to a downsample SubIFD, using SubIFDs DataType TIFF_IFD. + +Format: BigTIFF +Byte Order: Intel +Ifd Offset: 15572 +    ImageWidth (1 Short): 64 +    ImageLength (1 Short): 64 +    BitsPerSample (3 Short): 8, 8, 8 +    PhotometricInterpretation (1 Short): RGB +    StripOffsets (1 Short): 3284 +    SamplesPerPixel (1 Short): 3 +    RowsPerStrip (1 Short): 64 +    StripByteCounts (1 Short): 12288 +    SubIFDs (1 IFD): 3088 +SubIfd Offset: 3088 +    NewSubFileType (1 Long): 1 +    ImageWidth (1 Short): 32 +    ImageLength (1 Short): 32 +    BitsPerSample (3 Short): 8, 8, 8 +    PhotometricInterpretation (1 Short): RGB +    StripOffsets (1 Short): 16 +    SamplesPerPixel (1 Short): 3 +    RowsPerStrip (1 Short): 32 +    StripByteCounts (1 Short): 3072 +Ifd Offset: 31324 +    ImageWidth (1 Short): 64 +    ImageLength (1 Short): 64 +    BitsPerSample (3 Short): 8, 8, 8 +    PhotometricInterpretation (1 Short): RGB +    StripOffsets (1 Short): 19036 +    SamplesPerPixel (1 Short): 3 +    RowsPerStrip (1 Short): 64 +    StripByteCounts (1 Short): 12288 +    SubIFDs (1 IFD): 18840 +SubIfd Offset: 18840 +    NewSubFileType (1 Long): 1 +    ImageWidth (1 Short): 32 +    ImageLength (1 Short): 32 +    BitsPerSample (3 Short): 8, 8, 8 +    PhotometricInterpretation (1 Short): RGB +    StripOffsets (1 Short): 15768 +    SamplesPerPixel (1 Short): 3 +    RowsPerStrip (1 Short): 32 +    StripByteCounts (1 Short): 3072 + +# BigTIFFSubIFD8.tif + +BigTIFFSubIFD4.tif is very much the same as BigTIFFSubIFD4.tif, except that the new DataType TIFF_IFD8 is used for the SubIFDs tag. + +Format: BigTIFF +Byte Order: Intel +Ifd Offset: 15572 +    ImageWidth (1 Short): 64 +    ImageLength (1 Short): 64 +    BitsPerSample (3 Short): 8, 8, 8 +    PhotometricInterpretation (1 Short): RGB +    StripOffsets (1 Short): 3284 +    SamplesPerPixel (1 Short): 3 +    RowsPerStrip (1 Short): 64 +    StripByteCounts (1 Short): 12288 +    SubIFDs (1 IFD8): 3088 +SubIfd Offset: 3088 +    NewSubFileType (1 Long): 1 +    ImageWidth (1 Short): 32 +    ImageLength (1 Short): 32 +    BitsPerSample (3 Short): 8, 8, 8 +    PhotometricInterpretation (1 Short): RGB +    StripOffsets (1 Short): 16 +    SamplesPerPixel (1 Short): 3 +    RowsPerStrip (1 Short): 32 +    StripByteCounts (1 Short): 3072 +Ifd Offset: 31324 +    ImageWidth (1 Short): 64 +    ImageLength (1 Short): 64 +    BitsPerSample (3 Short): 8, 8, 8 +    PhotometricInterpretation (1 Short): RGB +    StripOffsets (1 Short): 19036 +    SamplesPerPixel (1 Short): 3 +    RowsPerStrip (1 Short): 64 +    StripByteCounts (1 Short): 12288 +    SubIFDs (1 IFD8): 18840 +SubIfd Offset: 18840 +    NewSubFileType (1 Long): 1 +    ImageWidth (1 Short): 32 +    ImageLength (1 Short): 32 +    BitsPerSample (3 Short): 8, 8, 8 +    PhotometricInterpretation (1 Short): RGB +    StripOffsets (1 Short): 15768 +    SamplesPerPixel (1 Short): 3 +    RowsPerStrip (1 Short): 32 +    StripByteCounts (1 Short): 3072 \ No newline at end of file diff --git a/tests/Images/Input/Tiff/BigTiff/readme.md b/tests/Images/Input/Tiff/BigTiff/readme.md index be5d28906..80f6b595b 100644 --- a/tests/Images/Input/Tiff/BigTiff/readme.md +++ b/tests/Images/Input/Tiff/BigTiff/readme.md @@ -1,3 +1,5 @@ -BigTIFF samples. +#### BigTIFF samples. -Downloaded from AWARE SYSTEMS: https://www.awaresystems.be/imaging/tiff/bigtiff.html \ No newline at end of file +For details: BigTIFFSamples.md + +Downloaded from https://www.awaresystems.be/imaging/tiff/bigtiff.html \ No newline at end of file From feb49798bb316635c87a116da2974faf9e98cc14 Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Tue, 4 Jan 2022 15:35:06 +0300 Subject: [PATCH 118/121] format --- .../Input/Tiff/BigTiff/BigTIFFSamples.md | 18 +++++++++--------- tests/Images/Input/Tiff/BigTiff/readme.md | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/Images/Input/Tiff/BigTiff/BigTIFFSamples.md b/tests/Images/Input/Tiff/BigTiff/BigTIFFSamples.md index c3047009e..0401109fd 100644 --- a/tests/Images/Input/Tiff/BigTiff/BigTIFFSamples.md +++ b/tests/Images/Input/Tiff/BigTiff/BigTIFFSamples.md @@ -2,15 +2,15 @@ These images were created by [AWare Systems](http://www.awaresystems.be/). # Index -[Classic.tif](#classic) -[BigTIFF.tif](#bigtiff) -[BigTIFFMotorola.tif](#bigtiffmotorola) -[BigTIFFLong.tif](#bigtifflong) -[BigTIFFLong8.tif](#bigtifflong8) -[BigTIFFMotorolaLongStrips.tif](#bigtiffmotorolalongstrips) -[BigTIFFLong8Tiles.tif](#bigtifflong8tiles) -[BigTIFFSubIFD4.tif](#bigtiffsubifd4) -[BigTIFFSubIFD8.tif](#bigtiffsubifd8) +[Classic.tif](#classictif) +[BigTIFF.tif](#bigtifftif) +[BigTIFFMotorola.tif](#bigtiffmotorolatif) +[BigTIFFLong.tif](#bigtifflongtif) +[BigTIFFLong8.tif](#bigtifflong8tif) +[BigTIFFMotorolaLongStrips.tif](#bigtiffmotorolalongstripstif) +[BigTIFFLong8Tiles.tif](#bigtifflong8tilestif) +[BigTIFFSubIFD4.tif](#bigtiffsubifd4tif) +[BigTIFFSubIFD8.tif](#bigtiffsubifd8tif) # Classic.tif diff --git a/tests/Images/Input/Tiff/BigTiff/readme.md b/tests/Images/Input/Tiff/BigTiff/readme.md index 80f6b595b..29f9c8ea9 100644 --- a/tests/Images/Input/Tiff/BigTiff/readme.md +++ b/tests/Images/Input/Tiff/BigTiff/readme.md @@ -1,5 +1,5 @@ #### BigTIFF samples. -For details: BigTIFFSamples.md +For details: [BigTIFFSamples.md](BigTIFFSamples.md) Downloaded from https://www.awaresystems.be/imaging/tiff/bigtiff.html \ No newline at end of file From c682504b38915949ce8699a1bd7dbbf630370fe0 Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Wed, 5 Jan 2022 19:55:42 +0300 Subject: [PATCH 119/121] Fix --- src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs | 10 +++++++++- src/ImageSharp/Formats/Jpeg/JpegThrowHelper.cs | 3 +++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index 4b68c39ea..73af42afd 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -472,7 +472,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg : JpegColorSpace.Cmyk; } - JpegThrowHelper.ThrowInvalidImageContentException($"Unsupported color mode. Supported component counts 1, 3, and 4; found {componentCount}"); + JpegThrowHelper.ThrowNotSupportedComponentCount(componentCount); return default; } @@ -998,6 +998,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg // 1 byte: Number of components byte componentCount = this.temp[5]; + // Validate: componentCount more than 4 can lead to a buffer overflow during stream + // reading so we must limit it to 4 + // We do not support jpeg images with more than 4 components anyway + if (componentCount > 4) + { + JpegThrowHelper.ThrowNotSupportedComponentCount(componentCount); + } + this.Frame = new JpegFrame(frameMarker, precision, frameWidth, frameHeight, componentCount); remaining -= length; diff --git a/src/ImageSharp/Formats/Jpeg/JpegThrowHelper.cs b/src/ImageSharp/Formats/Jpeg/JpegThrowHelper.cs index 0292fbcab..b238e45ef 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegThrowHelper.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegThrowHelper.cs @@ -45,5 +45,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg [MethodImpl(InliningOptions.ColdPath)] public static void ThrowDimensionsTooLarge(int width, int height) => throw new ImageFormatException($"Image is too large to encode at {width}x{height} for JPEG format."); + + [MethodImpl(InliningOptions.ColdPath)] + public static void ThrowNotSupportedComponentCount(int componentCount) => throw new NotSupportedException($"Images with {componentCount} components are not supported."); } } From 6b36d552c17f1d942de945da25dc078414c72bd4 Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Wed, 5 Jan 2022 20:02:06 +0300 Subject: [PATCH 120/121] Added example image to the test suite --- tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs | 1 + tests/ImageSharp.Tests/TestImages.cs | 1 + .../issues/issue-1900-malformed-unsupported-255-components.jpg | 3 +++ 3 files changed, 5 insertions(+) create mode 100644 tests/Images/Input/Jpg/issues/issue-1900-malformed-unsupported-255-components.jpg diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs index 08d8d9038..695a10ec3 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs @@ -193,6 +193,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg [WithFile(TestImages.Jpeg.Baseline.ArithmeticCoding, PixelTypes.Rgba32)] [WithFile(TestImages.Jpeg.Baseline.ArithmeticCodingProgressive, PixelTypes.Rgba32)] [WithFile(TestImages.Jpeg.Baseline.Lossless, PixelTypes.Rgba32)] + [WithFile(TestImages.Jpeg.Issues.MalformedUnsupportedComponentCount, PixelTypes.Rgba32)] public void ThrowsNotSupported_WithUnsupportedJpegs(TestImageProvider provider) where TPixel : unmanaged, IPixel { diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 3f28a6116..deed0b240 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -256,6 +256,7 @@ namespace SixLabors.ImageSharp.Tests public const string BadSubSampling1076 = "Jpg/issues/issue-1076-invalid-subsampling.jpg"; public const string IdentifyMultiFrame1211 = "Jpg/issues/issue-1221-identify-multi-frame.jpg"; public const string WrongColorSpace = "Jpg/issues/Issue1732-WrongColorSpace.jpg"; + public const string MalformedUnsupportedComponentCount = "Jpg/issues/issue-1900-malformed-unsupported-255-components.jpg"; public static class Fuzz { diff --git a/tests/Images/Input/Jpg/issues/issue-1900-malformed-unsupported-255-components.jpg b/tests/Images/Input/Jpg/issues/issue-1900-malformed-unsupported-255-components.jpg new file mode 100644 index 000000000..7b6d7c572 --- /dev/null +++ b/tests/Images/Input/Jpg/issues/issue-1900-malformed-unsupported-255-components.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f3553f76b72b98986df13a7508cd073a30b7c846dc441d1d68a518bf7b93bc66 +size 3951 From 22ed6da3697852e381bde4915c9a3c9f7d0039ed Mon Sep 17 00:00:00 2001 From: Dmitry Pentin Date: Wed, 5 Jan 2022 20:13:33 +0300 Subject: [PATCH 121/121] Moved 'unrecoverable image' to 'unsupported' test case --- .../Formats/Jpg/JpegDecoderTests.Images.cs | 150 ++++++++++-------- .../Formats/Jpg/JpegDecoderTests.cs | 5 +- 2 files changed, 82 insertions(+), 73 deletions(-) diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs index d82359e61..db5169a04 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs @@ -10,58 +10,72 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg public partial class JpegDecoderTests { public static string[] BaselineTestJpegs = - { - TestImages.Jpeg.Baseline.Calliphora, - TestImages.Jpeg.Baseline.Cmyk, - TestImages.Jpeg.Baseline.Ycck, - TestImages.Jpeg.Baseline.Jpeg400, - TestImages.Jpeg.Baseline.Turtle420, - TestImages.Jpeg.Baseline.Testorig420, - TestImages.Jpeg.Baseline.Jpeg420Small, - TestImages.Jpeg.Issues.Fuzz.AccessViolationException922, - TestImages.Jpeg.Baseline.Jpeg444, - TestImages.Jpeg.Baseline.Jpeg422, - TestImages.Jpeg.Baseline.Bad.BadEOF, - TestImages.Jpeg.Baseline.MultiScanBaselineCMYK, - TestImages.Jpeg.Baseline.YcckSubsample1222, - TestImages.Jpeg.Baseline.Bad.BadRST, - TestImages.Jpeg.Issues.MultiHuffmanBaseline394, - TestImages.Jpeg.Issues.ExifDecodeOutOfRange694, - TestImages.Jpeg.Issues.InvalidEOI695, - TestImages.Jpeg.Issues.ExifResizeOutOfRange696, - TestImages.Jpeg.Issues.InvalidAPP0721, - TestImages.Jpeg.Issues.ExifGetString750Load, - TestImages.Jpeg.Issues.ExifGetString750Transform, - TestImages.Jpeg.Issues.BadSubSampling1076, + { + TestImages.Jpeg.Baseline.Calliphora, + TestImages.Jpeg.Baseline.Cmyk, + TestImages.Jpeg.Baseline.Ycck, + TestImages.Jpeg.Baseline.Jpeg400, + TestImages.Jpeg.Baseline.Turtle420, + TestImages.Jpeg.Baseline.Testorig420, + TestImages.Jpeg.Baseline.Jpeg420Small, + TestImages.Jpeg.Issues.Fuzz.AccessViolationException922, + TestImages.Jpeg.Baseline.Jpeg444, + TestImages.Jpeg.Baseline.Jpeg422, + TestImages.Jpeg.Baseline.Bad.BadEOF, + TestImages.Jpeg.Baseline.MultiScanBaselineCMYK, + TestImages.Jpeg.Baseline.YcckSubsample1222, + TestImages.Jpeg.Baseline.Bad.BadRST, + TestImages.Jpeg.Issues.MultiHuffmanBaseline394, + TestImages.Jpeg.Issues.ExifDecodeOutOfRange694, + TestImages.Jpeg.Issues.InvalidEOI695, + TestImages.Jpeg.Issues.ExifResizeOutOfRange696, + TestImages.Jpeg.Issues.InvalidAPP0721, + TestImages.Jpeg.Issues.ExifGetString750Load, + TestImages.Jpeg.Issues.ExifGetString750Transform, + TestImages.Jpeg.Issues.BadSubSampling1076, - // LibJpeg can open this despite the invalid density units. - TestImages.Jpeg.Issues.Fuzz.ArgumentOutOfRangeException825B, + // LibJpeg can open this despite the invalid density units. + TestImages.Jpeg.Issues.Fuzz.ArgumentOutOfRangeException825B, - // LibJpeg can open this despite incorrect colorspace metadata. - TestImages.Jpeg.Issues.IncorrectColorspace855, + // LibJpeg can open this despite incorrect colorspace metadata. + TestImages.Jpeg.Issues.IncorrectColorspace855, - // High depth images - TestImages.Jpeg.Baseline.Testorig12bit, - }; + // High depth images + TestImages.Jpeg.Baseline.Testorig12bit, + }; public static string[] ProgressiveTestJpegs = - { - TestImages.Jpeg.Progressive.Fb, - TestImages.Jpeg.Progressive.Progress, - TestImages.Jpeg.Progressive.Festzug, - TestImages.Jpeg.Progressive.Bad.BadEOF, - TestImages.Jpeg.Issues.BadCoeffsProgressive178, - TestImages.Jpeg.Issues.MissingFF00ProgressiveGirl159, - TestImages.Jpeg.Issues.MissingFF00ProgressiveBedroom159, - TestImages.Jpeg.Issues.BadZigZagProgressive385, - TestImages.Jpeg.Progressive.Bad.ExifUndefType, - TestImages.Jpeg.Issues.NoEoiProgressive517, - TestImages.Jpeg.Issues.BadRstProgressive518, - TestImages.Jpeg.Issues.DhtHasWrongLength624, - TestImages.Jpeg.Issues.OrderedInterleavedProgressive723A, - TestImages.Jpeg.Issues.OrderedInterleavedProgressive723B, - TestImages.Jpeg.Issues.OrderedInterleavedProgressive723C - }; + { + TestImages.Jpeg.Progressive.Fb, + TestImages.Jpeg.Progressive.Progress, + TestImages.Jpeg.Progressive.Festzug, + TestImages.Jpeg.Progressive.Bad.BadEOF, + TestImages.Jpeg.Issues.BadCoeffsProgressive178, + TestImages.Jpeg.Issues.MissingFF00ProgressiveGirl159, + TestImages.Jpeg.Issues.MissingFF00ProgressiveBedroom159, + TestImages.Jpeg.Issues.BadZigZagProgressive385, + TestImages.Jpeg.Progressive.Bad.ExifUndefType, + TestImages.Jpeg.Issues.NoEoiProgressive517, + TestImages.Jpeg.Issues.BadRstProgressive518, + TestImages.Jpeg.Issues.DhtHasWrongLength624, + TestImages.Jpeg.Issues.OrderedInterleavedProgressive723A, + TestImages.Jpeg.Issues.OrderedInterleavedProgressive723B, + TestImages.Jpeg.Issues.OrderedInterleavedProgressive723C + }; + + public static string[] UnsupportedTestJpegs = + { + // Invalid componentCount value (2 or > 4) + TestImages.Jpeg.Issues.Fuzz.NullReferenceException823, + TestImages.Jpeg.Issues.MalformedUnsupportedComponentCount, + + // Arithmetic coding + TestImages.Jpeg.Baseline.ArithmeticCoding, + TestImages.Jpeg.Baseline.ArithmeticCodingProgressive, + + // Lossless jpeg + TestImages.Jpeg.Baseline.Lossless + }; public static string[] UnrecoverableTestJpegs = { @@ -70,7 +84,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg TestImages.Jpeg.Issues.Fuzz.AccessViolationException798, TestImages.Jpeg.Issues.Fuzz.DivideByZeroException821, TestImages.Jpeg.Issues.Fuzz.DivideByZeroException822, - TestImages.Jpeg.Issues.Fuzz.NullReferenceException823, TestImages.Jpeg.Issues.Fuzz.IndexOutOfRangeException824A, TestImages.Jpeg.Issues.Fuzz.IndexOutOfRangeException824B, TestImages.Jpeg.Issues.Fuzz.IndexOutOfRangeException824D, @@ -91,28 +104,27 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg TestImages.Jpeg.Issues.Fuzz.IndexOutOfRangeException824C, }; - private static readonly Dictionary CustomToleranceValues = - new Dictionary - { - // Baseline: - [TestImages.Jpeg.Baseline.Calliphora] = 0.00002f / 100, - [TestImages.Jpeg.Baseline.Bad.BadEOF] = 0.38f / 100, - [TestImages.Jpeg.Baseline.Bad.BadRST] = 0.0589f / 100, + private static readonly Dictionary CustomToleranceValues = new() + { + // Baseline: + [TestImages.Jpeg.Baseline.Calliphora] = 0.00002f / 100, + [TestImages.Jpeg.Baseline.Bad.BadEOF] = 0.38f / 100, + [TestImages.Jpeg.Baseline.Bad.BadRST] = 0.0589f / 100, - [TestImages.Jpeg.Baseline.Jpeg422] = 0.0013f / 100, - [TestImages.Jpeg.Baseline.Testorig420] = 0.38f / 100, - [TestImages.Jpeg.Baseline.Jpeg420Small] = 0.287f / 100, - [TestImages.Jpeg.Baseline.Turtle420] = 1.0f / 100, + [TestImages.Jpeg.Baseline.Jpeg422] = 0.0013f / 100, + [TestImages.Jpeg.Baseline.Testorig420] = 0.38f / 100, + [TestImages.Jpeg.Baseline.Jpeg420Small] = 0.287f / 100, + [TestImages.Jpeg.Baseline.Turtle420] = 1.0f / 100, - // Progressive: - [TestImages.Jpeg.Issues.MissingFF00ProgressiveGirl159] = 0.34f / 100, - [TestImages.Jpeg.Issues.BadCoeffsProgressive178] = 0.38f / 100, - [TestImages.Jpeg.Progressive.Bad.BadEOF] = 0.3f / 100, - [TestImages.Jpeg.Progressive.Festzug] = 0.02f / 100, - [TestImages.Jpeg.Progressive.Fb] = 0.16f / 100, - [TestImages.Jpeg.Progressive.Progress] = 0.31f / 100, - [TestImages.Jpeg.Issues.BadZigZagProgressive385] = 0.23f / 100, - [TestImages.Jpeg.Progressive.Bad.ExifUndefType] = 0.011f / 100, - }; + // Progressive: + [TestImages.Jpeg.Issues.MissingFF00ProgressiveGirl159] = 0.34f / 100, + [TestImages.Jpeg.Issues.BadCoeffsProgressive178] = 0.38f / 100, + [TestImages.Jpeg.Progressive.Bad.BadEOF] = 0.3f / 100, + [TestImages.Jpeg.Progressive.Festzug] = 0.02f / 100, + [TestImages.Jpeg.Progressive.Fb] = 0.16f / 100, + [TestImages.Jpeg.Progressive.Progress] = 0.31f / 100, + [TestImages.Jpeg.Issues.BadZigZagProgressive385] = 0.23f / 100, + [TestImages.Jpeg.Progressive.Bad.ExifUndefType] = 0.011f / 100, + }; } } diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs index 695a10ec3..7a2446959 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs @@ -190,10 +190,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg } [Theory] - [WithFile(TestImages.Jpeg.Baseline.ArithmeticCoding, PixelTypes.Rgba32)] - [WithFile(TestImages.Jpeg.Baseline.ArithmeticCodingProgressive, PixelTypes.Rgba32)] - [WithFile(TestImages.Jpeg.Baseline.Lossless, PixelTypes.Rgba32)] - [WithFile(TestImages.Jpeg.Issues.MalformedUnsupportedComponentCount, PixelTypes.Rgba32)] + [WithFileCollection(nameof(UnsupportedTestJpegs), PixelTypes.Rgba32)] public void ThrowsNotSupported_WithUnsupportedJpegs(TestImageProvider provider) where TPixel : unmanaged, IPixel {