From b1f6af6b0db33915ba05dc303587c4d00c6027d7 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 26 Mar 2018 18:45:46 -0700 Subject: [PATCH 01/32] Simplify Equals override --- src/ImageSharp/ColorSpaces/CieLch.cs | 7 +---- src/ImageSharp/ColorSpaces/CieLchuv.cs | 7 +---- src/ImageSharp/ColorSpaces/CieLuv.cs | 7 +---- .../CieXyChromaticityCoordinates.cs | 7 +---- src/ImageSharp/ColorSpaces/CieXyy.cs | 7 +---- src/ImageSharp/ColorSpaces/CieXyz.cs | 7 +---- src/ImageSharp/ColorSpaces/Cmyk.cs | 7 +---- .../RGBPrimariesChromaticityCoordinates.cs | 9 ++---- .../Implementation/Rgb/RgbWorkingSpace.cs | 7 +---- src/ImageSharp/ColorSpaces/Hsl.cs | 7 +---- src/ImageSharp/ColorSpaces/Hsv.cs | 7 +---- src/ImageSharp/ColorSpaces/HunterLab.cs | 7 +---- src/ImageSharp/ColorSpaces/LinearRgb.cs | 7 +---- src/ImageSharp/ColorSpaces/Lms.cs | 7 +---- src/ImageSharp/ColorSpaces/Rgb.cs | 7 +---- src/ImageSharp/ColorSpaces/YCbCr.cs | 7 +---- src/ImageSharp/Formats/Gif/PackedField.cs | 4 +-- .../Formats/Jpeg/Common/Block8x8.cs | 7 +---- .../Jpeg/Common/Decoder/AdobeMarker.cs | 7 +---- .../Formats/Jpeg/Common/Decoder/JFifMarker.cs | 9 ++---- src/ImageSharp/MetaData/ImageProperty.cs | 4 +-- .../MetaData/Profiles/Exif/ExifValue.cs | 28 ++++--------------- .../Profiles/ICC/Curves/IccParametricCurve.cs | 2 +- .../Profiles/ICC/Curves/IccResponseCurve.cs | 2 +- src/ImageSharp/PixelFormats/Alpha8.cs | 2 +- src/ImageSharp/PixelFormats/Bgr24.cs | 2 +- src/ImageSharp/PixelFormats/Bgra32.cs | 2 +- src/ImageSharp/PixelFormats/Bgra4444.cs | 2 +- src/ImageSharp/PixelFormats/Bgra5551.cs | 2 +- src/ImageSharp/PixelFormats/HalfVector4.cs | 2 +- .../PixelFormats/NormalizedByte2.cs | 2 +- .../PixelFormats/NormalizedByte4.cs | 2 +- .../PixelFormats/NormalizedShort4.cs | 2 +- src/ImageSharp/PixelFormats/Rgb24.cs | 2 +- src/ImageSharp/PixelFormats/RgbaVector.cs | 2 +- src/ImageSharp/PixelFormats/Short2.cs | 2 +- src/ImageSharp/PixelFormats/Short4.cs | 2 +- src/ImageSharp/Primitives/DenseMatrix{T}.cs | 2 +- 38 files changed, 44 insertions(+), 161 deletions(-) diff --git a/src/ImageSharp/ColorSpaces/CieLch.cs b/src/ImageSharp/ColorSpaces/CieLch.cs index 94443fd863..1b9cf9c2b7 100644 --- a/src/ImageSharp/ColorSpaces/CieLch.cs +++ b/src/ImageSharp/ColorSpaces/CieLch.cs @@ -194,12 +194,7 @@ namespace SixLabors.ImageSharp.ColorSpaces [MethodImpl(MethodImplOptions.AggressiveInlining)] public override bool Equals(object obj) { - if (obj is CieLch) - { - return this.Equals((CieLch)obj); - } - - return false; + return obj is CieLch other && this.Equals(other); } /// diff --git a/src/ImageSharp/ColorSpaces/CieLchuv.cs b/src/ImageSharp/ColorSpaces/CieLchuv.cs index 705b770d35..7ec27806d8 100644 --- a/src/ImageSharp/ColorSpaces/CieLchuv.cs +++ b/src/ImageSharp/ColorSpaces/CieLchuv.cs @@ -194,12 +194,7 @@ namespace SixLabors.ImageSharp.ColorSpaces [MethodImpl(MethodImplOptions.AggressiveInlining)] public override bool Equals(object obj) { - if (obj is CieLchuv) - { - return this.Equals((CieLchuv)obj); - } - - return false; + return obj is CieLchuv other && this.Equals(other); } /// diff --git a/src/ImageSharp/ColorSpaces/CieLuv.cs b/src/ImageSharp/ColorSpaces/CieLuv.cs index b0ae048ab7..e46b736a75 100644 --- a/src/ImageSharp/ColorSpaces/CieLuv.cs +++ b/src/ImageSharp/ColorSpaces/CieLuv.cs @@ -196,12 +196,7 @@ namespace SixLabors.ImageSharp.ColorSpaces [MethodImpl(MethodImplOptions.AggressiveInlining)] public override bool Equals(object obj) { - if (obj is CieLuv) - { - return this.Equals((CieLuv)obj); - } - - return false; + return obj is CieLuv other && this.Equals(other); } /// diff --git a/src/ImageSharp/ColorSpaces/CieXyChromaticityCoordinates.cs b/src/ImageSharp/ColorSpaces/CieXyChromaticityCoordinates.cs index d0a70dd191..d54de43bbb 100644 --- a/src/ImageSharp/ColorSpaces/CieXyChromaticityCoordinates.cs +++ b/src/ImageSharp/ColorSpaces/CieXyChromaticityCoordinates.cs @@ -132,12 +132,7 @@ namespace SixLabors.ImageSharp.ColorSpaces [MethodImpl(MethodImplOptions.AggressiveInlining)] public override bool Equals(object obj) { - if (obj is CieXyChromaticityCoordinates) - { - return this.Equals((CieXyChromaticityCoordinates)obj); - } - - return false; + return obj is CieXyChromaticityCoordinates other && this.Equals(other); } /// diff --git a/src/ImageSharp/ColorSpaces/CieXyy.cs b/src/ImageSharp/ColorSpaces/CieXyy.cs index 751830a0ba..9633f83ad0 100644 --- a/src/ImageSharp/ColorSpaces/CieXyy.cs +++ b/src/ImageSharp/ColorSpaces/CieXyy.cs @@ -148,12 +148,7 @@ namespace SixLabors.ImageSharp.ColorSpaces [MethodImpl(MethodImplOptions.AggressiveInlining)] public override bool Equals(object obj) { - if (obj is CieXyy) - { - return this.Equals((CieXyy)obj); - } - - return false; + return obj is CieXyy other && this.Equals(other); } /// diff --git a/src/ImageSharp/ColorSpaces/CieXyz.cs b/src/ImageSharp/ColorSpaces/CieXyz.cs index 0f1866009b..eedfed0798 100644 --- a/src/ImageSharp/ColorSpaces/CieXyz.cs +++ b/src/ImageSharp/ColorSpaces/CieXyz.cs @@ -148,12 +148,7 @@ namespace SixLabors.ImageSharp.ColorSpaces [MethodImpl(MethodImplOptions.AggressiveInlining)] public override bool Equals(object obj) { - if (obj is CieXyz) - { - return this.Equals((CieXyz)obj); - } - - return false; + return obj is CieXyz other && this.Equals(other); } /// diff --git a/src/ImageSharp/ColorSpaces/Cmyk.cs b/src/ImageSharp/ColorSpaces/Cmyk.cs index 2eb148a8c3..2e44ea920a 100644 --- a/src/ImageSharp/ColorSpaces/Cmyk.cs +++ b/src/ImageSharp/ColorSpaces/Cmyk.cs @@ -150,12 +150,7 @@ namespace SixLabors.ImageSharp.ColorSpaces [MethodImpl(MethodImplOptions.AggressiveInlining)] public override bool Equals(object obj) { - if (obj is Cmyk) - { - return this.Equals((Cmyk)obj); - } - - return false; + return obj is Cmyk other && this.Equals(other); } /// diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/RGBPrimariesChromaticityCoordinates.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/RGBPrimariesChromaticityCoordinates.cs index d279aba850..8afe2ffa05 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/RGBPrimariesChromaticityCoordinates.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/RGBPrimariesChromaticityCoordinates.cs @@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.RgbColorSap /// Represents the chromaticity coordinates of RGB primaries. /// One of the specifiers of . /// - internal struct RgbPrimariesChromaticityCoordinates : IEquatable + internal readonly struct RgbPrimariesChromaticityCoordinates : IEquatable { /// /// Initializes a new instance of the struct. @@ -76,12 +76,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.RgbColorSap /// public override bool Equals(object obj) { - if (obj is RgbPrimariesChromaticityCoordinates) - { - return this.Equals((RgbPrimariesChromaticityCoordinates)obj); - } - - return false; + return obj is RgbPrimariesChromaticityCoordinates other && this.Equals(other); } /// diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/RgbWorkingSpace.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/RgbWorkingSpace.cs index 5a5c39647f..530c016916 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/RgbWorkingSpace.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/RgbWorkingSpace.cs @@ -73,12 +73,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.RgbColorSap /// public override bool Equals(object obj) { - if (obj is RgbWorkingSpace) - { - return this.Equals((RgbWorkingSpace)obj); - } - - return false; + return obj is RgbWorkingSpace other && this.Equals(other); } /// diff --git a/src/ImageSharp/ColorSpaces/Hsl.cs b/src/ImageSharp/ColorSpaces/Hsl.cs index 1944ac0c6b..3b2ceae27f 100644 --- a/src/ImageSharp/ColorSpaces/Hsl.cs +++ b/src/ImageSharp/ColorSpaces/Hsl.cs @@ -150,12 +150,7 @@ namespace SixLabors.ImageSharp.ColorSpaces [MethodImpl(MethodImplOptions.AggressiveInlining)] public override bool Equals(object obj) { - if (obj is Hsl) - { - return this.Equals((Hsl)obj); - } - - return false; + return obj is Hsl other && this.Equals(other); } /// diff --git a/src/ImageSharp/ColorSpaces/Hsv.cs b/src/ImageSharp/ColorSpaces/Hsv.cs index fdfbfe5dd1..f646eb29d0 100644 --- a/src/ImageSharp/ColorSpaces/Hsv.cs +++ b/src/ImageSharp/ColorSpaces/Hsv.cs @@ -202,12 +202,7 @@ namespace SixLabors.ImageSharp.ColorSpaces [MethodImpl(MethodImplOptions.AggressiveInlining)] public override bool Equals(object obj) { - if (obj is Hsv) - { - return this.Equals((Hsv)obj); - } - - return false; + return obj is Hsv other && this.Equals(other); } /// diff --git a/src/ImageSharp/ColorSpaces/HunterLab.cs b/src/ImageSharp/ColorSpaces/HunterLab.cs index de42518d76..4ace27def9 100644 --- a/src/ImageSharp/ColorSpaces/HunterLab.cs +++ b/src/ImageSharp/ColorSpaces/HunterLab.cs @@ -190,12 +190,7 @@ namespace SixLabors.ImageSharp.ColorSpaces [MethodImpl(MethodImplOptions.AggressiveInlining)] public override bool Equals(object obj) { - if (obj is HunterLab) - { - return this.Equals((HunterLab)obj); - } - - return false; + return obj is HunterLab other && this.Equals(other); } /// diff --git a/src/ImageSharp/ColorSpaces/LinearRgb.cs b/src/ImageSharp/ColorSpaces/LinearRgb.cs index b8c446285a..f2dc297a01 100644 --- a/src/ImageSharp/ColorSpaces/LinearRgb.cs +++ b/src/ImageSharp/ColorSpaces/LinearRgb.cs @@ -182,12 +182,7 @@ namespace SixLabors.ImageSharp.ColorSpaces [MethodImpl(MethodImplOptions.AggressiveInlining)] public override bool Equals(object obj) { - if (obj is LinearRgb) - { - return this.Equals((LinearRgb)obj); - } - - return false; + return obj is LinearRgb other && this.Equals(other); } /// diff --git a/src/ImageSharp/ColorSpaces/Lms.cs b/src/ImageSharp/ColorSpaces/Lms.cs index 72ac16f213..09c20269ab 100644 --- a/src/ImageSharp/ColorSpaces/Lms.cs +++ b/src/ImageSharp/ColorSpaces/Lms.cs @@ -149,12 +149,7 @@ namespace SixLabors.ImageSharp.ColorSpaces [MethodImpl(MethodImplOptions.AggressiveInlining)] public override bool Equals(object obj) { - if (obj is Lms) - { - return this.Equals((Lms)obj); - } - - return false; + return obj is Lms other && this.Equals(other); } /// diff --git a/src/ImageSharp/ColorSpaces/Rgb.cs b/src/ImageSharp/ColorSpaces/Rgb.cs index ac86cfbf06..1282394670 100644 --- a/src/ImageSharp/ColorSpaces/Rgb.cs +++ b/src/ImageSharp/ColorSpaces/Rgb.cs @@ -204,12 +204,7 @@ namespace SixLabors.ImageSharp.ColorSpaces [MethodImpl(MethodImplOptions.AggressiveInlining)] public override bool Equals(object obj) { - if (obj is Rgb) - { - return this.Equals((Rgb)obj); - } - - return false; + return obj is Rgb other && this.Equals(other); } /// diff --git a/src/ImageSharp/ColorSpaces/YCbCr.cs b/src/ImageSharp/ColorSpaces/YCbCr.cs index 44a0b245d5..a6e27de94b 100644 --- a/src/ImageSharp/ColorSpaces/YCbCr.cs +++ b/src/ImageSharp/ColorSpaces/YCbCr.cs @@ -152,12 +152,7 @@ namespace SixLabors.ImageSharp.ColorSpaces [MethodImpl(MethodImplOptions.AggressiveInlining)] public override bool Equals(object obj) { - if (obj is YCbCr) - { - return this.Equals((YCbCr)obj); - } - - return false; + return obj is YCbCr other && this.Equals(other); } /// diff --git a/src/ImageSharp/Formats/Gif/PackedField.cs b/src/ImageSharp/Formats/Gif/PackedField.cs index 28a415e2b8..969449a9f9 100644 --- a/src/ImageSharp/Formats/Gif/PackedField.cs +++ b/src/ImageSharp/Formats/Gif/PackedField.cs @@ -169,9 +169,7 @@ namespace SixLabors.ImageSharp.Formats.Gif /// public override bool Equals(object obj) { - PackedField? field = obj as PackedField?; - - return this.Byte == field?.Byte; + return obj is PackedField other && this.Equals(other); } /// diff --git a/src/ImageSharp/Formats/Jpeg/Common/Block8x8.cs b/src/ImageSharp/Formats/Jpeg/Common/Block8x8.cs index 11a456ef9b..06fdb2c76d 100644 --- a/src/ImageSharp/Formats/Jpeg/Common/Block8x8.cs +++ b/src/ImageSharp/Formats/Jpeg/Common/Block8x8.cs @@ -273,12 +273,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common /// public override bool Equals(object obj) { - if (ReferenceEquals(null, obj)) - { - return false; - } - - return obj is Block8x8 && this.Equals((Block8x8)obj); + return obj is Block8x8 other && this.Equals(other); } /// diff --git a/src/ImageSharp/Formats/Jpeg/Common/Decoder/AdobeMarker.cs b/src/ImageSharp/Formats/Jpeg/Common/Decoder/AdobeMarker.cs index d55e36bd48..40059c5a0f 100644 --- a/src/ImageSharp/Formats/Jpeg/Common/Decoder/AdobeMarker.cs +++ b/src/ImageSharp/Formats/Jpeg/Common/Decoder/AdobeMarker.cs @@ -94,12 +94,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder /// public override bool Equals(object obj) { - if (ReferenceEquals(null, obj)) - { - return false; - } - - return obj is AdobeMarker && this.Equals((AdobeMarker)obj); + return obj is AdobeMarker other && this.Equals(other); } /// diff --git a/src/ImageSharp/Formats/Jpeg/Common/Decoder/JFifMarker.cs b/src/ImageSharp/Formats/Jpeg/Common/Decoder/JFifMarker.cs index c856fd04a6..afe4794a23 100644 --- a/src/ImageSharp/Formats/Jpeg/Common/Decoder/JFifMarker.cs +++ b/src/ImageSharp/Formats/Jpeg/Common/Decoder/JFifMarker.cs @@ -87,7 +87,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder } } - marker = default(JFifMarker); + marker = default; return false; } @@ -104,12 +104,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder /// public override bool Equals(object obj) { - if (ReferenceEquals(null, obj)) - { - return false; - } - - return obj is JFifMarker && this.Equals((JFifMarker)obj); + return obj is JFifMarker other && this.Equals(other); } /// diff --git a/src/ImageSharp/MetaData/ImageProperty.cs b/src/ImageSharp/MetaData/ImageProperty.cs index c60aaecfba..a663573763 100644 --- a/src/ImageSharp/MetaData/ImageProperty.cs +++ b/src/ImageSharp/MetaData/ImageProperty.cs @@ -110,9 +110,7 @@ namespace SixLabors.ImageSharp.MetaData /// public override bool Equals(object obj) { - ImageProperty other = obj as ImageProperty; - - return this.Equals(other); + return obj is ImageProperty other && Equals(other); } /// diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs index 3c2b23f37f..fd00c8585e 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs @@ -77,37 +77,24 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif /// /// Gets the data type of the exif value. /// - public ExifDataType DataType - { - get; - } + public ExifDataType DataType { get; } /// /// Gets a value indicating whether the value is an array. /// - public bool IsArray - { - get; - } + public bool IsArray { get; } /// /// Gets the tag of the exif value. /// - public ExifTag Tag - { - get; - } + public ExifTag Tag { get; } /// /// Gets or sets the value. /// public object Value { - get - { - return this.exifValue; - } - + get => this.exifValue; set { this.CheckValue(value); @@ -217,12 +204,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif /// public override bool Equals(object obj) { - if (ReferenceEquals(this, obj)) - { - return true; - } - - return this.Equals(obj as ExifValue); + return obj is ExifValue other && this.Equals(other); } /// diff --git a/src/ImageSharp/MetaData/Profiles/ICC/Curves/IccParametricCurve.cs b/src/ImageSharp/MetaData/Profiles/ICC/Curves/IccParametricCurve.cs index 46aec49be6..ee8b4c731e 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/Curves/IccParametricCurve.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/Curves/IccParametricCurve.cs @@ -158,7 +158,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc return true; } - return obj is IccParametricCurve && this.Equals((IccParametricCurve)obj); + return obj is IccParametricCurve other && this.Equals(other); } /// diff --git a/src/ImageSharp/MetaData/Profiles/ICC/Curves/IccResponseCurve.cs b/src/ImageSharp/MetaData/Profiles/ICC/Curves/IccResponseCurve.cs index ae9cd84b47..8a7162198b 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/Curves/IccResponseCurve.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/Curves/IccResponseCurve.cs @@ -77,7 +77,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc return true; } - return obj is IccResponseCurve && this.Equals((IccResponseCurve)obj); + return obj is IccResponseCurve other && this.Equals(other); } /// diff --git a/src/ImageSharp/PixelFormats/Alpha8.cs b/src/ImageSharp/PixelFormats/Alpha8.cs index c266035a6b..ad887b7145 100644 --- a/src/ImageSharp/PixelFormats/Alpha8.cs +++ b/src/ImageSharp/PixelFormats/Alpha8.cs @@ -124,7 +124,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// True if the object is equal to the packed vector. public override bool Equals(object obj) { - return (obj is Alpha8) && this.Equals((Alpha8)obj); + return obj is Alpha8 other && this.Equals(other); } /// diff --git a/src/ImageSharp/PixelFormats/Bgr24.cs b/src/ImageSharp/PixelFormats/Bgr24.cs index e210856b36..801edcc0bf 100644 --- a/src/ImageSharp/PixelFormats/Bgr24.cs +++ b/src/ImageSharp/PixelFormats/Bgr24.cs @@ -57,7 +57,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// public override bool Equals(object obj) { - return obj?.GetType() == typeof(Bgr24) && this.Equals((Bgr24)obj); + return obj is Bgr24 other && this.Equals(other); } /// diff --git a/src/ImageSharp/PixelFormats/Bgra32.cs b/src/ImageSharp/PixelFormats/Bgra32.cs index e8469414d3..ec2296844b 100644 --- a/src/ImageSharp/PixelFormats/Bgra32.cs +++ b/src/ImageSharp/PixelFormats/Bgra32.cs @@ -101,7 +101,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - public override bool Equals(object obj) => obj?.GetType() == typeof(Bgra32) && this.Equals((Bgra32)obj); + public override bool Equals(object obj) => obj is Bgra32 other && this.Equals(other); /// public override int GetHashCode() diff --git a/src/ImageSharp/PixelFormats/Bgra4444.cs b/src/ImageSharp/PixelFormats/Bgra4444.cs index c51a872d1a..fd75125503 100644 --- a/src/ImageSharp/PixelFormats/Bgra4444.cs +++ b/src/ImageSharp/PixelFormats/Bgra4444.cs @@ -142,7 +142,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// public override bool Equals(object obj) { - return (obj is Bgra4444) && this.Equals((Bgra4444)obj); + return obj is Bgra4444 other && this.Equals(other); } /// diff --git a/src/ImageSharp/PixelFormats/Bgra5551.cs b/src/ImageSharp/PixelFormats/Bgra5551.cs index 8be4ce82c9..2169949765 100644 --- a/src/ImageSharp/PixelFormats/Bgra5551.cs +++ b/src/ImageSharp/PixelFormats/Bgra5551.cs @@ -142,7 +142,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// public override bool Equals(object obj) { - return (obj is Bgra5551) && this.Equals((Bgra5551)obj); + return obj is Bgra5551 other && this.Equals(other); } /// diff --git a/src/ImageSharp/PixelFormats/HalfVector4.cs b/src/ImageSharp/PixelFormats/HalfVector4.cs index 87a1c9a498..8356624871 100644 --- a/src/ImageSharp/PixelFormats/HalfVector4.cs +++ b/src/ImageSharp/PixelFormats/HalfVector4.cs @@ -172,7 +172,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// public override bool Equals(object obj) { - return (obj is HalfVector4) && this.Equals((HalfVector4)obj); + return obj is HalfVector4 other && this.Equals(other); } /// diff --git a/src/ImageSharp/PixelFormats/NormalizedByte2.cs b/src/ImageSharp/PixelFormats/NormalizedByte2.cs index 9a69f6ab36..e38e3a6bfd 100644 --- a/src/ImageSharp/PixelFormats/NormalizedByte2.cs +++ b/src/ImageSharp/PixelFormats/NormalizedByte2.cs @@ -175,7 +175,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// public override bool Equals(object obj) { - return (obj is NormalizedByte2) && this.Equals((NormalizedByte2)obj); + return obj is NormalizedByte2 other && this.Equals(other); } /// diff --git a/src/ImageSharp/PixelFormats/NormalizedByte4.cs b/src/ImageSharp/PixelFormats/NormalizedByte4.cs index 920f92cae7..8568cd3fc6 100644 --- a/src/ImageSharp/PixelFormats/NormalizedByte4.cs +++ b/src/ImageSharp/PixelFormats/NormalizedByte4.cs @@ -168,7 +168,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// public override bool Equals(object obj) { - return (obj is NormalizedByte4) && this.Equals((NormalizedByte4)obj); + return obj is NormalizedByte4 other && this.Equals(other); } /// diff --git a/src/ImageSharp/PixelFormats/NormalizedShort4.cs b/src/ImageSharp/PixelFormats/NormalizedShort4.cs index 45f984da0b..94df4ec505 100644 --- a/src/ImageSharp/PixelFormats/NormalizedShort4.cs +++ b/src/ImageSharp/PixelFormats/NormalizedShort4.cs @@ -170,7 +170,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// public override bool Equals(object obj) { - return (obj is NormalizedShort4) && this.Equals((NormalizedShort4)obj); + return obj is NormalizedShort4 other && this.Equals(other); } /// diff --git a/src/ImageSharp/PixelFormats/Rgb24.cs b/src/ImageSharp/PixelFormats/Rgb24.cs index d867d9065e..b82b47a389 100644 --- a/src/ImageSharp/PixelFormats/Rgb24.cs +++ b/src/ImageSharp/PixelFormats/Rgb24.cs @@ -57,7 +57,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// public override bool Equals(object obj) { - return obj?.GetType() == typeof(Rgb24) && this.Equals((Rgb24)obj); + return obj is Rgb24 other && this.Equals(other); } /// diff --git a/src/ImageSharp/PixelFormats/RgbaVector.cs b/src/ImageSharp/PixelFormats/RgbaVector.cs index ba641d590c..a7c112aa63 100644 --- a/src/ImageSharp/PixelFormats/RgbaVector.cs +++ b/src/ImageSharp/PixelFormats/RgbaVector.cs @@ -290,7 +290,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// public override bool Equals(object obj) { - return (obj is RgbaVector) && this.Equals((RgbaVector)obj); + return obj is RgbaVector other && this.Equals(other); } /// diff --git a/src/ImageSharp/PixelFormats/Short2.cs b/src/ImageSharp/PixelFormats/Short2.cs index 1355a94135..6b95a3e042 100644 --- a/src/ImageSharp/PixelFormats/Short2.cs +++ b/src/ImageSharp/PixelFormats/Short2.cs @@ -171,7 +171,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// public override bool Equals(object obj) { - return (obj is Short2) && this.Equals((Short2)obj); + return obj is Short2 other && this.Equals(other); } /// diff --git a/src/ImageSharp/PixelFormats/Short4.cs b/src/ImageSharp/PixelFormats/Short4.cs index aecb4d2de8..c35e0d6aa9 100644 --- a/src/ImageSharp/PixelFormats/Short4.cs +++ b/src/ImageSharp/PixelFormats/Short4.cs @@ -166,7 +166,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// public override bool Equals(object obj) { - return (obj is Short4) && this == (Short4)obj; + return obj is Short4 other && this.Equals(other); } /// diff --git a/src/ImageSharp/Primitives/DenseMatrix{T}.cs b/src/ImageSharp/Primitives/DenseMatrix{T}.cs index 1f459e7cb0..5f3defd118 100644 --- a/src/ImageSharp/Primitives/DenseMatrix{T}.cs +++ b/src/ImageSharp/Primitives/DenseMatrix{T}.cs @@ -207,7 +207,7 @@ namespace SixLabors.ImageSharp.Primitives } /// - public override bool Equals(object obj) => obj is DenseMatrix matrix && this.Equals(matrix); + public override bool Equals(object obj) => obj is DenseMatrix other && this.Equals(other); /// public override int GetHashCode() => this.Data.GetHashCode(); From 647f15e1b07830c48cf2d8b21f16a4930a09e031 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 26 Mar 2018 18:46:44 -0700 Subject: [PATCH 02/32] Annotate additional readonly structures --- .../PdfJsPort/Components/PdfJsFileMarker.cs | 6 +++--- src/ImageSharp/Primitives/Rational.cs | 21 +++++++------------ src/ImageSharp/Primitives/SignedRational.cs | 10 ++++----- 3 files changed, 16 insertions(+), 21 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsFileMarker.cs b/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsFileMarker.cs index d6ff1e9eda..8e51c0b7cc 100644 --- a/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsFileMarker.cs +++ b/src/ImageSharp/Formats/Jpeg/PdfJsPort/Components/PdfJsFileMarker.cs @@ -6,7 +6,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components /// /// Represents a jpeg file marker /// - internal struct PdfJsFileMarker + internal readonly struct PdfJsFileMarker { /// /// Initializes a new instance of the struct. @@ -34,9 +34,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort.Components } /// - /// Gets or sets a value indicating whether the current marker is invalid + /// Gets a value indicating whether the current marker is invalid /// - public bool Invalid { get; set; } + public bool Invalid { get; } /// /// Gets the position of the marker within a stream diff --git a/src/ImageSharp/Primitives/Rational.cs b/src/ImageSharp/Primitives/Rational.cs index 6678eb9540..fa3961ffa8 100644 --- a/src/ImageSharp/Primitives/Rational.cs +++ b/src/ImageSharp/Primitives/Rational.cs @@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.Primitives /// /// This is a very simplified implementation of a rational number designed for use with metadata only. /// - public struct Rational : IEquatable + public readonly struct Rational : IEquatable { /// /// Initializes a new instance of the struct. @@ -41,7 +41,7 @@ namespace SixLabors.ImageSharp.Primitives /// Specified if the rational should be simplified. public Rational(uint numerator, uint denominator, bool simplify) { - LongRational rational = new LongRational(numerator, denominator, simplify); + var rational = new LongRational(numerator, denominator, simplify); this.Numerator = (uint)rational.Numerator; this.Denominator = (uint)rational.Denominator; @@ -63,7 +63,7 @@ namespace SixLabors.ImageSharp.Primitives /// Whether to use the best possible precision when parsing the value. public Rational(double value, bool bestPrecision) { - LongRational rational = new LongRational(Math.Abs(value), bestPrecision); + var rational = new LongRational(Math.Abs(value), bestPrecision); this.Numerator = (uint)rational.Numerator; this.Denominator = (uint)rational.Denominator; @@ -129,19 +129,14 @@ namespace SixLabors.ImageSharp.Primitives /// public override bool Equals(object obj) { - if (obj is Rational) - { - return this.Equals((Rational)obj); - } - - return false; + return obj is Rational other && this.Equals(other); } /// public bool Equals(Rational other) { - LongRational left = new LongRational(this.Numerator, this.Denominator); - LongRational right = new LongRational(other.Numerator, other.Denominator); + var left = new LongRational(this.Numerator, this.Denominator); + var right = new LongRational(other.Numerator, other.Denominator); return left.Equals(right); } @@ -149,7 +144,7 @@ namespace SixLabors.ImageSharp.Primitives /// public override int GetHashCode() { - LongRational self = new LongRational(this.Numerator, this.Denominator); + var self = new LongRational(this.Numerator, this.Denominator); return self.GetHashCode(); } @@ -180,7 +175,7 @@ namespace SixLabors.ImageSharp.Primitives /// The public string ToString(IFormatProvider provider) { - LongRational rational = new LongRational(this.Numerator, this.Denominator); + var rational = new LongRational(this.Numerator, this.Denominator); return rational.ToString(provider); } } diff --git a/src/ImageSharp/Primitives/SignedRational.cs b/src/ImageSharp/Primitives/SignedRational.cs index c2a7b3e234..955e9db5e7 100644 --- a/src/ImageSharp/Primitives/SignedRational.cs +++ b/src/ImageSharp/Primitives/SignedRational.cs @@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.Primitives /// /// This is a very simplified implementation of a rational number designed for use with metadata only. /// - public struct SignedRational : IEquatable + public readonly struct SignedRational : IEquatable { /// /// Initializes a new instance of the struct. @@ -41,7 +41,7 @@ namespace SixLabors.ImageSharp.Primitives /// Specified if the rational should be simplified. public SignedRational(int numerator, int denominator, bool simplify) { - LongRational rational = new LongRational(numerator, denominator, simplify); + var rational = new LongRational(numerator, denominator, simplify); this.Numerator = (int)rational.Numerator; this.Denominator = (int)rational.Denominator; @@ -140,8 +140,8 @@ namespace SixLabors.ImageSharp.Primitives /// public bool Equals(SignedRational other) { - LongRational left = new LongRational(this.Numerator, this.Denominator); - LongRational right = new LongRational(other.Numerator, other.Denominator); + var left = new LongRational(this.Numerator, this.Denominator); + var right = new LongRational(other.Numerator, other.Denominator); return left.Equals(right); } @@ -180,7 +180,7 @@ namespace SixLabors.ImageSharp.Primitives /// The public string ToString(IFormatProvider provider) { - LongRational rational = new LongRational(this.Numerator, this.Denominator); + var rational = new LongRational(this.Numerator, this.Denominator); return rational.ToString(provider); } } From 7194abe29348dd54548d0fbec2da0c8698ca3d2f Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 26 Mar 2018 19:01:47 -0700 Subject: [PATCH 03/32] Omit types when infererable from the left or right hand sides --- src/ImageSharp/ColorSpaces/CieLab.cs | 2 +- .../MetaData/Profiles/Exif/ExifReader.cs | 28 +++++++------------ src/ImageSharp/PixelFormats/Argb32.cs | 2 +- .../PixelFormats/ColorBuilder{TPixel}.cs | 6 ++-- src/ImageSharp/PixelFormats/HalfTypeHelper.cs | 4 +-- .../PixelFormats/NamedColors{TPixel}.cs | 2 +- src/ImageSharp/Primitives/LongRational.cs | 4 +-- src/ImageSharp/Primitives/SignedRational.cs | 11 ++------ 8 files changed, 23 insertions(+), 36 deletions(-) diff --git a/src/ImageSharp/ColorSpaces/CieLab.cs b/src/ImageSharp/ColorSpaces/CieLab.cs index cb08d08bf9..ce5c6c1186 100644 --- a/src/ImageSharp/ColorSpaces/CieLab.cs +++ b/src/ImageSharp/ColorSpaces/CieLab.cs @@ -23,7 +23,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// Represents a that has L, A, B values set to zero. /// - public static readonly CieLab Empty = default(CieLab); + public static readonly CieLab Empty = default; /// /// The backing vector for SIMD support. diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs index 8a7b1f7d7e..78e39d8d49 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs @@ -33,20 +33,12 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif /// /// Gets the thumbnail length in the byte stream /// - public uint ThumbnailLength - { - get; - private set; - } + public uint ThumbnailLength { get; private set; } /// /// Gets the thumbnail offset position in the byte stream /// - public uint ThumbnailOffset - { - get; - private set; - } + public uint ThumbnailOffset { get; private set; } /// /// Gets the remaining length. @@ -124,8 +116,8 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif int dataTypeSize = (int)ExifValue.GetSize(dataType); int length = data.Length / dataTypeSize; - TDataType[] result = new TDataType[length]; - byte[] buffer = new byte[dataTypeSize]; + var result = new TDataType[length]; + var buffer = new byte[dataTypeSize]; for (int i = 0; i < length; i++) { @@ -423,7 +415,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif { if (!this.ValidateArray(data, 8)) { - return default(double); + return default; } return BitConverter.ToDouble(data, 0); @@ -433,7 +425,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif { if (!this.ValidateArray(data, 4)) { - return default(uint); + return default; } return BitConverter.ToUInt32(data, 0); @@ -443,7 +435,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif { if (!this.ValidateArray(data, 2)) { - return default(ushort); + return default; } return BitConverter.ToUInt16(data, 0); @@ -453,7 +445,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif { if (!this.ValidateArray(data, 4)) { - return default(float); + return default; } return BitConverter.ToSingle(data, 0); @@ -491,7 +483,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif { if (!this.ValidateArray(data, 8, 4)) { - return default(SignedRational); + return default; } int numerator = BitConverter.ToInt32(data, 0); @@ -504,7 +496,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif { if (!this.ValidateArray(data, 2)) { - return default(short); + return default; } return BitConverter.ToInt16(data, 0); diff --git a/src/ImageSharp/PixelFormats/Argb32.cs b/src/ImageSharp/PixelFormats/Argb32.cs index 33294838e6..dc1f3c08a0 100644 --- a/src/ImageSharp/PixelFormats/Argb32.cs +++ b/src/ImageSharp/PixelFormats/Argb32.cs @@ -347,7 +347,7 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] private static uint Pack(ref Vector3 vector) { - Vector4 value = new Vector4(vector, 1); + var value = new Vector4(vector, 1); return Pack(ref value); } diff --git a/src/ImageSharp/PixelFormats/ColorBuilder{TPixel}.cs b/src/ImageSharp/PixelFormats/ColorBuilder{TPixel}.cs index c646d804ac..184928d0e4 100644 --- a/src/ImageSharp/PixelFormats/ColorBuilder{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/ColorBuilder{TPixel}.cs @@ -32,8 +32,8 @@ namespace SixLabors.ImageSharp.PixelFormats throw new ArgumentException("Hexadecimal string is not in the correct format.", nameof(hex)); } - TPixel result = default(TPixel); - Rgba32 rgba = new Rgba32( + TPixel result = default; + var rgba = new Rgba32( (byte)(packedValue >> 24), (byte)(packedValue >> 16), (byte)(packedValue >> 8), @@ -62,7 +62,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// Returns a that represents the color defined by the provided RGBA values. public static TPixel FromRGBA(byte red, byte green, byte blue, byte alpha) { - TPixel color = default(TPixel); + TPixel color = default; color.PackFromRgba32(new Rgba32(red, green, blue, alpha)); return color; } diff --git a/src/ImageSharp/PixelFormats/HalfTypeHelper.cs b/src/ImageSharp/PixelFormats/HalfTypeHelper.cs index 4d6ef0fb40..cf8b9f4a23 100644 --- a/src/ImageSharp/PixelFormats/HalfTypeHelper.cs +++ b/src/ImageSharp/PixelFormats/HalfTypeHelper.cs @@ -19,7 +19,7 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static ushort Pack(float value) { - Uif uif = new Uif { F = value }; + var uif = new Uif { F = value }; return Pack(uif.I); } @@ -113,7 +113,7 @@ namespace SixLabors.ImageSharp.PixelFormats result = ((((uint)value & 0x8000) << 16) | ((((((uint)value >> 10) & 0x1f) - 15) + 127) << 23)) | (mantissa << 13); } - Uif uif = new Uif { U = result }; + var uif = new Uif { U = result }; return uif.F; } diff --git a/src/ImageSharp/PixelFormats/NamedColors{TPixel}.cs b/src/ImageSharp/PixelFormats/NamedColors{TPixel}.cs index 6a2902f9b1..e27bde8822 100644 --- a/src/ImageSharp/PixelFormats/NamedColors{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/NamedColors{TPixel}.cs @@ -735,7 +735,7 @@ namespace SixLabors.ImageSharp.PixelFormats private static TPixel[] GetWebSafePalette() { Rgba32[] constants = ColorConstants.WebSafeColors; - TPixel[] safe = new TPixel[constants.Length + 1]; + var safe = new TPixel[constants.Length + 1]; Span constantsBytes = constants.AsSpan().NonPortableCast(); PixelOperations.Instance.PackFromRgba32Bytes(constantsBytes, safe, constants.Length); diff --git a/src/ImageSharp/Primitives/LongRational.cs b/src/ImageSharp/Primitives/LongRational.cs index 641a1e5e53..9addf1e18a 100644 --- a/src/ImageSharp/Primitives/LongRational.cs +++ b/src/ImageSharp/Primitives/LongRational.cs @@ -268,9 +268,9 @@ namespace SixLabors.ImageSharp.Primitives return this.Numerator.ToString(provider); } - StringBuilder sb = new StringBuilder(); + var sb = new StringBuilder(); sb.Append(this.Numerator.ToString(provider)); - sb.Append("/"); + sb.Append('/'); sb.Append(this.Denominator.ToString(provider)); return sb.ToString(); } diff --git a/src/ImageSharp/Primitives/SignedRational.cs b/src/ImageSharp/Primitives/SignedRational.cs index 955e9db5e7..5cce98d033 100644 --- a/src/ImageSharp/Primitives/SignedRational.cs +++ b/src/ImageSharp/Primitives/SignedRational.cs @@ -63,7 +63,7 @@ namespace SixLabors.ImageSharp.Primitives /// Whether to use the best possible precision when parsing the value. public SignedRational(double value, bool bestPrecision) { - LongRational rational = new LongRational(value, bestPrecision); + var rational = new LongRational(value, bestPrecision); this.Numerator = (int)rational.Numerator; this.Denominator = (int)rational.Denominator; @@ -129,12 +129,7 @@ namespace SixLabors.ImageSharp.Primitives /// public override bool Equals(object obj) { - if (obj is SignedRational) - { - return this.Equals((SignedRational)obj); - } - - return false; + return obj is SignedRational other && Equals(other); } /// @@ -149,7 +144,7 @@ namespace SixLabors.ImageSharp.Primitives /// public override int GetHashCode() { - LongRational self = new LongRational(this.Numerator, this.Denominator); + var self = new LongRational(this.Numerator, this.Denominator); return self.GetHashCode(); } From dd9b1738eb422386b3a37b34937833e64f71bb3b Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 26 Mar 2018 19:03:49 -0700 Subject: [PATCH 04/32] Make ImageProperty a readonly struct --- src/ImageSharp/MetaData/ImageProperty.cs | 23 ++++--------------- .../MetaData/ImagePropertyTests.cs | 18 ++++++--------- 2 files changed, 11 insertions(+), 30 deletions(-) diff --git a/src/ImageSharp/MetaData/ImageProperty.cs b/src/ImageSharp/MetaData/ImageProperty.cs index a663573763..e4f60e8b33 100644 --- a/src/ImageSharp/MetaData/ImageProperty.cs +++ b/src/ImageSharp/MetaData/ImageProperty.cs @@ -10,10 +10,10 @@ namespace SixLabors.ImageSharp.MetaData /// the copyright information, the date, where the image was created /// or some other information. /// - public class ImageProperty : IEquatable + public readonly struct ImageProperty : IEquatable { /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the struct. /// /// The name of the property. /// The value of the property. @@ -26,7 +26,7 @@ namespace SixLabors.ImageSharp.MetaData } /// - /// Initializes a new instance of the class + /// Initializes a new instance of the struct /// by making a copy from another property. /// /// @@ -71,11 +71,6 @@ namespace SixLabors.ImageSharp.MetaData /// public static bool operator ==(ImageProperty left, ImageProperty right) { - if (ReferenceEquals(left, right)) - { - return true; - } - return left.Equals(right); } @@ -110,7 +105,7 @@ namespace SixLabors.ImageSharp.MetaData /// public override bool Equals(object obj) { - return obj is ImageProperty other && Equals(other); + return obj is ImageProperty other && this.Equals(other); } /// @@ -153,16 +148,6 @@ namespace SixLabors.ImageSharp.MetaData /// An object to compare with this object. public bool Equals(ImageProperty other) { - if (ReferenceEquals(other, null)) - { - return false; - } - - if (ReferenceEquals(this, other)) - { - return true; - } - return this.Name.Equals(other.Name) && Equals(this.Value, other.Value); } } diff --git a/tests/ImageSharp.Tests/MetaData/ImagePropertyTests.cs b/tests/ImageSharp.Tests/MetaData/ImagePropertyTests.cs index 5e15d556c0..b5886522a8 100644 --- a/tests/ImageSharp.Tests/MetaData/ImagePropertyTests.cs +++ b/tests/ImageSharp.Tests/MetaData/ImagePropertyTests.cs @@ -18,13 +18,11 @@ namespace SixLabors.ImageSharp.Tests [Fact] public void AreEqual() { - ImageProperty property1 = new ImageProperty("Foo", "Bar"); - ImageProperty property2 = new ImageProperty("Foo", "Bar"); - ImageProperty property3 = null; + var property1 = new ImageProperty("Foo", "Bar"); + var property2 = new ImageProperty("Foo", "Bar"); Assert.Equal(property1, property2); Assert.True(property1 == property2); - Assert.Null(property3); } /// @@ -33,15 +31,13 @@ namespace SixLabors.ImageSharp.Tests [Fact] public void AreNotEqual() { - ImageProperty property1 = new ImageProperty("Foo", "Bar"); - ImageProperty property2 = new ImageProperty("Foo", "Foo"); - ImageProperty property3 = new ImageProperty("Bar", "Bar"); - ImageProperty property4 = new ImageProperty("Foo", null); + var property1 = new ImageProperty("Foo", "Bar"); + var property2 = new ImageProperty("Foo", "Foo"); + var property3 = new ImageProperty("Bar", "Bar"); + var property4 = new ImageProperty("Foo", null); Assert.False(property1.Equals("Foo")); - Assert.NotNull(property1); - Assert.NotEqual(property1, property2); Assert.True(property1 != property2); @@ -66,7 +62,7 @@ namespace SixLabors.ImageSharp.Tests [Fact] public void ConstructorAssignsProperties() { - ImageProperty property = new ImageProperty("Foo", null); + var property = new ImageProperty("Foo", null); Assert.Equal("Foo", property.Name); Assert.Null(property.Value); From 3e9484cb922287bf3d6c105f08c03c9c8f557ba4 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 26 Mar 2018 19:07:33 -0700 Subject: [PATCH 05/32] Use standard sb variable name --- .../Formats/Jpeg/Common/Block8x8.cs | 12 +++++----- .../Formats/Jpeg/Common/Block8x8F.cs | 12 +++++----- src/ImageSharp/Image.FromStream.cs | 8 +++---- src/ImageSharp/ImageExtensions.cs | 24 +++++++++---------- .../MetaData/Profiles/Exif/ExifValue.cs | 2 +- 5 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/Common/Block8x8.cs b/src/ImageSharp/Formats/Jpeg/Common/Block8x8.cs index 06fdb2c76d..8a571fa6b7 100644 --- a/src/ImageSharp/Formats/Jpeg/Common/Block8x8.cs +++ b/src/ImageSharp/Formats/Jpeg/Common/Block8x8.cs @@ -241,19 +241,19 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common /// public override string ToString() { - var bld = new StringBuilder(); - bld.Append('['); + var sb = new StringBuilder(); + sb.Append('['); for (int i = 0; i < Size; i++) { - bld.Append(this[i]); + sb.Append(this[i]); if (i < Size - 1) { - bld.Append(','); + sb.Append(','); } } - bld.Append(']'); - return bld.ToString(); + sb.Append(']'); + return sb.ToString(); } /// diff --git a/src/ImageSharp/Formats/Jpeg/Common/Block8x8F.cs b/src/ImageSharp/Formats/Jpeg/Common/Block8x8F.cs index f45b5df4eb..3f71c498b2 100644 --- a/src/ImageSharp/Formats/Jpeg/Common/Block8x8F.cs +++ b/src/ImageSharp/Formats/Jpeg/Common/Block8x8F.cs @@ -496,19 +496,19 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common /// public override string ToString() { - var bld = new StringBuilder(); - bld.Append('['); + var sb = new StringBuilder(); + sb.Append('['); for (int i = 0; i < Size; i++) { - bld.Append(this[i]); + sb.Append(this[i]); if (i < Size - 1) { - bld.Append(','); + sb.Append(','); } } - bld.Append(']'); - return bld.ToString(); + sb.Append(']'); + return sb.ToString(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/Image.FromStream.cs b/src/ImageSharp/Image.FromStream.cs index 9061c334dc..3236e00072 100644 --- a/src/ImageSharp/Image.FromStream.cs +++ b/src/ImageSharp/Image.FromStream.cs @@ -183,15 +183,15 @@ namespace SixLabors.ImageSharp return data.img; } - var stringBuilder = new StringBuilder(); - stringBuilder.AppendLine("Image cannot be loaded. Available decoders:"); + var sb = new StringBuilder(); + sb.AppendLine("Image cannot be loaded. Available decoders:"); foreach (KeyValuePair val in config.ImageFormatsManager.ImageDecoders) { - stringBuilder.AppendLine($" - {val.Key.Name} : {val.Value.GetType().Name}"); + sb.AppendLine($" - {val.Key.Name} : {val.Value.GetType().Name}"); } - throw new NotSupportedException(stringBuilder.ToString()); + throw new NotSupportedException(sb.ToString()); } private static T WithSeekableStream(Configuration config, Stream stream, Func action) diff --git a/src/ImageSharp/ImageExtensions.cs b/src/ImageSharp/ImageExtensions.cs index 7d23d95d9c..294da3dc40 100644 --- a/src/ImageSharp/ImageExtensions.cs +++ b/src/ImageSharp/ImageExtensions.cs @@ -35,28 +35,28 @@ namespace SixLabors.ImageSharp IImageFormat format = source.GetConfiguration().ImageFormatsManager.FindFormatByFileExtension(ext); if (format == null) { - var stringBuilder = new StringBuilder(); - stringBuilder.AppendLine($"Can't find a format that is associated with the file extention '{ext}'. Registered formats with there extensions include:"); + var sb = new StringBuilder(); + sb.AppendLine($"Can't find a format that is associated with the file extention '{ext}'. Registered formats with there extensions include:"); foreach (IImageFormat fmt in source.GetConfiguration().ImageFormats) { - stringBuilder.AppendLine($" - {fmt.Name} : {string.Join(", ", fmt.FileExtensions)}"); + sb.AppendLine($" - {fmt.Name} : {string.Join(", ", fmt.FileExtensions)}"); } - throw new NotSupportedException(stringBuilder.ToString()); + throw new NotSupportedException(sb.ToString()); } IImageEncoder encoder = source.GetConfiguration().ImageFormatsManager.FindEncoder(format); if (encoder == null) { - var stringBuilder = new StringBuilder(); - stringBuilder.AppendLine($"Can't find encoder for file extention '{ext}' using image format '{format.Name}'. Registered encoders include:"); + var sb = new StringBuilder(); + sb.AppendLine($"Can't find encoder for file extention '{ext}' using image format '{format.Name}'. Registered encoders include:"); foreach (KeyValuePair enc in source.GetConfiguration().ImageFormatsManager.ImageEncoders) { - stringBuilder.AppendLine($" - {enc.Key} : {enc.Value.GetType().Name}"); + sb.AppendLine($" - {enc.Key} : {enc.Value.GetType().Name}"); } - throw new NotSupportedException(stringBuilder.ToString()); + throw new NotSupportedException(sb.ToString()); } source.Save(filePath, encoder); @@ -97,15 +97,15 @@ namespace SixLabors.ImageSharp if (encoder == null) { - var stringBuilder = new StringBuilder(); - stringBuilder.AppendLine("Can't find encoder for provided mime type. Available encoded:"); + var sb = new StringBuilder(); + sb.AppendLine("Can't find encoder for provided mime type. Available encoded:"); foreach (KeyValuePair val in source.GetConfiguration().ImageFormatsManager.ImageEncoders) { - stringBuilder.AppendLine($" - {val.Key.Name} : {val.Value.GetType().Name}"); + sb.AppendLine($" - {val.Key.Name} : {val.Value.GetType().Name}"); } - throw new NotSupportedException(stringBuilder.ToString()); + throw new NotSupportedException(sb.ToString()); } source.Save(stream, encoder); diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs index fd00c8585e..e36d0a25a4 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs @@ -254,7 +254,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif foreach (object value in (Array)this.exifValue) { sb.Append(this.ToString(value)); - sb.Append(" "); + sb.Append(' '); } return sb.ToString(); From 4dbb5704f82f1e4ec951c7c3632235527bd6061b Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 26 Mar 2018 19:12:40 -0700 Subject: [PATCH 06/32] Remove NotNull guaurds on structs --- .../Implementation/CieLab/CieLabToCieXyzConverter.cs | 2 -- .../Implementation/CieLab/CieXyzToCieLabConverter.cs | 3 --- .../Implementation/CieLch/CIeLchToCieLabConverter.cs | 2 -- .../Implementation/CieLch/CieLabToCieLchConverter.cs | 3 --- .../Implementation/CieLchuv/CieLchuvToCieLuvConverter.cs | 3 --- .../Implementation/CieLchuv/CieLuvToCieLchuvConverter.cs | 3 --- .../Implementation/CieLuv/CieLuvToCieXyzConverter.cs | 3 --- 7 files changed, 19 deletions(-) diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLab/CieLabToCieXyzConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLab/CieLabToCieXyzConverter.cs index 0a5ae3627e..53d9c927ad 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLab/CieLabToCieXyzConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLab/CieLabToCieXyzConverter.cs @@ -15,8 +15,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieLabColor [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieXyz Convert(CieLab input) { - DebugGuard.NotNull(input, nameof(input)); - // Conversion algorithm described here: http://www.brucelindbloom.com/index.html?Eqn_Lab_to_XYZ.html float l = input.L, a = input.A, b = input.B; float fy = (l + 16) / 116F; diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLab/CieXyzToCieLabConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLab/CieXyzToCieLabConverter.cs index 22308260c2..454601b884 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLab/CieXyzToCieLabConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLab/CieXyzToCieLabConverter.cs @@ -3,7 +3,6 @@ using System; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.ColorSpaces; namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieLabColorSapce { @@ -44,8 +43,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieLabColor [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieLab Convert(CieXyz input) { - DebugGuard.NotNull(input, nameof(input)); - // Conversion algorithm described here: http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_Lab.html float wx = this.LabWhitePoint.X, wy = this.LabWhitePoint.Y, wz = this.LabWhitePoint.Z; diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLch/CIeLchToCieLabConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLch/CIeLchToCieLabConverter.cs index 35fae30e83..d56ee59f50 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLch/CIeLchToCieLabConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLch/CIeLchToCieLabConverter.cs @@ -16,8 +16,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieLchColor [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieLab Convert(CieLch input) { - DebugGuard.NotNull(input, nameof(input)); - // Conversion algorithm described here: // https://en.wikipedia.org/wiki/Lab_color_space#Cylindrical_representation:_CIELCh_or_CIEHLC float l = input.L, c = input.C, hDegrees = input.H; diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLch/CieLabToCieLchConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLch/CieLabToCieLchConverter.cs index aa4614f9ca..ec73a830f6 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLch/CieLabToCieLchConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLch/CieLabToCieLchConverter.cs @@ -3,7 +3,6 @@ using System; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.ColorSpaces; namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieLchColorSapce { @@ -16,8 +15,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieLchColor [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieLch Convert(CieLab input) { - DebugGuard.NotNull(input, nameof(input)); - // Conversion algorithm described here: // https://en.wikipedia.org/wiki/Lab_color_space#Cylindrical_representation:_CIELCh_or_CIEHLC float l = input.L, a = input.A, b = input.B; diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLchuv/CieLchuvToCieLuvConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLchuv/CieLchuvToCieLuvConverter.cs index fc6554a905..eb523806a4 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLchuv/CieLchuvToCieLuvConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLchuv/CieLchuvToCieLuvConverter.cs @@ -3,7 +3,6 @@ using System; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.ColorSpaces; namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieLchuvColorSapce { @@ -16,8 +15,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieLchuvCol [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieLuv Convert(CieLchuv input) { - DebugGuard.NotNull(input, nameof(input)); - // Conversion algorithm described here: // https://en.wikipedia.org/wiki/CIELUV#Cylindrical_representation_.28CIELCH.29 float l = input.L, c = input.C, hDegrees = input.H; diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLchuv/CieLuvToCieLchuvConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLchuv/CieLuvToCieLchuvConverter.cs index f0d7a80a22..7a9dd2c6a7 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLchuv/CieLuvToCieLchuvConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLchuv/CieLuvToCieLchuvConverter.cs @@ -3,7 +3,6 @@ using System; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.ColorSpaces; namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieLchuvColorSapce { @@ -16,8 +15,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieLchuvCol [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieLchuv Convert(CieLuv input) { - DebugGuard.NotNull(input, nameof(input)); - // Conversion algorithm described here: // https://en.wikipedia.org/wiki/CIELUV#Cylindrical_representation_.28CIELCH.29 float l = input.L, a = input.U, b = input.V; diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuv/CieLuvToCieXyzConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuv/CieLuvToCieXyzConverter.cs index 50e8335ed6..7a264fdfe2 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuv/CieLuvToCieXyzConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuv/CieLuvToCieXyzConverter.cs @@ -3,7 +3,6 @@ using System; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.ColorSpaces; namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieLuvColorSapce { @@ -16,8 +15,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieLuvColor [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieXyz Convert(CieLuv input) { - DebugGuard.NotNull(input, nameof(input)); - // Conversion algorithm described here: http://www.brucelindbloom.com/index.html?Eqn_Luv_to_XYZ.html float l = input.L, u = input.U, v = input.V; From 95af0eedd0273947de59cb467d8bfa032c3b039b Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 26 Mar 2018 19:12:49 -0700 Subject: [PATCH 07/32] Use nameof --- src/ImageSharp/Formats/Bmp/BmpDecoder.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoder.cs b/src/ImageSharp/Formats/Bmp/BmpDecoder.cs index 78a9de6c45..d3cb50d6ba 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoder.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoder.cs @@ -28,7 +28,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp where TPixel : struct, IPixel { - Guard.NotNull(stream, "stream"); + Guard.NotNull(stream, nameof(stream)); return new BmpDecoderCore(configuration, this).Decode(stream); } @@ -36,7 +36,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp /// public IImageInfo Identify(Configuration configuration, Stream stream) { - Guard.NotNull(stream, "stream"); + Guard.NotNull(stream, nameof(stream)); return new BmpDecoderCore(configuration, this).Identify(stream); } From a12c7c06d5a071eafc2bcce04bdfaf3fbc2b0aeb Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Tue, 27 Mar 2018 09:38:20 -0700 Subject: [PATCH 08/32] Make BmpFileHeader readonly --- src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs | 13 +++++---- src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs | 18 ++++++------- src/ImageSharp/Formats/Bmp/BmpFileHeader.cs | 28 +++++++++++++------- 3 files changed, 33 insertions(+), 26 deletions(-) diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs index 9f4dba5b4f..4b5b150c49 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs @@ -581,13 +581,12 @@ namespace SixLabors.ImageSharp.Formats.Bmp this.currentStream.Read(data, 0, BmpFileHeader.Size); - this.fileHeader = new BmpFileHeader - { - Type = BitConverter.ToInt16(data, 0), - FileSize = BitConverter.ToInt32(data, 2), - Reserved = BitConverter.ToInt32(data, 6), - Offset = BitConverter.ToInt32(data, 10) - }; + this.fileHeader = new BmpFileHeader( + type: BitConverter.ToInt16(data, 0), + fileSize: BitConverter.ToInt32(data, 2), + reserved: BitConverter.ToInt32(data, 6), + offset: BitConverter.ToInt32(data, 10) + ); } /// diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs index 66c8b6c086..7e4dfde596 100644 --- a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs @@ -55,9 +55,9 @@ namespace SixLabors.ImageSharp.Formats.Bmp this.padding = bytesPerLine - (image.Width * (int)this.bitsPerPixel); // Do not use IDisposable pattern here as we want to preserve the stream. - EndianBinaryWriter writer = new EndianBinaryWriter(Endianness.LittleEndian, stream); + var writer = new EndianBinaryWriter(Endianness.LittleEndian, stream); - BmpInfoHeader infoHeader = new BmpInfoHeader + var infoHeader = new BmpInfoHeader { HeaderSize = BmpInfoHeader.BitmapInfoHeaderSize, Height = image.Height, @@ -69,12 +69,12 @@ namespace SixLabors.ImageSharp.Formats.Bmp ClrImportant = 0 }; - BmpFileHeader fileHeader = new BmpFileHeader - { - Type = 19778, // BM - Offset = 54, - FileSize = 54 + infoHeader.ImageSize - }; + var fileHeader = new BmpFileHeader( + type: 19778, // BM + offset: 54, + reserved: 0, + fileSize: 54 + infoHeader.ImageSize + ); WriteHeader(writer, fileHeader); this.WriteInfo(writer, infoHeader); @@ -92,7 +92,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp /// /// The containing the header data. /// - private static void WriteHeader(EndianBinaryWriter writer, BmpFileHeader fileHeader) + private static void WriteHeader(EndianBinaryWriter writer, in BmpFileHeader fileHeader) { writer.Write(fileHeader.Type); writer.Write(fileHeader.FileSize); diff --git a/src/ImageSharp/Formats/Bmp/BmpFileHeader.cs b/src/ImageSharp/Formats/Bmp/BmpFileHeader.cs index 4255ecae49..ed17164a22 100644 --- a/src/ImageSharp/Formats/Bmp/BmpFileHeader.cs +++ b/src/ImageSharp/Formats/Bmp/BmpFileHeader.cs @@ -13,35 +13,43 @@ namespace SixLabors.ImageSharp.Formats.Bmp /// All of the other integer values are stored in little-endian format /// (i.e. least-significant byte first). /// - internal sealed class BmpFileHeader + internal readonly struct BmpFileHeader { /// /// Defines of the data structure in the bitmap file. /// public const int Size = 14; + public BmpFileHeader(short type, int fileSize, int reserved, int offset) + { + this.Type = type; + this.FileSize = fileSize; + this.Reserved = reserved; + this.Offset = offset; + } + /// - /// Gets or sets the Bitmap identifier. + /// Gets the Bitmap identifier. /// The field used to identify the bitmap file: 0x42 0x4D /// (Hex code points for B and M) /// - public short Type { get; set; } + public short Type { get; } /// - /// Gets or sets the size of the bitmap file in bytes. + /// Gets the size of the bitmap file in bytes. /// - public int FileSize { get; set; } + public int FileSize { get; } /// - /// Gets or sets any reserved data; actual value depends on the application + /// Gets any reserved data; actual value depends on the application /// that creates the image. /// - public int Reserved { get; set; } + public int Reserved { get; } /// - /// Gets or sets the offset, i.e. starting address, of the byte where + /// Gets the offset, i.e. starting address, of the byte where /// the bitmap data can be found. /// - public int Offset { get; set; } + public int Offset { get; } } -} +} \ No newline at end of file From 804a12e2b1ed6f57c0bb10f9f4faa1395565c90e Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Tue, 27 Mar 2018 09:39:38 -0700 Subject: [PATCH 09/32] Use TryRead pattern for PngChunks First step toward converting this to an immutable readonly struct --- src/ImageSharp/Formats/Png/PngChunk.cs | 9 ++- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 72 ++++++++++---------- 2 files changed, 43 insertions(+), 38 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngChunk.cs b/src/ImageSharp/Formats/Png/PngChunk.cs index 2483a3ad9d..b944b43a34 100644 --- a/src/ImageSharp/Formats/Png/PngChunk.cs +++ b/src/ImageSharp/Formats/Png/PngChunk.cs @@ -10,13 +10,18 @@ namespace SixLabors.ImageSharp.Formats.Png /// internal sealed class PngChunk { + public PngChunk(int length) + { + this.Length = length; + } + /// - /// Gets or sets the length. + /// Gets the length. /// An unsigned integer giving the number of bytes in the chunk's /// data field. The length counts only the data field, not itself, /// the chunk type code, or the CRC. Zero is a valid length /// - public int Length { get; set; } + public int Length { get; } /// /// Gets or sets the chunk type as string with 4 chars. diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index ffa3875057..e5431cf34f 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -217,19 +217,18 @@ namespace SixLabors.ImageSharp.Formats.Png { using (var deframeStream = new ZlibInflateStream(this.currentStream)) { - PngChunk currentChunk; - while (!this.isEndChunkReached && (currentChunk = this.ReadChunk()) != null) + while (!this.isEndChunkReached && this.TryReadChunk(out PngChunk chunk)) { try { - switch (currentChunk.Type) + switch (chunk.Type) { case PngChunkTypes.Header: - this.ReadHeaderChunk(currentChunk.Data.Array); + this.ReadHeaderChunk(chunk.Data.Array); this.ValidateHeader(); break; case PngChunkTypes.Physical: - this.ReadPhysicalChunk(metadata, currentChunk.Data.Array); + this.ReadPhysicalChunk(metadata, chunk.Data.Array); break; case PngChunkTypes.Data: if (image == null) @@ -237,23 +236,23 @@ namespace SixLabors.ImageSharp.Formats.Png this.InitializeImage(metadata, out image); } - deframeStream.AllocateNewBytes(currentChunk.Length); + deframeStream.AllocateNewBytes(chunk.Length); this.ReadScanlines(deframeStream.CompressedStream, image.Frames.RootFrame); this.currentStream.Read(this.crcBuffer, 0, 4); break; case PngChunkTypes.Palette: - byte[] pal = new byte[currentChunk.Length]; - Buffer.BlockCopy(currentChunk.Data.Array, 0, pal, 0, currentChunk.Length); + byte[] pal = new byte[chunk.Length]; + Buffer.BlockCopy(chunk.Data.Array, 0, pal, 0, chunk.Length); this.palette = pal; break; case PngChunkTypes.PaletteAlpha: - byte[] alpha = new byte[currentChunk.Length]; - Buffer.BlockCopy(currentChunk.Data.Array, 0, alpha, 0, currentChunk.Length); + byte[] alpha = new byte[chunk.Length]; + Buffer.BlockCopy(chunk.Data.Array, 0, alpha, 0, chunk.Length); this.paletteAlpha = alpha; this.AssignTransparentMarkers(alpha); break; case PngChunkTypes.Text: - this.ReadTextChunk(metadata, currentChunk.Data.Array, currentChunk.Length); + this.ReadTextChunk(metadata, chunk.Data.Array, chunk.Length); break; case PngChunkTypes.End: this.isEndChunkReached = true; @@ -263,10 +262,10 @@ namespace SixLabors.ImageSharp.Formats.Png finally { // Data is rented in ReadChunkData() - if (currentChunk.Data != null) + if (chunk.Data != null) { - currentChunk.Data.Dispose(); - currentChunk.Data = null; + chunk.Data.Dispose(); + chunk.Data = null; } } } @@ -297,25 +296,24 @@ namespace SixLabors.ImageSharp.Formats.Png this.currentStream.Skip(8); try { - PngChunk currentChunk; - while (!this.isEndChunkReached && (currentChunk = this.ReadChunk()) != null) + while (!this.isEndChunkReached && this.TryReadChunk(out PngChunk chunk)) { try { - switch (currentChunk.Type) + switch (chunk.Type) { case PngChunkTypes.Header: - this.ReadHeaderChunk(currentChunk.Data.Array); + this.ReadHeaderChunk(chunk.Data.Array); this.ValidateHeader(); break; case PngChunkTypes.Physical: - this.ReadPhysicalChunk(metadata, currentChunk.Data.Array); + this.ReadPhysicalChunk(metadata, chunk.Data.Array); break; case PngChunkTypes.Data: - this.SkipChunkDataAndCrc(currentChunk); + this.SkipChunkDataAndCrc(chunk); break; case PngChunkTypes.Text: - this.ReadTextChunk(metadata, currentChunk.Data.Array, currentChunk.Length); + this.ReadTextChunk(metadata, chunk.Data.Array, chunk.Length); break; case PngChunkTypes.End: this.isEndChunkReached = true; @@ -325,9 +323,9 @@ namespace SixLabors.ImageSharp.Formats.Png finally { // Data is rented in ReadChunkData() - if (currentChunk.Data != null) + if (chunk.Data != null) { - ArrayPool.Shared.Return(currentChunk.Data.Array); + ArrayPool.Shared.Return(chunk.Data.Array); } } } @@ -1208,36 +1206,40 @@ namespace SixLabors.ImageSharp.Formats.Png /// /// The . /// - private PngChunk ReadChunk() + private bool TryReadChunk(out PngChunk chunk) { - var chunk = new PngChunk(); - this.ReadChunkLength(chunk); + int length = this.ReadChunkLength(); - if (chunk.Length == -1) + if (length == -1) { + chunk = default; + // IEND - return null; + return false; } + chunk = new PngChunk(length); + if (chunk.Length < 0 || chunk.Length > this.currentStream.Length - this.currentStream.Position) { // Not a valid chunk so we skip back all but one of the four bytes we have just read. // That lets us read one byte at a time until we reach a known chunk. this.currentStream.Position -= 3; - return chunk; + + return true; } this.ReadChunkType(chunk); if (chunk.Type == PngChunkTypes.Data) { - return chunk; + return true; } this.ReadChunkData(chunk); this.ReadChunkCrc(chunk); - return chunk; + return true; } /// @@ -1314,21 +1316,19 @@ namespace SixLabors.ImageSharp.Formats.Png /// /// Calculates the length of the given chunk. /// - /// The chunk. /// /// Thrown if the input stream is not valid. /// - private void ReadChunkLength(PngChunk chunk) + private int ReadChunkLength() { int numBytes = this.currentStream.Read(this.chunkLengthBuffer, 0, 4); if (numBytes < 4) { - chunk.Length = -1; - return; + return -1; } - chunk.Length = BinaryPrimitives.ReadInt32BigEndian(this.chunkLengthBuffer); + return BinaryPrimitives.ReadInt32BigEndian(this.chunkLengthBuffer); } /// From 0121e3868da23bae2ee1fb9054cb982213d95734 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Tue, 27 Mar 2018 09:52:02 -0700 Subject: [PATCH 10/32] Make PngHeader immutable --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 21 ++++----- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 23 +++++----- src/ImageSharp/Formats/Png/PngHeader.cs | 48 ++++++++++++++------ 3 files changed, 54 insertions(+), 38 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index e5431cf34f..2186444739 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -336,7 +336,7 @@ namespace SixLabors.ImageSharp.Formats.Png this.previousScanline?.Dispose(); } - if (this.header == null) + if (this.header.Width == 0 && this.header.Height == 0) { throw new ImageFormatException("PNG Image does not contain a header chunk"); } @@ -1157,16 +1157,15 @@ namespace SixLabors.ImageSharp.Formats.Png /// The containing data. private void ReadHeaderChunk(ReadOnlySpan data) { - this.header = new PngHeader - { - Width = BinaryPrimitives.ReadInt32BigEndian(data.Slice(0, 4)), - Height = BinaryPrimitives.ReadInt32BigEndian(data.Slice(4, 4)), - BitDepth = data[8], - ColorType = (PngColorType)data[9], - CompressionMethod = data[10], - FilterMethod = data[11], - InterlaceMethod = (PngInterlaceMode)data[12] - }; + this.header = new PngHeader( + width: BinaryPrimitives.ReadInt32BigEndian(data.Slice(0, 4)), + height: BinaryPrimitives.ReadInt32BigEndian(data.Slice(4, 4)), + bitDepth: data[8], + colorType: (PngColorType)data[9], + compressionMethod: data[10], + filterMethod: data[11], + interlaceMethod: (PngInterlaceMode)data[12] + ); } /// diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 0cded1d80c..5f7cd9b23d 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -212,16 +212,15 @@ namespace SixLabors.ImageSharp.Formats.Png this.bytesPerPixel = this.CalculateBytesPerPixel(); - var header = new PngHeader - { - Width = image.Width, - Height = image.Height, - ColorType = this.pngColorType, - BitDepth = this.bitDepth, - FilterMethod = 0, // None - CompressionMethod = 0, - InterlaceMethod = 0 - }; + var header = new PngHeader( + width: image.Width, + height: image.Height, + colorType: this.pngColorType, + bitDepth: this.bitDepth, + filterMethod: 0, // None + compressionMethod: 0, + interlaceMethod: 0 + ); this.WriteHeaderChunk(stream, header); @@ -415,7 +414,7 @@ namespace SixLabors.ImageSharp.Formats.Png /// /// The containing image data. /// The . - private void WriteHeaderChunk(Stream stream, PngHeader header) + private void WriteHeaderChunk(Stream stream, in PngHeader header) { BinaryPrimitives.WriteInt32BigEndian(new Span(this.chunkDataBuffer, 0, 4), header.Width); BinaryPrimitives.WriteInt32BigEndian(new Span(this.chunkDataBuffer, 4, 4), header.Height); @@ -436,7 +435,7 @@ namespace SixLabors.ImageSharp.Formats.Png /// The containing image data. /// The . /// The quantized frame. - private void WritePaletteChunk(Stream stream, PngHeader header, QuantizedFrame quantized) + private void WritePaletteChunk(Stream stream, in PngHeader header, QuantizedFrame quantized) where TPixel : struct, IPixel { // Grab the palette and write it to the stream. diff --git a/src/ImageSharp/Formats/Png/PngHeader.cs b/src/ImageSharp/Formats/Png/PngHeader.cs index a70032ce3c..df85642bed 100644 --- a/src/ImageSharp/Formats/Png/PngHeader.cs +++ b/src/ImageSharp/Formats/Png/PngHeader.cs @@ -6,55 +6,73 @@ namespace SixLabors.ImageSharp.Formats.Png /// /// Represents the png header chunk. /// - internal sealed class PngHeader + internal readonly struct PngHeader { + public PngHeader( + int width, + int height, + byte bitDepth, + PngColorType colorType, + byte compressionMethod, + byte filterMethod, + PngInterlaceMode interlaceMethod) + { + this.Width = width; + this.Height = height; + this.BitDepth = bitDepth; + this.ColorType = colorType; + this.CompressionMethod = compressionMethod; + this.FilterMethod = filterMethod; + this.InterlaceMethod = interlaceMethod; + } + /// - /// Gets or sets the dimension in x-direction of the image in pixels. + /// Gets the dimension in x-direction of the image in pixels. /// - public int Width { get; set; } + public int Width { get; } /// - /// Gets or sets the dimension in y-direction of the image in pixels. + /// Gets the dimension in y-direction of the image in pixels. /// - public int Height { get; set; } + public int Height { get; } /// - /// Gets or sets the bit depth. + /// Gets the bit depth. /// Bit depth is a single-byte integer giving the number of bits per sample /// or per palette index (not per pixel). Valid values are 1, 2, 4, 8, and 16, /// although not all values are allowed for all color types. /// - public byte BitDepth { get; set; } + public byte BitDepth { get; } /// - /// Gets or sets the color type. + /// Gets the color type. /// Color type is a integer that describes the interpretation of the /// image data. Color type codes represent sums of the following values: /// 1 (palette used), 2 (color used), and 4 (alpha channel used). /// - public PngColorType ColorType { get; set; } + public PngColorType ColorType { get; } /// - /// Gets or sets the compression method. + /// Gets the compression method. /// Indicates the method used to compress the image data. At present, /// only compression method 0 (deflate/inflate compression with a sliding /// window of at most 32768 bytes) is defined. /// - public byte CompressionMethod { get; set; } + public byte CompressionMethod { get; } /// - /// Gets or sets the preprocessing method. + /// Gets the preprocessing method. /// Indicates the preprocessing method applied to the image /// data before compression. At present, only filter method 0 /// (adaptive filtering with five basic filter types) is defined. /// - public byte FilterMethod { get; set; } + public byte FilterMethod { get; } /// - /// Gets or sets the transmission order. + /// Gets the transmission order. /// Indicates the transmission order of the image data. /// Two values are currently defined: 0 (no interlace) or 1 (Adam7 interlace). /// - public PngInterlaceMode InterlaceMethod { get; set; } + public PngInterlaceMode InterlaceMethod { get; } } } From 7955593d92d36a14d10b6b722f390c1131311a25 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Tue, 27 Mar 2018 10:01:50 -0700 Subject: [PATCH 11/32] Remove SpanHelper.Copy --- src/ImageSharp/Memory/SpanHelper.cs | 16 +--------------- .../ImageSharp.Tests/Memory/SpanUtilityTests.cs | 16 ++++++++-------- 2 files changed, 9 insertions(+), 23 deletions(-) diff --git a/src/ImageSharp/Memory/SpanHelper.cs b/src/ImageSharp/Memory/SpanHelper.cs index 4a6b7b7ce6..592e2a885b 100644 --- a/src/ImageSharp/Memory/SpanHelper.cs +++ b/src/ImageSharp/Memory/SpanHelper.cs @@ -11,20 +11,6 @@ namespace SixLabors.ImageSharp.Memory /// internal static class SpanHelper { - /// - /// Copy 'count' number of elements of the same type from 'source' to 'dest' - /// - /// The element type. - /// The to copy elements from. - /// The destination . - /// The number of elements to copy - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static unsafe void Copy(ReadOnlySpan source, Span destination, int count) - where T : struct - { - source.Slice(0, count).CopyTo(destination); - } - /// /// Copy all elements of 'source' into 'destination'. /// @@ -35,7 +21,7 @@ namespace SixLabors.ImageSharp.Memory public static void Copy(ReadOnlySpan source, Span destination) where T : struct { - Copy(source, destination, Math.Min(source.Length, destination.Length)); + source.Slice(0, Math.Min(source.Length, destination.Length)).CopyTo(destination); } /// diff --git a/tests/ImageSharp.Tests/Memory/SpanUtilityTests.cs b/tests/ImageSharp.Tests/Memory/SpanUtilityTests.cs index a813e0c1dd..908830fb7c 100644 --- a/tests/ImageSharp.Tests/Memory/SpanUtilityTests.cs +++ b/tests/ImageSharp.Tests/Memory/SpanUtilityTests.cs @@ -66,7 +66,7 @@ namespace SixLabors.ImageSharp.Tests.Memory var apSource = new Span(source, 1, source.Length - 1); var apDest = new Span(dest, 1, dest.Length - 1); - SpanHelper.Copy(apSource, apDest, count - 1); + apSource.Slice(0, count - 1).CopyTo(apDest); AssertNotDefault(source, 1); AssertNotDefault(dest, 1); @@ -89,7 +89,7 @@ namespace SixLabors.ImageSharp.Tests.Memory var apSource = new Span(source, 1, source.Length - 1); var apDest = new Span(dest, 1, dest.Length - 1); - SpanHelper.Copy(apSource, apDest, count - 1); + apSource.Slice(0, count - 1).CopyTo(apDest); AssertNotDefault(source, 1); AssertNotDefault(dest, 1); @@ -112,7 +112,7 @@ namespace SixLabors.ImageSharp.Tests.Memory var apSource = new Span(source, 1, source.Length - 1); var apDest = new Span(dest, 1, dest.Length - 1); - SpanHelper.Copy(apSource, apDest, count - 1); + apSource.Slice(0, count - 1).CopyTo(apDest); AssertNotDefault(source, 1); AssertNotDefault(dest, 1); @@ -136,7 +136,7 @@ namespace SixLabors.ImageSharp.Tests.Memory var apSource = new Span(source, 1, source.Length - 1); var apDest = new Span(dest, sizeof(TestStructs.Foo), dest.Length - sizeof(TestStructs.Foo)); - SpanHelper.Copy(apSource.AsBytes(), apDest, (count - 1) * sizeof(TestStructs.Foo)); + apSource.AsBytes().Slice(0, (count - 1) * sizeof(TestStructs.Foo)).CopyTo(apDest); AssertNotDefault(source, 1); @@ -159,7 +159,7 @@ namespace SixLabors.ImageSharp.Tests.Memory var apSource = new Span(source, 1, source.Length - 1); var apDest = new Span(dest, sizeof(TestStructs.AlignedFoo), dest.Length - sizeof(TestStructs.AlignedFoo)); - SpanHelper.Copy(apSource.AsBytes(), apDest, (count - 1) * sizeof(TestStructs.AlignedFoo)); + apSource.AsBytes().Slice(0, (count - 1) * sizeof(TestStructs.AlignedFoo)).CopyTo(apDest); AssertNotDefault(source, 1); @@ -182,7 +182,7 @@ namespace SixLabors.ImageSharp.Tests.Memory var apSource = new Span(source); var apDest = new Span(dest); - SpanHelper.Copy(apSource.AsBytes(), apDest, count * sizeof(int)); + apSource.AsBytes().Slice(0, count * sizeof(int)).CopyTo(apDest); AssertNotDefault(source, 1); @@ -198,12 +198,12 @@ namespace SixLabors.ImageSharp.Tests.Memory { int srcCount = count * sizeof(TestStructs.Foo); byte[] source = CreateTestBytes(srcCount); - TestStructs.Foo[] dest = new TestStructs.Foo[count + 2]; + var dest = new TestStructs.Foo[count + 2]; var apSource = new Span(source); var apDest = new Span(dest); - SpanHelper.Copy(apSource, apDest.AsBytes(), count * sizeof(TestStructs.Foo)); + apSource.Slice(0, count * sizeof(TestStructs.Foo)).CopyTo(apDest.AsBytes()); AssertNotDefault(source, sizeof(TestStructs.Foo) + 1); AssertNotDefault(dest, 1); From d8b188ffc3a492ddd86fa46e3e0a2287b719c4b3 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Tue, 27 Mar 2018 10:03:04 -0700 Subject: [PATCH 12/32] Make PixelTypeInfo a struct --- src/ImageSharp/Formats/PixelTypeInfo.cs | 4 ++-- tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs | 2 +- tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs | 2 +- tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs | 4 ++-- tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/ImageSharp/Formats/PixelTypeInfo.cs b/src/ImageSharp/Formats/PixelTypeInfo.cs index ed21b91bfc..c83ce67889 100644 --- a/src/ImageSharp/Formats/PixelTypeInfo.cs +++ b/src/ImageSharp/Formats/PixelTypeInfo.cs @@ -6,10 +6,10 @@ namespace SixLabors.ImageSharp.Formats /// /// Contains information about the pixels that make up an images visual data. /// - public class PixelTypeInfo + public readonly struct PixelTypeInfo { /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the struct. /// /// Color depth, in number of bits per pixel. internal PixelTypeInfo(int bitsPerPixel) diff --git a/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs index d958278f6e..c15b0c2b08 100644 --- a/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs @@ -57,7 +57,7 @@ namespace SixLabors.ImageSharp.Tests var testFile = TestFile.Create(imagePath); using (var stream = new MemoryStream(testFile.Bytes, false)) { - Assert.Equal(expectedPixelSize, Image.Identify(stream)?.PixelType?.BitsPerPixel); + Assert.Equal(expectedPixelSize, Image.Identify(stream)?.PixelType.BitsPerPixel); } } } diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs index 9cdb9f8b1a..9cd29f460f 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs @@ -172,7 +172,7 @@ namespace SixLabors.ImageSharp.Tests TestFile testFile = TestFile.Create(imagePath); using (var stream = new MemoryStream(testFile.Bytes, false)) { - Assert.Equal(expectedPixelSize, Image.Identify(stream)?.PixelType?.BitsPerPixel); + Assert.Equal(expectedPixelSize, Image.Identify(stream)?.PixelType.BitsPerPixel); } } diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs index 95ee40e807..c7ac71ed92 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs @@ -397,10 +397,10 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg [InlineData(TestImages.Jpeg.Baseline.Snake, 24)] public void DetectPixelSize(string imagePath, int expectedPixelSize) { - TestFile testFile = TestFile.Create(imagePath); + var testFile = TestFile.Create(imagePath); using (var stream = new MemoryStream(testFile.Bytes, false)) { - Assert.Equal(expectedPixelSize, Image.Identify(stream)?.PixelType?.BitsPerPixel); + Assert.Equal(expectedPixelSize, Image.Identify(stream)?.PixelType.BitsPerPixel); } } } diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs index f70e4e3300..8e83f5ffb7 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs @@ -228,10 +228,10 @@ namespace SixLabors.ImageSharp.Tests [InlineData(TestImages.Png.Rgb48BppInterlaced, 48)] public void DetectPixelSize(string imagePath, int expectedPixelSize) { - TestFile testFile = TestFile.Create(imagePath); + var testFile = TestFile.Create(imagePath); using (var stream = new MemoryStream(testFile.Bytes, false)) { - Assert.Equal(expectedPixelSize, Image.Identify(stream)?.PixelType?.BitsPerPixel); + Assert.Equal(expectedPixelSize, Image.Identify(stream)?.PixelType.BitsPerPixel); } } From e2507675066b41fe6f0ea59e38b0e7a3e1462d01 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Tue, 27 Mar 2018 11:39:52 -0700 Subject: [PATCH 13/32] Make ExifValue immutable --- .../MetaData/Profiles/Exif/ExifProfile.cs | 9 +- .../MetaData/Profiles/Exif/ExifValue.cs | 163 ++++++++---------- .../MetaData/Profiles/Exif/ExifWriter.cs | 32 ++-- .../Profiles/Exif/ExifProfileTests.cs | 10 +- 4 files changed, 94 insertions(+), 120 deletions(-) diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs index 7cd2d002d7..82542d2eea 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs @@ -106,7 +106,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif /// /// Gets the values of this EXIF profile. /// - public IEnumerable Values + public IList Values { get { @@ -193,16 +193,17 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif /// The value. public void SetValue(ExifTag tag, object value) { - foreach (ExifValue exifValue in this.Values) + for (int i = 0; i < this.Values.Count; i++) { - if (exifValue.Tag == tag) + if (this.Values[i].Tag == tag) { - exifValue.Value = value; + this.Values[i] = this.Values[i].WithValue(value); return; } } var newExifValue = ExifValue.Create(tag, value); + this.values.Add(newExifValue); } diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs index e36d0a25a4..055c22995a 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs @@ -13,11 +13,6 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif /// public sealed class ExifValue : IEquatable { - /// - /// The exif value. - /// - private object exifValue; - /// /// Initializes a new instance of the class /// by making a copy from another exif value. @@ -31,33 +26,16 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif this.DataType = other.DataType; this.IsArray = other.IsArray; this.Tag = other.Tag; + if (!other.IsArray) { - this.exifValue = other.exifValue; + this.Value = other.Value; } else { - var array = (Array)other.exifValue; - this.exifValue = array.Clone(); - } - } - - /// - /// Initializes a new instance of the class. - /// - /// The tag. - /// The data type. - /// Whether the value is an array. - internal ExifValue(ExifTag tag, ExifDataType dataType, bool isArray) - { - this.Tag = tag; - this.DataType = dataType; - this.IsArray = isArray; - - if (dataType == ExifDataType.Ascii) - { - this.IsArray = false; + var array = (Array)other.Value; + this.Value = array.Clone(); } } @@ -69,9 +47,13 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif /// The value. /// Whether the value is an array. internal ExifValue(ExifTag tag, ExifDataType dataType, object value, bool isArray) - : this(tag, dataType, isArray) { - this.exifValue = value; + this.Tag = tag; + this.DataType = dataType; + this.IsArray = isArray && dataType != ExifDataType.Ascii; + this.Value = value; + + // this.CheckValue(value); } /// @@ -90,17 +72,9 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif public ExifTag Tag { get; } /// - /// Gets or sets the value. + /// Gets the value. /// - public object Value - { - get => this.exifValue; - set - { - this.CheckValue(value); - this.exifValue = value; - } - } + public object Value { get; } /// /// Gets a value indicating whether the EXIF value has a value. @@ -109,14 +83,14 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif { get { - if (this.exifValue == null) + if (this.Value == null) { return false; } if (this.DataType == ExifDataType.Ascii) { - return ((string)this.exifValue).Length > 0; + return ((string)this.Value).Length > 0; } return true; @@ -130,7 +104,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif { get { - if (this.exifValue == null) + if (this.Value == null) { return 4; } @@ -150,18 +124,30 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif { if (this.DataType == ExifDataType.Ascii) { - return Encoding.UTF8.GetBytes((string)this.exifValue).Length; + return Encoding.UTF8.GetBytes((string)this.Value).Length; } if (this.IsArray) { - return ((Array)this.exifValue).Length; + return ((Array)this.Value).Length; } return 1; } } + /// + /// Clones the current value, overwriting the value. + /// + /// The value to overwrite. + /// + public ExifValue WithValue(object value) + { + this.CheckValue(value); + + return new ExifValue(this.Tag, this.DataType, value, this.IsArray); + } + /// /// Compares two objects for equality. /// @@ -223,7 +209,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif return this.Tag == other.Tag && this.DataType == other.DataType && - object.Equals(this.exifValue, other.exifValue); + object.Equals(this.Value, other.Value); } /// @@ -235,23 +221,23 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif /// public override string ToString() { - if (this.exifValue == null) + if (this.Value == null) { return null; } if (this.DataType == ExifDataType.Ascii) { - return (string)this.exifValue; + return (string)this.Value; } if (!this.IsArray) { - return this.ToString(this.exifValue); + return this.ToString(this.Value); } var sb = new StringBuilder(); - foreach (object value in (Array)this.exifValue) + foreach (object value in (Array)this.Value) { sb.Append(this.ToString(value)); sb.Append(' '); @@ -275,13 +261,6 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif { Guard.IsFalse(tag == ExifTag.Unknown, nameof(tag), "Invalid Tag"); - ExifValue exifValue; - Type type = value?.GetType(); - if (type != null && type.IsArray) - { - type = type.GetElementType(); - } - switch (tag) { case ExifTag.ImageDescription: @@ -337,8 +316,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif case ExifTag.GPSDestBearingRef: case ExifTag.GPSDestDistanceRef: case ExifTag.GPSDateStamp: - exifValue = new ExifValue(tag, ExifDataType.Ascii, true); - break; + return new ExifValue(tag, ExifDataType.Ascii, value, true); case ExifTag.ClipPath: case ExifTag.VersionYear: @@ -351,13 +329,12 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif case ExifTag.XPKeywords: case ExifTag.XPSubject: case ExifTag.GPSVersionID: - exifValue = new ExifValue(tag, ExifDataType.Byte, true); - break; + return new ExifValue(tag, ExifDataType.Byte, value, true); + case ExifTag.FaxProfile: case ExifTag.ModeNumber: case ExifTag.GPSAltitudeRef: - exifValue = new ExifValue(tag, ExifDataType.Byte, false); - break; + return new ExifValue(tag, ExifDataType.Byte, value, false); case ExifTag.FreeOffsets: case ExifTag.FreeByteCounts: @@ -371,8 +348,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif case ExifTag.StripRowCounts: case ExifTag.IntergraphRegisters: case ExifTag.TimeZoneOffset: - exifValue = new ExifValue(tag, ExifDataType.Long, true); - break; + return new ExifValue(tag, ExifDataType.Long, value, true); case ExifTag.SubfileType: case ExifTag.SubIFDOffset: case ExifTag.GPSIFDOffset: @@ -394,8 +370,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif case ExifTag.FaxRecvParams: case ExifTag.FaxRecvTime: case ExifTag.ImageNumber: - exifValue = new ExifValue(tag, ExifDataType.Long, false); - break; + return new ExifValue(tag, ExifDataType.Long, value, false); case ExifTag.WhitePoint: case ExifTag.PrimaryChromaticities: @@ -410,8 +385,8 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif case ExifTag.GPSTimestamp: case ExifTag.GPSDestLatitude: case ExifTag.GPSDestLongitude: - exifValue = new ExifValue(tag, ExifDataType.Rational, true); - break; + return new ExifValue(tag, ExifDataType.Rational, value, true); + case ExifTag.XPosition: case ExifTag.YPosition: case ExifTag.XResolution: @@ -445,8 +420,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif case ExifTag.GPSImgDirection: case ExifTag.GPSDestBearing: case ExifTag.GPSDestDistance: - exifValue = new ExifValue(tag, ExifDataType.Rational, false); - break; + return new ExifValue(tag, ExifDataType.Rational, value, false); case ExifTag.BitsPerSample: case ExifTag.MinSampleValue: @@ -469,8 +443,8 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif case ExifTag.ISOSpeedRatings: case ExifTag.SubjectArea: case ExifTag.SubjectLocation: - exifValue = new ExifValue(tag, ExifDataType.Short, true); - break; + return new ExifValue(tag, ExifDataType.Short, value, true); + case ExifTag.OldSubfileType: case ExifTag.Compression: case ExifTag.PhotometricInterpretation: @@ -517,20 +491,18 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif case ExifTag.Sharpness: case ExifTag.SubjectDistanceRange: case ExifTag.GPSDifferential: - exifValue = new ExifValue(tag, ExifDataType.Short, false); - break; + return new ExifValue(tag, ExifDataType.Short, value, false); case ExifTag.Decode: - exifValue = new ExifValue(tag, ExifDataType.SignedRational, true); - break; + return new ExifValue(tag, ExifDataType.SignedRational, value, true); + case ExifTag.ShutterSpeedValue: case ExifTag.BrightnessValue: case ExifTag.ExposureBiasValue: case ExifTag.AmbientTemperature: case ExifTag.WaterDepth: case ExifTag.CameraElevationAngle: - exifValue = new ExifValue(tag, ExifDataType.SignedRational, false); - break; + return new ExifValue(tag, ExifDataType.SignedRational, value, false); case ExifTag.JPEGTables: case ExifTag.OECF: @@ -547,18 +519,17 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif case ExifTag.ImageSourceData: case ExifTag.GPSProcessingMethod: case ExifTag.GPSAreaInformation: - exifValue = new ExifValue(tag, ExifDataType.Undefined, true); - break; + return new ExifValue(tag, ExifDataType.Undefined, value, true); + case ExifTag.FileSource: case ExifTag.SceneType: - exifValue = new ExifValue(tag, ExifDataType.Undefined, false); - break; + return new ExifValue(tag, ExifDataType.Undefined, value, false); case ExifTag.StripOffsets: case ExifTag.TileByteCounts: case ExifTag.ImageLayer: - exifValue = CreateNumber(tag, type, true); - break; + return CreateNumber(tag, value, true); + case ExifTag.ImageWidth: case ExifTag.ImageLength: case ExifTag.TileWidth: @@ -567,15 +538,11 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif case ExifTag.ConsecutiveBadFaxLines: case ExifTag.PixelXDimension: case ExifTag.PixelYDimension: - exifValue = CreateNumber(tag, type, false); - break; + return CreateNumber(tag, value, false); default: throw new NotSupportedException(); } - - exifValue.Value = value; - return exifValue; } /// @@ -617,29 +584,35 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif /// Returns an EXIF value with a numeric type for the given tag. /// /// The tag. - /// The numeric type. + /// The value. /// Whether the value is an array. /// /// The . /// - private static ExifValue CreateNumber(ExifTag tag, Type type, bool isArray) + private static ExifValue CreateNumber(ExifTag tag, object value, bool isArray) { + Type type = value?.GetType(); + if (type != null && type.IsArray) + { + type = type.GetElementType(); + } + if (type == null || type == typeof(ushort)) { - return new ExifValue(tag, ExifDataType.Short, isArray); + return new ExifValue(tag, ExifDataType.Short, value, isArray); } if (type == typeof(short)) { - return new ExifValue(tag, ExifDataType.SignedShort, isArray); + return new ExifValue(tag, ExifDataType.SignedShort, value, isArray); } if (type == typeof(uint)) { - return new ExifValue(tag, ExifDataType.Long, isArray); + return new ExifValue(tag, ExifDataType.Long, value, isArray); } - return new ExifValue(tag, ExifDataType.SignedLong, isArray); + return new ExifValue(tag, ExifDataType.SignedLong, value, isArray); } /// @@ -770,7 +743,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif private int GetHashCode(ExifValue exif) { int hashCode = exif.Tag.GetHashCode() ^ exif.DataType.GetHashCode(); - return hashCode ^ exif.exifValue?.GetHashCode() ?? hashCode; + return hashCode ^ exif.Value?.GetHashCode() ?? hashCode; } } } \ No newline at end of file diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifWriter.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifWriter.cs index a4cfc7e13e..ef51392dd8 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifWriter.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifWriter.cs @@ -294,18 +294,18 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif /// Which parts will be written. /// private ExifParts allowedParts; - private Collection values; - private Collection dataOffsets; - private Collection ifdIndexes; - private Collection exifIndexes; - private Collection gpsIndexes; + private IList values; + private IList dataOffsets; + private IList ifdIndexes; + private IList exifIndexes; + private IList gpsIndexes; /// /// Initializes a new instance of the class. /// /// The values. /// The allowed parts. - public ExifWriter(Collection values, ExifParts allowedParts) + public ExifWriter(IList values, ExifParts allowedParts) { this.values = values; this.allowedParts = allowedParts; @@ -377,12 +377,12 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif if (exifLength > 0) { - this.values[exifIndex].Value = ifdOffset + ifdLength; + this.values[exifIndex] = this.values[exifIndex].WithValue(ifdOffset + ifdLength); } if (gpsLength > 0) { - this.values[gpsIndex].Value = ifdOffset + ifdLength + exifLength; + this.values[gpsIndex] = this.values[gpsIndex].WithValue(ifdOffset + ifdLength + exifLength); } i = Write(BitConverter.GetBytes(ifdOffset), result, i); @@ -414,7 +414,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif return offset + source.Length; } - private int GetIndex(Collection indexes, ExifTag tag) + private int GetIndex(IList indexes, ExifTag tag) { foreach (int index in indexes) { @@ -437,7 +437,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif return new Collection(); } - Collection result = new Collection(); + var result = new Collection(); for (int i = 0; i < this.values.Count; i++) { ExifValue value = this.values[i]; @@ -457,7 +457,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif return result; } - private uint GetLength(IEnumerable indexes) + private uint GetLength(IList indexes) { uint length = 0; @@ -494,7 +494,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif return newOffset; } - private int WriteData(Collection indexes, byte[] destination, int offset) + private int WriteData(IList indexes, byte[] destination, int offset) { if (this.dataOffsets.Count == 0) { @@ -517,9 +517,9 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif return newOffset; } - private int WriteHeaders(Collection indexes, byte[] destination, int offset) + private int WriteHeaders(IList indexes, byte[] destination, int offset) { - this.dataOffsets = new Collection(); + this.dataOffsets = new List(); int newOffset = Write(BitConverter.GetBytes((ushort)indexes.Count), destination, offset); @@ -550,7 +550,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif return newOffset; } - private int WriteRational(Rational value, byte[] destination, int offset) + private int WriteRational(in Rational value, byte[] destination, int offset) { Write(BitConverter.GetBytes(value.Numerator), destination, offset); Write(BitConverter.GetBytes(value.Denominator), destination, offset + 4); @@ -558,7 +558,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif return offset + 8; } - private int WriteSignedRational(SignedRational value, byte[] destination, int offset) + private int WriteSignedRational(in SignedRational value, byte[] destination, int offset) { Write(BitConverter.GetBytes(value.Numerator), destination, offset); Write(BitConverter.GetBytes(value.Denominator), destination, offset + 4); diff --git a/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs b/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs index 65a469b6f1..7b5924b776 100644 --- a/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs +++ b/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs @@ -141,7 +141,7 @@ namespace SixLabors.ImageSharp.Tests ExifValue value = image.MetaData.ExifProfile.GetValue(ExifTag.Software); TestValue(value, "ImageSharp"); - Assert.Throws(() => { value.Value = 15; }); + Assert.Throws(() => { value.WithValue(15); }); image.MetaData.ExifProfile.SetValue(ExifTag.ShutterSpeedValue, new SignedRational(75.55)); @@ -149,7 +149,7 @@ namespace SixLabors.ImageSharp.Tests TestValue(value, new SignedRational(7555, 100)); - Assert.Throws(() => { value.Value = 75; }); + Assert.Throws(() => { value.WithValue(75); }); image.MetaData.ExifProfile.SetValue(ExifTag.XResolution, new Rational(150.0)); @@ -159,7 +159,7 @@ namespace SixLabors.ImageSharp.Tests value = image.MetaData.ExifProfile.GetValue(ExifTag.XResolution); TestValue(value, new Rational(150, 1)); - Assert.Throws(() => { value.Value = "ImageSharp"; }); + Assert.Throws(() => { value.WithValue("ImageSharp"); }); image.MetaData.ExifProfile.SetValue(ExifTag.ReferenceBlackWhite, null); @@ -209,11 +209,11 @@ namespace SixLabors.ImageSharp.Tests [Fact] public void Syncs() { - ExifProfile exifProfile = new ExifProfile(); + var exifProfile = new ExifProfile(); exifProfile.SetValue(ExifTag.XResolution, new Rational(200)); exifProfile.SetValue(ExifTag.YResolution, new Rational(300)); - ImageMetaData metaData = new ImageMetaData(); + var metaData = new ImageMetaData(); metaData.ExifProfile = exifProfile; metaData.HorizontalResolution = 200; metaData.VerticalResolution = 300; From 29a76e88191826f428d3d66ca1eb9274413bfbad Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Tue, 27 Mar 2018 12:02:49 -0700 Subject: [PATCH 14/32] Remove trailing lines and commas --- src/ImageSharp/Formats/Bmp/BmpBitsPerPixel.cs | 4 ++-- src/ImageSharp/Formats/Bmp/BmpCompression.cs | 2 +- src/ImageSharp/Formats/Bmp/BmpConstants.cs | 2 +- src/ImageSharp/Formats/Bmp/BmpEncoder.cs | 4 +--- src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs | 5 ++--- 5 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/ImageSharp/Formats/Bmp/BmpBitsPerPixel.cs b/src/ImageSharp/Formats/Bmp/BmpBitsPerPixel.cs index d08487cf27..0029a6b68d 100644 --- a/src/ImageSharp/Formats/Bmp/BmpBitsPerPixel.cs +++ b/src/ImageSharp/Formats/Bmp/BmpBitsPerPixel.cs @@ -16,6 +16,6 @@ namespace SixLabors.ImageSharp.Formats.Bmp /// /// 32 bits per pixel. Each pixel consists of 4 bytes. /// - Pixel32 = 4, + Pixel32 = 4 } -} +} \ No newline at end of file diff --git a/src/ImageSharp/Formats/Bmp/BmpCompression.cs b/src/ImageSharp/Formats/Bmp/BmpCompression.cs index 1280498acb..22b12346fb 100644 --- a/src/ImageSharp/Formats/Bmp/BmpCompression.cs +++ b/src/ImageSharp/Formats/Bmp/BmpCompression.cs @@ -58,4 +58,4 @@ namespace SixLabors.ImageSharp.Formats.Bmp /// PNG = 5 } -} +} \ No newline at end of file diff --git a/src/ImageSharp/Formats/Bmp/BmpConstants.cs b/src/ImageSharp/Formats/Bmp/BmpConstants.cs index b7291bb99e..99799b619c 100644 --- a/src/ImageSharp/Formats/Bmp/BmpConstants.cs +++ b/src/ImageSharp/Formats/Bmp/BmpConstants.cs @@ -20,4 +20,4 @@ namespace SixLabors.ImageSharp.Formats.Bmp /// public static readonly IEnumerable FileExtensions = new[] { "bm", "bmp", "dip" }; } -} +} \ No newline at end of file diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoder.cs b/src/ImageSharp/Formats/Bmp/BmpEncoder.cs index d80e43c63b..9edd0fcd4e 100644 --- a/src/ImageSharp/Formats/Bmp/BmpEncoder.cs +++ b/src/ImageSharp/Formats/Bmp/BmpEncoder.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System; -using System.Collections.Generic; using System.IO; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.PixelFormats; @@ -28,4 +26,4 @@ namespace SixLabors.ImageSharp.Formats.Bmp encoder.Encode(image, stream); } } -} +} \ No newline at end of file diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs index 055c22995a..e64c6efec9 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs @@ -26,7 +26,6 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif this.DataType = other.DataType; this.IsArray = other.IsArray; this.Tag = other.Tag; - if (!other.IsArray) { @@ -52,7 +51,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif this.DataType = dataType; this.IsArray = isArray && dataType != ExifDataType.Ascii; this.Value = value; - + // this.CheckValue(value); } @@ -144,7 +143,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif public ExifValue WithValue(object value) { this.CheckValue(value); - + return new ExifValue(this.Tag, this.DataType, value, this.IsArray); } From 38217711880959e0d59b1415bbfc3b91c4f002ae Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Tue, 27 Mar 2018 12:03:10 -0700 Subject: [PATCH 15/32] Remove unused using statements --- .../Conversion/Implementation/CieLch/CIeLchToCieLabConverter.cs | 1 - src/ImageSharp/IImageFrameCollection.cs | 1 - src/ImageSharp/PixelFormats/RgbaVector.PixelOperations.cs | 1 - 3 files changed, 3 deletions(-) diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLch/CIeLchToCieLabConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLch/CIeLchToCieLabConverter.cs index d56ee59f50..0b1ebae0ed 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLch/CIeLchToCieLabConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLch/CIeLchToCieLabConverter.cs @@ -3,7 +3,6 @@ using System; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.ColorSpaces; namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieLchColorSapce { diff --git a/src/ImageSharp/IImageFrameCollection.cs b/src/ImageSharp/IImageFrameCollection.cs index 81b512e221..c9232c7780 100644 --- a/src/ImageSharp/IImageFrameCollection.cs +++ b/src/ImageSharp/IImageFrameCollection.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.Collections; using System.Collections.Generic; using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/PixelFormats/RgbaVector.PixelOperations.cs b/src/ImageSharp/PixelFormats/RgbaVector.PixelOperations.cs index 0817ef5ad3..6a9f38d7ff 100644 --- a/src/ImageSharp/PixelFormats/RgbaVector.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/RgbaVector.PixelOperations.cs @@ -3,7 +3,6 @@ using System; using System.Numerics; -using SixLabors.ImageSharp.Memory; namespace SixLabors.ImageSharp.PixelFormats { From fecab7f03c525dc4d1f03011123a0ceb29e8ca09 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Tue, 27 Mar 2018 12:32:17 -0700 Subject: [PATCH 16/32] Make STYLECOP happy --- src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs | 7 +++---- src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs | 3 +-- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 3 +-- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 3 +-- 4 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs index 4b5b150c49..dfbd44c046 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs @@ -224,7 +224,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp var color = default(TPixel); var rgba = new Rgba32(0, 0, 0, 255); - using (var buffer = this.memoryManager.AllocateClean2D(width, height)) + using (Buffer2D buffer = this.memoryManager.AllocateClean2D(width, height)) { this.UncompressRle8(width, buffer.Span); @@ -398,7 +398,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp var color = default(TPixel); var rgba = new Rgba32(0, 0, 0, 255); - using (var buffer = this.memoryManager.AllocateManagedByteBuffer(stride)) + using (IManagedByteBuffer buffer = this.memoryManager.AllocateManagedByteBuffer(stride)) { for (int y = 0; y < height; y++) { @@ -585,8 +585,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp type: BitConverter.ToInt16(data, 0), fileSize: BitConverter.ToInt32(data, 2), reserved: BitConverter.ToInt32(data, 6), - offset: BitConverter.ToInt32(data, 10) - ); + offset: BitConverter.ToInt32(data, 10)); } /// diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs index 7e4dfde596..be7c1d2e55 100644 --- a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs @@ -73,8 +73,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp type: 19778, // BM offset: 54, reserved: 0, - fileSize: 54 + infoHeader.ImageSize - ); + fileSize: 54 + infoHeader.ImageSize); WriteHeader(writer, fileHeader); this.WriteInfo(writer, infoHeader); diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 2186444739..234ed6bbd0 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -1164,8 +1164,7 @@ namespace SixLabors.ImageSharp.Formats.Png colorType: (PngColorType)data[9], compressionMethod: data[10], filterMethod: data[11], - interlaceMethod: (PngInterlaceMode)data[12] - ); + interlaceMethod: (PngInterlaceMode)data[12]); } /// diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 5f7cd9b23d..17aae17620 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -219,8 +219,7 @@ namespace SixLabors.ImageSharp.Formats.Png bitDepth: this.bitDepth, filterMethod: 0, // None compressionMethod: 0, - interlaceMethod: 0 - ); + interlaceMethod: 0); this.WriteHeaderChunk(stream, header); From 88acab01451b078e279e7356504c0d1f0a0e6206 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Tue, 27 Mar 2018 13:15:51 -0700 Subject: [PATCH 17/32] Address STYLECOP violations, round 2. --- .../MetaData/Profiles/Exif/ExifValue.cs | 24 +++++++++---------- src/ImageSharp/Primitives/SignedRational.cs | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs index e64c6efec9..6d76619e76 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs @@ -135,18 +135,6 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif } } - /// - /// Clones the current value, overwriting the value. - /// - /// The value to overwrite. - /// - public ExifValue WithValue(object value) - { - this.CheckValue(value); - - return new ExifValue(this.Tag, this.DataType, value, this.IsArray); - } - /// /// Compares two objects for equality. /// @@ -211,6 +199,18 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif object.Equals(this.Value, other.Value); } + /// + /// Clones the current value, overwriting the value. + /// + /// The value to overwrite. + /// + public ExifValue WithValue(object value) + { + this.CheckValue(value); + + return new ExifValue(this.Tag, this.DataType, value, this.IsArray); + } + /// public override int GetHashCode() { diff --git a/src/ImageSharp/Primitives/SignedRational.cs b/src/ImageSharp/Primitives/SignedRational.cs index 5cce98d033..bc0e41966e 100644 --- a/src/ImageSharp/Primitives/SignedRational.cs +++ b/src/ImageSharp/Primitives/SignedRational.cs @@ -129,7 +129,7 @@ namespace SixLabors.ImageSharp.Primitives /// public override bool Equals(object obj) { - return obj is SignedRational other && Equals(other); + return obj is SignedRational other && this.Equals(other); } /// From 3f196ee4a128c2bfc36178293186c01c6bbb31b6 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Tue, 27 Mar 2018 13:32:29 -0700 Subject: [PATCH 18/32] Revert "Make PixelTypeInfo a struct" This reverts commit 9269aac086d78c24a0be71c2d52bc44a82f1428b. --- src/ImageSharp/Formats/PixelTypeInfo.cs | 4 ++-- tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs | 2 +- tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs | 2 +- tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs | 4 ++-- tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/ImageSharp/Formats/PixelTypeInfo.cs b/src/ImageSharp/Formats/PixelTypeInfo.cs index c83ce67889..ed21b91bfc 100644 --- a/src/ImageSharp/Formats/PixelTypeInfo.cs +++ b/src/ImageSharp/Formats/PixelTypeInfo.cs @@ -6,10 +6,10 @@ namespace SixLabors.ImageSharp.Formats /// /// Contains information about the pixels that make up an images visual data. /// - public readonly struct PixelTypeInfo + public class PixelTypeInfo { /// - /// Initializes a new instance of the struct. + /// Initializes a new instance of the class. /// /// Color depth, in number of bits per pixel. internal PixelTypeInfo(int bitsPerPixel) diff --git a/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs index c15b0c2b08..d958278f6e 100644 --- a/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs @@ -57,7 +57,7 @@ namespace SixLabors.ImageSharp.Tests var testFile = TestFile.Create(imagePath); using (var stream = new MemoryStream(testFile.Bytes, false)) { - Assert.Equal(expectedPixelSize, Image.Identify(stream)?.PixelType.BitsPerPixel); + Assert.Equal(expectedPixelSize, Image.Identify(stream)?.PixelType?.BitsPerPixel); } } } diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs index 9cd29f460f..9cdb9f8b1a 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs @@ -172,7 +172,7 @@ namespace SixLabors.ImageSharp.Tests TestFile testFile = TestFile.Create(imagePath); using (var stream = new MemoryStream(testFile.Bytes, false)) { - Assert.Equal(expectedPixelSize, Image.Identify(stream)?.PixelType.BitsPerPixel); + Assert.Equal(expectedPixelSize, Image.Identify(stream)?.PixelType?.BitsPerPixel); } } diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs index c7ac71ed92..95ee40e807 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs @@ -397,10 +397,10 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg [InlineData(TestImages.Jpeg.Baseline.Snake, 24)] public void DetectPixelSize(string imagePath, int expectedPixelSize) { - var testFile = TestFile.Create(imagePath); + TestFile testFile = TestFile.Create(imagePath); using (var stream = new MemoryStream(testFile.Bytes, false)) { - Assert.Equal(expectedPixelSize, Image.Identify(stream)?.PixelType.BitsPerPixel); + Assert.Equal(expectedPixelSize, Image.Identify(stream)?.PixelType?.BitsPerPixel); } } } diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs index 8e83f5ffb7..f70e4e3300 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs @@ -228,10 +228,10 @@ namespace SixLabors.ImageSharp.Tests [InlineData(TestImages.Png.Rgb48BppInterlaced, 48)] public void DetectPixelSize(string imagePath, int expectedPixelSize) { - var testFile = TestFile.Create(imagePath); + TestFile testFile = TestFile.Create(imagePath); using (var stream = new MemoryStream(testFile.Bytes, false)) { - Assert.Equal(expectedPixelSize, Image.Identify(stream)?.PixelType.BitsPerPixel); + Assert.Equal(expectedPixelSize, Image.Identify(stream)?.PixelType?.BitsPerPixel); } } From 5405215c1a4d6a4a7e42596cdea051facce9b602 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Tue, 27 Mar 2018 15:39:45 -0700 Subject: [PATCH 19/32] Eliminate intermediate buffer allocations when reading Exif tags --- .../MetaData/Profiles/Exif/ExifReader.cs | 313 +++++++++--------- 1 file changed, 163 insertions(+), 150 deletions(-) diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs index 78e39d8d49..92ec42f35a 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs @@ -2,10 +2,12 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers.Binary; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Text; +using SixLabors.ImageSharp.IO; using SixLabors.ImageSharp.Primitives; namespace SixLabors.ImageSharp.MetaData.Profiles.Exif @@ -15,20 +17,20 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif /// internal sealed class ExifReader { - private readonly Collection invalidTags = new Collection(); + private readonly List invalidTags = new List(); private byte[] exifData; - private uint currentIndex; - private bool isLittleEndian; + private int position; + private Endianness endianness = Endianness.BigEndian; private uint exifOffset; private uint gpsOffset; - private uint startIndex; + private int startIndex; - private delegate TDataType ConverterMethod(byte[] data); + private delegate TDataType ConverterMethod(ReadOnlySpan data); /// /// Gets the invalid tags. /// - public IEnumerable InvalidTags => this.invalidTags; + public IList InvalidTags => this.invalidTags; /// /// Gets the thumbnail length in the byte stream @@ -47,12 +49,12 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif { get { - if (this.currentIndex >= this.exifData.Length) + if (this.position >= this.exifData.Length) { return 0; } - return this.exifData.Length - (int)this.currentIndex; + return this.exifData.Length - (int)this.position; } } @@ -63,55 +65,58 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif /// /// The . /// - public Collection Read(byte[] data) + public List Read(byte[] data) { DebugGuard.NotNull(data, nameof(data)); - var result = new Collection(); + var values = new List(); this.exifData = data; if (this.GetString(4) == "Exif") { - if (this.GetShort() != 0) + if (this.ReadShort() != 0) { - return result; + return values; } this.startIndex = 6; } else { - this.currentIndex = 0; + this.position = 0; } - this.isLittleEndian = this.GetString(2) == "II"; + if (this.GetString(2) == "II") + { + this.endianness = Endianness.LittleEndian; + } - if (this.GetShort() != 0x002A) + if (this.ReadShort() != 0x002A) { - return result; + return values; } - uint ifdOffset = this.GetLong(); - this.AddValues(result, ifdOffset); + uint ifdOffset = this.ReadUInt32(); + this.AddValues(values, (int)ifdOffset); - uint thumbnailOffset = this.GetLong(); - this.GetThumbnail(thumbnailOffset); + uint thumbnailOffset = this.ReadUInt32(); + this.GetThumbnail((int)thumbnailOffset); if (this.exifOffset != 0) { - this.AddValues(result, this.exifOffset); + this.AddValues(values, (int)this.exifOffset); } if (this.gpsOffset != 0) { - this.AddValues(result, this.gpsOffset); + this.AddValues(values, (int)this.gpsOffset); } - return result; + return values; } - private static TDataType[] ToArray(ExifDataType dataType, byte[] data, ConverterMethod converter) + private static TDataType[] ToArray(ExifDataType dataType, ReadOnlySpan data, ConverterMethod converter) { int dataTypeSize = (int)ExifValue.GetSize(dataType); int length = data.Length / dataTypeSize; @@ -121,7 +126,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif for (int i = 0; i < length; i++) { - Array.Copy(data, i * dataTypeSize, buffer, 0, dataTypeSize); + data.Slice(i * dataTypeSize, dataTypeSize).CopyTo(buffer); result.SetValue(converter(buffer), i); } @@ -129,14 +134,14 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif return result; } - private static byte ToByte(byte[] data) - { - return data[0]; - } + private byte ConvertToByte(ReadOnlySpan buffer) => buffer[0]; - private static string ToString(byte[] data) + private unsafe string ConvertToString(ReadOnlySpan buffer) { - string result = Encoding.UTF8.GetString(data, 0, data.Length); + byte[] bytes = buffer.ToArray(); + + string result = Encoding.UTF8.GetString(bytes, 0, buffer.Length); + int nullCharIndex = result.IndexOf('\0'); if (nullCharIndex != -1) { @@ -151,15 +156,14 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif /// /// The values. /// The index. - private void AddValues(Collection values, uint index) + private void AddValues(IList values, int index) { - this.currentIndex = this.startIndex + index; - ushort count = this.GetShort(); + this.position = this.startIndex + index; + ushort count = this.ReadShort(); for (ushort i = 0; i < count; i++) { - ExifValue value = this.CreateValue(); - if (value == null) + if (!this.TryReadValue(out ExifValue value)) { continue; } @@ -200,9 +204,9 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif } } - private object ConvertValue(ExifDataType dataType, byte[] data, uint numberOfComponents) + private object ConvertValue(ExifDataType dataType, ReadOnlySpan buffer, uint numberOfComponents) { - if (data == null || data.Length == 0) + if (buffer == null || buffer.Length == 0) { return null; } @@ -212,106 +216,110 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif case ExifDataType.Unknown: return null; case ExifDataType.Ascii: - return ToString(data); + return this.ConvertToString(buffer); case ExifDataType.Byte: if (numberOfComponents == 1) { - return ToByte(data); + return this.ConvertToByte(buffer); } - return data; + return buffer.ToArray(); case ExifDataType.DoubleFloat: if (numberOfComponents == 1) { - return this.ToDouble(data); + return this.ConvertToDouble(buffer); } - return ToArray(dataType, data, this.ToDouble); + return ToArray(dataType, buffer, this.ConvertToDouble); case ExifDataType.Long: if (numberOfComponents == 1) { - return this.ToLong(data); + return this.ConvertToUInt64(buffer); } - return ToArray(dataType, data, this.ToLong); + return ToArray(dataType, buffer, this.ConvertToUInt64); case ExifDataType.Rational: if (numberOfComponents == 1) { - return this.ToRational(data); + return this.ToRational(buffer); } - return ToArray(dataType, data, this.ToRational); + return ToArray(dataType, buffer, this.ToRational); case ExifDataType.Short: if (numberOfComponents == 1) { - return this.ToShort(data); + return this.ConvertToShort(buffer); } - return ToArray(dataType, data, this.ToShort); + return ToArray(dataType, buffer, this.ConvertToShort); case ExifDataType.SignedByte: if (numberOfComponents == 1) { - return this.ToSignedByte(data); + return this.ConvertToSignedByte(buffer); } - return ToArray(dataType, data, this.ToSignedByte); + return ToArray(dataType, buffer, this.ConvertToSignedByte); case ExifDataType.SignedLong: if (numberOfComponents == 1) { - return this.ToSignedLong(data); + return this.ToInt32(buffer); } - return ToArray(dataType, data, this.ToSignedLong); + return ToArray(dataType, buffer, this.ToInt32); case ExifDataType.SignedRational: if (numberOfComponents == 1) { - return this.ToSignedRational(data); + return this.ToSignedRational(buffer); } - return ToArray(dataType, data, this.ToSignedRational); + return ToArray(dataType, buffer, this.ToSignedRational); case ExifDataType.SignedShort: if (numberOfComponents == 1) { - return this.ToSignedShort(data); + return this.ConvertToSignedShort(buffer); } - return ToArray(dataType, data, this.ToSignedShort); + return ToArray(dataType, buffer, this.ConvertToSignedShort); case ExifDataType.SingleFloat: if (numberOfComponents == 1) { - return this.ToSingle(data); + return this.ConvertToSingle(buffer); } - return ToArray(dataType, data, this.ToSingle); + return ToArray(dataType, buffer, this.ConvertToSingle); case ExifDataType.Undefined: if (numberOfComponents == 1) { - return ToByte(data); + return ConvertToByte(buffer); } - return data; + return buffer.ToArray(); default: throw new NotSupportedException(); } } - private ExifValue CreateValue() + private bool TryReadValue(out ExifValue exifValue) { if (this.RemainingLength < 12) { - return null; + exifValue = default; + + return false; } - ExifTag tag = this.ToEnum(this.GetShort(), ExifTag.Unknown); - ExifDataType dataType = this.ToEnum(this.GetShort(), ExifDataType.Unknown); + ExifTag tag = this.ToEnum(this.ReadShort(), ExifTag.Unknown); + ExifDataType dataType = this.ToEnum(this.ReadShort(), ExifDataType.Unknown); object value; if (dataType == ExifDataType.Unknown) { - return new ExifValue(tag, dataType, null, false); + exifValue = new ExifValue(tag, dataType, null, false); + + return true; } - uint numberOfComponents = this.GetLong(); + uint numberOfComponents = this.ReadUInt32(); // 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) @@ -321,29 +329,36 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif } uint size = numberOfComponents * ExifValue.GetSize(dataType); - byte[] data = this.GetBytes(4); + + this.TryReadSpan(4, out ReadOnlySpan data); if (size > 4) { - uint oldIndex = this.currentIndex; - this.currentIndex = this.ToLong(data) + this.startIndex; + int oldIndex = this.position; + this.position = (int)this.ConvertToUInt64(data) + this.startIndex; if (this.RemainingLength < size) { this.invalidTags.Add(tag); - this.currentIndex = oldIndex; - return null; + this.position = oldIndex; + + exifValue = default; + + return false; } - value = this.ConvertValue(dataType, this.GetBytes(size), numberOfComponents); - this.currentIndex = oldIndex; + this.TryReadSpan((int)size, out ReadOnlySpan innerData); + + value = this.ConvertValue(dataType, innerData, numberOfComponents); + this.position = oldIndex; } else { value = this.ConvertValue(dataType, data, numberOfComponents); } - bool isArray = value != null && numberOfComponents > 1; - return new ExifValue(tag, dataType, value, isArray); + exifValue = new ExifValue(tag, dataType, value, isArray: value != null && numberOfComponents > 1); + + return true; } private TEnum ToEnum(int value, TEnum defaultValue) @@ -358,51 +373,57 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif return defaultValue; } - private byte[] GetBytes(uint length) + private bool TryReadSpan(int length, out ReadOnlySpan span) { - if (this.currentIndex + length > (uint)this.exifData.Length) + if (this.position + length > this.exifData.Length || this.position < 0) { - return null; + span = default; + + return false; } - byte[] data = new byte[length]; - Array.Copy(this.exifData, (int)this.currentIndex, data, 0, (int)length); - this.currentIndex += length; + span = new ReadOnlySpan(this.exifData, this.position, length); + + this.position += length; - return data; + return true; } - private uint GetLong() + private uint ReadUInt32() { - return this.ToLong(this.GetBytes(4)); + // Known as Long in Exif Specification + return this.TryReadSpan(4, out ReadOnlySpan span) + ? this.ConvertToUInt64(span) + : default; } - private ushort GetShort() + private ushort ReadShort() { - return this.ToShort(this.GetBytes(2)); + return this.TryReadSpan(2, out ReadOnlySpan span) + ? this.ConvertToShort(span) + : default; } - private string GetString(uint length) + private string GetString(int length) { - byte[] data = this.GetBytes(length); - if (data == null || data.Length == 0) + if (this.TryReadSpan(length, out ReadOnlySpan span) && span.Length != 0) { - return null; + return this.ConvertToString(span); } - return ToString(data); + return null; } - private void GetThumbnail(uint offset) + private void GetThumbnail(int offset) { - var values = new Collection(); + var values = new List(); this.AddValues(values, offset); foreach (ExifValue value in values) { if (value.Tag == ExifTag.JPEGInterchangeFormat && (value.DataType == ExifDataType.Long)) { - this.ThumbnailOffset = (uint)value.Value + this.startIndex; + this.ThumbnailOffset = (uint)value.Value + (uint)this.startIndex; } else if (value.Tag == ExifTag.JPEGInterchangeFormatLength && value.DataType == ExifDataType.Long) { @@ -411,120 +432,112 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif } } - private double ToDouble(byte[] data) + private unsafe double ConvertToDouble(ReadOnlySpan buffer) { - if (!this.ValidateArray(data, 8)) + if (buffer.Length < 8) { return default; } - return BitConverter.ToDouble(data, 0); + long intValue = this.endianness == Endianness.BigEndian + ? BinaryPrimitives.ReadInt64BigEndian(buffer) + : BinaryPrimitives.ReadInt64LittleEndian(buffer); + + return *((double*)&intValue); } - private uint ToLong(byte[] data) + private uint ConvertToUInt64(ReadOnlySpan buffer) { - if (!this.ValidateArray(data, 4)) + // Known as Long in Exif Specification + if (buffer.Length < 4) { return default; } - return BitConverter.ToUInt32(data, 0); + return this.endianness == Endianness.BigEndian + ? BinaryPrimitives.ReadUInt32BigEndian(buffer) + : BinaryPrimitives.ReadUInt32LittleEndian(buffer); } - private ushort ToShort(byte[] data) + private ushort ConvertToShort(ReadOnlySpan buffer) { - if (!this.ValidateArray(data, 2)) + if (buffer.Length < 2) { return default; } - return BitConverter.ToUInt16(data, 0); + return this.endianness == Endianness.BigEndian + ? BinaryPrimitives.ReadUInt16BigEndian(buffer) + : BinaryPrimitives.ReadUInt16LittleEndian(buffer); } - private float ToSingle(byte[] data) + private unsafe float ConvertToSingle(ReadOnlySpan buffer) { - if (!this.ValidateArray(data, 4)) + if (buffer.Length < 4) { return default; } - return BitConverter.ToSingle(data, 0); + int intValue = this.endianness == Endianness.BigEndian + ? BinaryPrimitives.ReadInt32BigEndian(buffer) + : BinaryPrimitives.ReadInt32LittleEndian(buffer); + + return *((float*)&intValue); } - private Rational ToRational(byte[] data) + private Rational ToRational(ReadOnlySpan buffer) { - if (!this.ValidateArray(data, 8, 4)) + if (buffer.Length < 8) { - return default(Rational); + return default; } - uint numerator = BitConverter.ToUInt32(data, 0); - uint denominator = BitConverter.ToUInt32(data, 4); + uint numerator = ConvertToUInt64(buffer.Slice(0, 4)); + uint denominator = ConvertToUInt64(buffer.Slice(4, 4)); return new Rational(numerator, denominator, false); } - private sbyte ToSignedByte(byte[] data) + private sbyte ConvertToSignedByte(ReadOnlySpan buffer) { - return unchecked((sbyte)data[0]); + return unchecked((sbyte)buffer[0]); } - private int ToSignedLong(byte[] data) + private int ToInt32(ReadOnlySpan buffer) // SignedLong in Exif Specification { - if (!this.ValidateArray(data, 4)) + if (buffer.Length < 4) { - return default(int); + return default; } - return BitConverter.ToInt32(data, 0); + return this.endianness == Endianness.BigEndian + ? BinaryPrimitives.ReadInt32BigEndian(buffer) + : BinaryPrimitives.ReadInt32LittleEndian(buffer); } - private SignedRational ToSignedRational(byte[] data) + private SignedRational ToSignedRational(ReadOnlySpan buffer) { - if (!this.ValidateArray(data, 8, 4)) + if (buffer.Length < 8) { return default; } - int numerator = BitConverter.ToInt32(data, 0); - int denominator = BitConverter.ToInt32(data, 4); + int numerator = this.ToInt32(buffer.Slice(0, 4)); + int denominator = this.ToInt32(buffer.Slice(4, 4)); return new SignedRational(numerator, denominator, false); } - private short ToSignedShort(byte[] data) + private short ConvertToSignedShort(ReadOnlySpan buffer) { - if (!this.ValidateArray(data, 2)) + if (buffer.Length < 2) { return default; } - return BitConverter.ToInt16(data, 0); - } - - private bool ValidateArray(byte[] data, int size) - { - return this.ValidateArray(data, size, size); - } - - private bool ValidateArray(byte[] data, int size, int stepSize) - { - if (data == null || data.Length < size) - { - return false; - } - - if (this.isLittleEndian == BitConverter.IsLittleEndian) - { - return true; - } - - for (int i = 0; i < data.Length; i += stepSize) - { - Array.Reverse(data, i, stepSize); - } - - return true; + return this.endianness == Endianness.BigEndian + ? BinaryPrimitives.ReadInt16BigEndian(buffer) + : BinaryPrimitives.ReadInt16LittleEndian(buffer); } } } \ No newline at end of file From 0ac93761b4c4ef88baf06f5b284e57a6a9891a37 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Tue, 27 Mar 2018 15:41:28 -0700 Subject: [PATCH 20/32] Make InvalidTags & Values tags readonly This is a list to avoid list resizes when constructing from another instance --- .../MetaData/Profiles/Exif/ExifProfile.cs | 26 +++++++++---------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs index 82542d2eea..fcedb4a9c9 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs @@ -23,12 +23,12 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif /// /// The collection of EXIF values /// - private Collection values; + private List values; /// /// The list of invalid EXIF tags /// - private List invalidTags; + private IReadOnlyList invalidTags; /// /// The thumbnail offset position in the byte stream @@ -75,8 +75,9 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif this.invalidTags = new List(other.invalidTags); if (other.values != null) { - this.values = new Collection(); - foreach (ExifValue value in other.values) + this.values = new List(other.Values.Count); + + foreach (ExifValue value in other.Values) { this.values.Add(new ExifValue(value)); } @@ -92,21 +93,17 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif /// /// Gets or sets which parts will be written when the profile is added to an image. /// - public ExifParts Parts - { - get; - set; - } + public ExifParts Parts { get; set; } /// /// Gets the tags that where found but contained an invalid value. /// - public IEnumerable InvalidTags => this.invalidTags; + public IReadOnlyList InvalidTags => this.invalidTags; /// /// Gets the values of this EXIF profile. /// - public IList Values + public IReadOnlyList Values { get { @@ -195,9 +192,10 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif { for (int i = 0; i < this.Values.Count; i++) { - if (this.Values[i].Tag == tag) + if (this.values[i].Tag == tag) { - this.Values[i] = this.Values[i].WithValue(value); + this.values[i] = this.values[i].WithValue(value); + return; } } @@ -263,7 +261,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif if (this.data == null) { - this.values = new Collection(); + this.values = new List(); return; } From 59a42b7f2e359f7f716682ca7c01bf09f8b34afc Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Tue, 27 Mar 2018 15:46:34 -0700 Subject: [PATCH 21/32] Qualify access --- src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs index 92ec42f35a..39779e9e5d 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs @@ -290,7 +290,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif case ExifDataType.Undefined: if (numberOfComponents == 1) { - return ConvertToByte(buffer); + return this.ConvertToByte(buffer); } return buffer.ToArray(); @@ -492,8 +492,8 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif return default; } - uint numerator = ConvertToUInt64(buffer.Slice(0, 4)); - uint denominator = ConvertToUInt64(buffer.Slice(4, 4)); + uint numerator = this.ConvertToUInt64(buffer.Slice(0, 4)); + uint denominator = this.ConvertToUInt64(buffer.Slice(4, 4)); return new Rational(numerator, denominator, false); } From 53c9640a51bc6cb04805fa37d4c4f1b62dfaa1a0 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Tue, 27 Mar 2018 15:51:32 -0700 Subject: [PATCH 22/32] Eliminate two more allocations --- src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs index 39779e9e5d..e4b1efa3bf 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs @@ -6,6 +6,8 @@ using System.Buffers.Binary; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using System.Text; using SixLabors.ImageSharp.IO; using SixLabors.ImageSharp.Primitives; @@ -122,11 +124,10 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif int length = data.Length / dataTypeSize; var result = new TDataType[length]; - var buffer = new byte[dataTypeSize]; for (int i = 0; i < length; i++) { - data.Slice(i * dataTypeSize, dataTypeSize).CopyTo(buffer); + ReadOnlySpan buffer = data.Slice(i * dataTypeSize, dataTypeSize); result.SetValue(converter(buffer), i); } @@ -138,10 +139,16 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif private unsafe string ConvertToString(ReadOnlySpan buffer) { +#if NETSTANDARD1_1 byte[] bytes = buffer.ToArray(); string result = Encoding.UTF8.GetString(bytes, 0, buffer.Length); +#else + byte* pointer = (byte*)Unsafe.AsPointer(ref MemoryMarshal.GetReference(buffer)); + + string result = Encoding.UTF8.GetString(pointer, buffer.Length); +#endif int nullCharIndex = result.IndexOf('\0'); if (nullCharIndex != -1) { From d9142ad0ba972fd708c8e90d6001b93953a24247 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Tue, 27 Mar 2018 16:08:57 -0700 Subject: [PATCH 23/32] Fix tests --- .../MetaData/Profiles/Exif/ExifProfileTests.cs | 2 +- .../MetaData/Profiles/Exif/ExifReaderTests.cs | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs b/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs index 7b5924b776..1ffd75c0e4 100644 --- a/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs +++ b/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs @@ -255,7 +255,7 @@ namespace SixLabors.ImageSharp.Tests [Fact] public void WriteTooLargeProfile() { - StringBuilder junk = new StringBuilder(); + var junk = new StringBuilder(); for (int i = 0; i < 65500; i++) { junk.Append("I"); diff --git a/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifReaderTests.cs b/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifReaderTests.cs index dee6d5ff39..25ac60831a 100644 --- a/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifReaderTests.cs +++ b/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifReaderTests.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System.Collections.Generic; using System.Collections.ObjectModel; using SixLabors.ImageSharp.MetaData.Profiles.Exif; using Xunit; @@ -12,10 +13,10 @@ namespace SixLabors.ImageSharp.Tests [Fact] public void Read_DataIsEmpty_ReturnsEmptyCollection() { - ExifReader reader = new ExifReader(); + var reader = new ExifReader(); byte[] data = new byte[] { }; - Collection result = reader.Read(data); + IList result = reader.Read(data); Assert.Equal(0, result.Count); } @@ -23,10 +24,10 @@ namespace SixLabors.ImageSharp.Tests [Fact] public void Read_DataIsMinimal_ReturnsEmptyCollection() { - ExifReader reader = new ExifReader(); + var reader = new ExifReader(); byte[] data = new byte[] { 69, 120, 105, 102, 0, 0 }; - Collection result = reader.Read(data); + IList result = reader.Read(data); Assert.Equal(0, result.Count); } From 4f2f361a114234f747906dea7af636b8867817bb Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Wed, 28 Mar 2018 08:49:05 -0700 Subject: [PATCH 24/32] Set ExifDataType values explictly (to spec) --- .../MetaData/Profiles/Exif/ExifDataType.cs | 50 +++++++++---------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifDataType.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifDataType.cs index 8c3c1171c7..5bd38b195d 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifDataType.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifDataType.cs @@ -11,66 +11,66 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif /// /// Unknown /// - Unknown, + Unknown = 0, /// - /// Byte + /// An 8-bit unsigned integer. /// - Byte, + Byte = 1, /// - /// Ascii + /// An 8-bit byte containing one 7-bit ASCII code. The final byte is terminated with NULL. /// - Ascii, + Ascii = 2, /// - /// Short + /// A 16-bit (2-byte) unsigned integer. /// - Short, + Short = 3, /// - /// Long + /// A 32-bit (4-byte) unsigned integer. /// - Long, + Long = 4, /// - /// Rational + /// Two LONGs. The first LONG is the numerator and the second LONG expresses the denominator. /// - Rational, + Rational = 5, /// - /// SignedByte + /// An 8-bit signed integer. /// - SignedByte, + SignedByte = 6, /// - /// Undefined + /// An 8-bit byte that can take any value depending on the field definition. /// - Undefined, + Undefined = 7, /// - /// SignedShort + /// A 16-bit (2-byte) signed integer. /// - SignedShort, + SignedShort = 8, /// - /// SignedLong + /// A 32-bit (4-byte) signed integer (2's complement notation). /// - SignedLong, + SignedLong = 9, /// - /// SignedRational + /// Two SLONGs. The first SLONG is the numerator and the second SLONG is the denominator. /// - SignedRational, + SignedRational = 10, /// - /// SingleFloat + /// A 32-bit floating point value. /// - SingleFloat, + SingleFloat = 11, /// - /// DoubleFloat + /// A 64-bit floating point value. /// - DoubleFloat + DoubleFloat = 12 } } \ No newline at end of file From 81cfbb6740ee1408336fbc1e60106930ac00840e Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Wed, 28 Mar 2018 08:52:21 -0700 Subject: [PATCH 25/32] Improve overrun handling, variable names, and validate data on construction --- .../MetaData/Profiles/Exif/ExifProfile.cs | 6 +- .../MetaData/Profiles/Exif/ExifReader.cs | 104 +++++++++++------- .../MetaData/Profiles/Exif/ExifValue.cs | 4 +- .../Profiles/Exif/ExifProfileTests.cs | 7 +- .../MetaData/Profiles/Exif/ExifReaderTests.cs | 11 +- 5 files changed, 77 insertions(+), 55 deletions(-) diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs index fcedb4a9c9..de70c41f52 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs @@ -265,8 +265,10 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif return; } - var reader = new ExifReader(); - this.values = reader.Read(this.data); + var reader = new ExifReader(this.data); + + this.values = reader.ReadValues(); + this.invalidTags = new List(reader.InvalidTags); this.thumbnailOffset = (int)reader.ThumbnailOffset; this.thumbnailLength = (int)reader.ThumbnailLength; diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs index e4b1efa3bf..407030196a 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs @@ -19,15 +19,22 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif /// internal sealed class ExifReader { + private delegate TDataType ConverterMethod(ReadOnlySpan data); + private readonly List invalidTags = new List(); - private byte[] exifData; + private readonly byte[] exifData; private int position; private Endianness endianness = Endianness.BigEndian; private uint exifOffset; private uint gpsOffset; private int startIndex; - private delegate TDataType ConverterMethod(ReadOnlySpan data); + public ExifReader(byte[] exifData) + { + DebugGuard.NotNull(exifData, nameof(exifData)); + + this.exifData = exifData; + } /// /// Gets the invalid tags. @@ -56,28 +63,23 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif return 0; } - return this.exifData.Length - (int)this.position; + return this.exifData.Length - this.position; } } /// /// Reads and returns the collection of EXIF values. /// - /// The data. /// /// The . /// - public List Read(byte[] data) + public List ReadValues() { - DebugGuard.NotNull(data, nameof(data)); - var values = new List(); - this.exifData = data; - - if (this.GetString(4) == "Exif") + if (this.ReadString(4) == "Exif") { - if (this.ReadShort() != 0) + if (this.ReadUInt16() != 0) { return values; } @@ -89,12 +91,12 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif this.position = 0; } - if (this.GetString(2) == "II") + if (this.ReadString(2) == "II") { this.endianness = Endianness.LittleEndian; } - if (this.ReadShort() != 0x002A) + if (this.ReadUInt16() != 0x002A) { return values; } @@ -163,12 +165,12 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif /// /// The values. /// The index. - private void AddValues(IList values, int index) + private void AddValues(List values, int index) { this.position = this.startIndex + index; - ushort count = this.ReadShort(); + int count = this.ReadUInt16(); - for (ushort i = 0; i < count; i++) + for (int i = 0; i < count; i++) { if (!this.TryReadValue(out ExifValue value)) { @@ -241,10 +243,10 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif case ExifDataType.Long: if (numberOfComponents == 1) { - return this.ConvertToUInt64(buffer); + return this.ConvertToUInt32(buffer); } - return ToArray(dataType, buffer, this.ConvertToUInt64); + return ToArray(dataType, buffer, this.ConvertToUInt32); case ExifDataType.Rational: if (numberOfComponents == 1) { @@ -269,10 +271,10 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif case ExifDataType.SignedLong: if (numberOfComponents == 1) { - return this.ToInt32(buffer); + return this.ConvertToInt32(buffer); } - return ToArray(dataType, buffer, this.ToInt32); + return ToArray(dataType, buffer, this.ConvertToInt32); case ExifDataType.SignedRational: if (numberOfComponents == 1) { @@ -308,6 +310,8 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif private bool TryReadValue(out ExifValue exifValue) { + // 2 | 2 | 4 | 4 + // tag | type | count | value offset if (this.RemainingLength < 12) { exifValue = default; @@ -315,17 +319,21 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif return false; } - ExifTag tag = this.ToEnum(this.ReadShort(), ExifTag.Unknown); - ExifDataType dataType = this.ToEnum(this.ReadShort(), ExifDataType.Unknown); - object value; + ExifTag tag = this.ToEnum(this.ReadUInt16(), ExifTag.Unknown); + uint type = this.ReadUInt16(); - if (dataType == ExifDataType.Unknown) + // Ensure that the data type is valid + if (type == 0 || type > 12) { - exifValue = new ExifValue(tag, dataType, null, false); + exifValue = new ExifValue(tag, ExifDataType.Unknown, null, false); return true; } + var dataType = (ExifDataType)type; + + object value; + uint numberOfComponents = this.ReadUInt32(); // Issue #132: ExifDataType == Undefined is treated like a byte array. @@ -337,12 +345,26 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif uint size = numberOfComponents * ExifValue.GetSize(dataType); - this.TryReadSpan(4, out ReadOnlySpan data); + this.TryReadSpan(4, out ReadOnlySpan offsetBuffer); if (size > 4) { int oldIndex = this.position; - this.position = (int)this.ConvertToUInt64(data) + this.startIndex; + + uint newIndex = this.ConvertToUInt32(offsetBuffer) + (uint)this.startIndex; + + // Ensure that the new index does not overrun the data + if (newIndex > int.MaxValue) + { + this.invalidTags.Add(tag); + + exifValue = default; + + return false; + } + + this.position = (int)newIndex; + if (this.RemainingLength < size) { this.invalidTags.Add(tag); @@ -353,14 +375,14 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif return false; } - this.TryReadSpan((int)size, out ReadOnlySpan innerData); + this.TryReadSpan((int)size, out ReadOnlySpan dataBuffer); - value = this.ConvertValue(dataType, innerData, numberOfComponents); + value = this.ConvertValue(dataType, dataBuffer, numberOfComponents); this.position = oldIndex; } else { - value = this.ConvertValue(dataType, data, numberOfComponents); + value = this.ConvertValue(dataType, offsetBuffer, numberOfComponents); } exifValue = new ExifValue(tag, dataType, value, isArray: value != null && numberOfComponents > 1); @@ -382,7 +404,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif private bool TryReadSpan(int length, out ReadOnlySpan span) { - if (this.position + length > this.exifData.Length || this.position < 0) + if (this.RemainingLength < length) { span = default; @@ -390,7 +412,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif } span = new ReadOnlySpan(this.exifData, this.position, length); - + this.position += length; return true; @@ -400,18 +422,18 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif { // Known as Long in Exif Specification return this.TryReadSpan(4, out ReadOnlySpan span) - ? this.ConvertToUInt64(span) + ? this.ConvertToUInt32(span) : default; } - private ushort ReadShort() + private ushort ReadUInt16() { return this.TryReadSpan(2, out ReadOnlySpan span) ? this.ConvertToShort(span) : default; } - private string GetString(int length) + private string ReadString(int length) { if (this.TryReadSpan(length, out ReadOnlySpan span) && span.Length != 0) { @@ -453,7 +475,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif return *((double*)&intValue); } - private uint ConvertToUInt64(ReadOnlySpan buffer) + private uint ConvertToUInt32(ReadOnlySpan buffer) { // Known as Long in Exif Specification if (buffer.Length < 4) @@ -499,8 +521,8 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif return default; } - uint numerator = this.ConvertToUInt64(buffer.Slice(0, 4)); - uint denominator = this.ConvertToUInt64(buffer.Slice(4, 4)); + uint numerator = this.ConvertToUInt32(buffer.Slice(0, 4)); + uint denominator = this.ConvertToUInt32(buffer.Slice(4, 4)); return new Rational(numerator, denominator, false); } @@ -510,7 +532,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif return unchecked((sbyte)buffer[0]); } - private int ToInt32(ReadOnlySpan buffer) // SignedLong in Exif Specification + private int ConvertToInt32(ReadOnlySpan buffer) // SignedLong in Exif Specification { if (buffer.Length < 4) { @@ -529,8 +551,8 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif return default; } - int numerator = this.ToInt32(buffer.Slice(0, 4)); - int denominator = this.ToInt32(buffer.Slice(4, 4)); + int numerator = this.ConvertToInt32(buffer.Slice(0, 4)); + int denominator = this.ConvertToInt32(buffer.Slice(4, 4)); return new SignedRational(numerator, denominator, false); } diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs index 6d76619e76..7b51c6d21c 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs @@ -51,8 +51,6 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif this.DataType = dataType; this.IsArray = isArray && dataType != ExifDataType.Ascii; this.Value = value; - - // this.CheckValue(value); } /// @@ -698,7 +696,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif { return description; } - + switch (this.DataType) { case ExifDataType.Ascii: diff --git a/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs b/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs index 1ffd75c0e4..d98c61279b 100644 --- a/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs +++ b/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs @@ -261,11 +261,11 @@ namespace SixLabors.ImageSharp.Tests junk.Append("I"); } - Image image = new Image(100, 100); + var image = new Image(100, 100); image.MetaData.ExifProfile = new ExifProfile(); image.MetaData.ExifProfile.SetValue(ExifTag.ImageDescription, junk.ToString()); - using (MemoryStream memStream = new MemoryStream()) + using (var memStream = new MemoryStream()) { Assert.Throws(() => image.SaveAsJpeg(memStream)); } @@ -274,6 +274,9 @@ namespace SixLabors.ImageSharp.Tests [Fact] public void ExifTypeUndefined() { + // This image contains an 802 byte EXIF profile + // It has a tag with an index offset of 18,481,152 bytes (overrunning the data) + Image image = TestFile.Create(TestImages.Jpeg.Progressive.Bad.ExifUndefType).CreateImage(); Assert.NotNull(image); diff --git a/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifReaderTests.cs b/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifReaderTests.cs index 25ac60831a..c9542a98a9 100644 --- a/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifReaderTests.cs +++ b/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifReaderTests.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. using System.Collections.Generic; -using System.Collections.ObjectModel; using SixLabors.ImageSharp.MetaData.Profiles.Exif; using Xunit; @@ -13,10 +12,9 @@ namespace SixLabors.ImageSharp.Tests [Fact] public void Read_DataIsEmpty_ReturnsEmptyCollection() { - var reader = new ExifReader(); - byte[] data = new byte[] { }; + var reader = new ExifReader(new byte[] { }); - IList result = reader.Read(data); + IList result = reader.ReadValues(); Assert.Equal(0, result.Count); } @@ -24,10 +22,9 @@ namespace SixLabors.ImageSharp.Tests [Fact] public void Read_DataIsMinimal_ReturnsEmptyCollection() { - var reader = new ExifReader(); - byte[] data = new byte[] { 69, 120, 105, 102, 0, 0 }; + var reader = new ExifReader(new byte[] { 69, 120, 105, 102, 0, 0 }); - IList result = reader.Read(data); + IList result = reader.ReadValues(); Assert.Equal(0, result.Count); } From 1c1592b9d5af97fa813da85ca25666da8fcb329c Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Wed, 28 Mar 2018 09:02:28 -0700 Subject: [PATCH 26/32] Breakout ExifTags from ExifWriter --- .../MetaData/Profiles/Exif/ExifTags.cs | 281 ++++++++++++++++++ .../MetaData/Profiles/Exif/ExifWriter.cs | 281 +----------------- 2 files changed, 286 insertions(+), 276 deletions(-) create mode 100644 src/ImageSharp/MetaData/Profiles/Exif/ExifTags.cs diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifTags.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifTags.cs new file mode 100644 index 0000000000..e497fc7fa4 --- /dev/null +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifTags.cs @@ -0,0 +1,281 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using static SixLabors.ImageSharp.MetaData.Profiles.Exif.ExifTag; + +namespace SixLabors.ImageSharp.MetaData.Profiles.Exif +{ + internal static class ExifTags + { + /// + /// The collection if Image File Directory tags + /// + public static readonly ExifTag[] Ifd = + { + SubfileType, + OldSubfileType, + ImageWidth, + ImageLength, + BitsPerSample, + Compression, + PhotometricInterpretation, + Thresholding, + CellWidth, + CellLength, + FillOrder, + DocumentName, + ImageDescription, + Make, + Model, + StripOffsets, + Orientation, + SamplesPerPixel, + RowsPerStrip, + StripByteCounts, + MinSampleValue, + MaxSampleValue, + XResolution, + YResolution, + PlanarConfiguration, + PageName, + XPosition, + YPosition, + FreeOffsets, + FreeByteCounts, + GrayResponseUnit, + GrayResponseCurve, + T4Options, + T6Options, + ResolutionUnit, + PageNumber, + ColorResponseUnit, + TransferFunction, + Software, + DateTime, + Artist, + HostComputer, + Predictor, + WhitePoint, + PrimaryChromaticities, + ColorMap, + HalftoneHints, + TileWidth, + TileLength, + TileOffsets, + TileByteCounts, + BadFaxLines, + CleanFaxData, + ConsecutiveBadFaxLines, + InkSet, + InkNames, + NumberOfInks, + DotRange, + TargetPrinter, + ExtraSamples, + SampleFormat, + SMinSampleValue, + SMaxSampleValue, + TransferRange, + ClipPath, + XClipPathUnits, + YClipPathUnits, + Indexed, + JPEGTables, + OPIProxy, + ProfileType, + FaxProfile, + CodingMethods, + VersionYear, + ModeNumber, + Decode, + DefaultImageColor, + T82ptions, + JPEGProc, + JPEGInterchangeFormat, + JPEGInterchangeFormatLength, + JPEGRestartInterval, + JPEGLosslessPredictors, + JPEGPointTransforms, + JPEGQTables, + JPEGDCTables, + JPEGACTables, + YCbCrCoefficients, + YCbCrSubsampling, + YCbCrSubsampling, + YCbCrPositioning, + ReferenceBlackWhite, + StripRowCounts, + XMP, + Rating, + RatingPercent, + ImageID, + CFARepeatPatternDim, + CFAPattern2, + BatteryLevel, + Copyright, + MDFileTag, + MDScalePixel, + MDLabName, + MDSampleInfo, + MDPrepDate, + MDPrepTime, + MDFileUnits, + PixelScale, + IntergraphPacketData, + IntergraphRegisters, + IntergraphMatrix, + ModelTiePoint, + SEMInfo, + ModelTransform, + ImageLayer, + FaxRecvParams, + FaxSubaddress, + FaxRecvTime, + ImageSourceData, + XPTitle, + XPComment, + XPAuthor, + XPKeywords, + XPSubject, + GDALMetadata, + GDALNoData + }; + + /// + /// The collection of Exif tags + /// + public static readonly ExifTag[] Exif = + { + ExposureTime, + FNumber, + ExposureProgram, + SpectralSensitivity, + ISOSpeedRatings, + OECF, + Interlace, + TimeZoneOffset, + SelfTimerMode, + SensitivityType, + StandardOutputSensitivity, + RecommendedExposureIndex, + ISOSpeed, + ISOSpeedLatitudeyyy, + ISOSpeedLatitudezzz, + ExifVersion, + DateTimeOriginal, + DateTimeDigitized, + OffsetTime, + OffsetTimeOriginal, + OffsetTimeDigitized, + ComponentsConfiguration, + CompressedBitsPerPixel, + ShutterSpeedValue, + ApertureValue, + BrightnessValue, + ExposureBiasValue, + MaxApertureValue, + SubjectDistance, + MeteringMode, + LightSource, + Flash, + FocalLength, + FlashEnergy2, + SpatialFrequencyResponse2, + Noise, + FocalPlaneXResolution2, + FocalPlaneYResolution2, + FocalPlaneResolutionUnit2, + ImageNumber, + SecurityClassification, + ImageHistory, + SubjectArea, + ExposureIndex2, + TIFFEPStandardID, + SensingMethod2, + MakerNote, + UserComment, + SubsecTime, + SubsecTimeOriginal, + SubsecTimeDigitized, + AmbientTemperature, + Humidity, + Pressure, + WaterDepth, + Acceleration, + CameraElevationAngle, + FlashpixVersion, + ColorSpace, + PixelXDimension, + PixelYDimension, + RelatedSoundFile, + FlashEnergy, + SpatialFrequencyResponse, + FocalPlaneXResolution, + FocalPlaneYResolution, + FocalPlaneResolutionUnit, + SubjectLocation, + ExposureIndex, + SensingMethod, + FileSource, + SceneType, + CFAPattern, + CustomRendered, + ExposureMode, + WhiteBalance, + DigitalZoomRatio, + FocalLengthIn35mmFilm, + SceneCaptureType, + GainControl, + Contrast, + Saturation, + Sharpness, + DeviceSettingDescription, + SubjectDistanceRange, + ImageUniqueID, + OwnerName, + SerialNumber, + LensInfo, + LensMake, + LensModel, + LensSerialNumber + }; + + /// + /// The collection of GPS tags + /// + public static readonly ExifTag[] Gps = + { + GPSVersionID, + GPSLatitudeRef, + GPSLatitude, + GPSLongitudeRef, + GPSLongitude, + GPSAltitudeRef, + GPSAltitude, + GPSTimestamp, + GPSSatellites, + GPSStatus, + GPSMeasureMode, + GPSDOP, + GPSSpeedRef, + GPSSpeed, + GPSTrackRef, + GPSTrack, + GPSImgDirectionRef, + GPSImgDirection, + GPSMapDatum, + GPSDestLatitudeRef, + GPSDestLatitude, + GPSDestLongitudeRef, + GPSDestLongitude, + GPSDestBearingRef, + GPSDestBearing, + GPSDestDistanceRef, + GPSDestDistance, + GPSProcessingMethod, + GPSAreaInformation, + GPSDateStamp, + GPSDifferential + }; + } +} \ No newline at end of file diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifWriter.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifWriter.cs index ef51392dd8..8d8f019c9e 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifWriter.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifWriter.cs @@ -19,277 +19,6 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif /// private const int StartIndex = 6; - /// - /// The collection if Image File Directory tags - /// - private static readonly ExifTag[] IfdTags = - { - ExifTag.SubfileType, - ExifTag.OldSubfileType, - ExifTag.ImageWidth, - ExifTag.ImageLength, - ExifTag.BitsPerSample, - ExifTag.Compression, - ExifTag.PhotometricInterpretation, - ExifTag.Thresholding, - ExifTag.CellWidth, - ExifTag.CellLength, - ExifTag.FillOrder, - ExifTag.DocumentName, - ExifTag.ImageDescription, - ExifTag.Make, - ExifTag.Model, - ExifTag.StripOffsets, - ExifTag.Orientation, - ExifTag.SamplesPerPixel, - ExifTag.RowsPerStrip, - ExifTag.StripByteCounts, - ExifTag.MinSampleValue, - ExifTag.MaxSampleValue, - ExifTag.XResolution, - ExifTag.YResolution, - ExifTag.PlanarConfiguration, - ExifTag.PageName, - ExifTag.XPosition, - ExifTag.YPosition, - ExifTag.FreeOffsets, - ExifTag.FreeByteCounts, - ExifTag.GrayResponseUnit, - ExifTag.GrayResponseCurve, - ExifTag.T4Options, - ExifTag.T6Options, - ExifTag.ResolutionUnit, - ExifTag.PageNumber, - ExifTag.ColorResponseUnit, - ExifTag.TransferFunction, - ExifTag.Software, - ExifTag.DateTime, - ExifTag.Artist, - ExifTag.HostComputer, - ExifTag.Predictor, - ExifTag.WhitePoint, - ExifTag.PrimaryChromaticities, - ExifTag.ColorMap, - ExifTag.HalftoneHints, - ExifTag.TileWidth, - ExifTag.TileLength, - ExifTag.TileOffsets, - ExifTag.TileByteCounts, - ExifTag.BadFaxLines, - ExifTag.CleanFaxData, - ExifTag.ConsecutiveBadFaxLines, - ExifTag.InkSet, - ExifTag.InkNames, - ExifTag.NumberOfInks, - ExifTag.DotRange, - ExifTag.TargetPrinter, - ExifTag.ExtraSamples, - ExifTag.SampleFormat, - ExifTag.SMinSampleValue, - ExifTag.SMaxSampleValue, - ExifTag.TransferRange, - ExifTag.ClipPath, - ExifTag.XClipPathUnits, - ExifTag.YClipPathUnits, - ExifTag.Indexed, - ExifTag.JPEGTables, - ExifTag.OPIProxy, - ExifTag.ProfileType, - ExifTag.FaxProfile, - ExifTag.CodingMethods, - ExifTag.VersionYear, - ExifTag.ModeNumber, - ExifTag.Decode, - ExifTag.DefaultImageColor, - ExifTag.T82ptions, - ExifTag.JPEGProc, - ExifTag.JPEGInterchangeFormat, - ExifTag.JPEGInterchangeFormatLength, - ExifTag.JPEGRestartInterval, - ExifTag.JPEGLosslessPredictors, - ExifTag.JPEGPointTransforms, - ExifTag.JPEGQTables, - ExifTag.JPEGDCTables, - ExifTag.JPEGACTables, - ExifTag.YCbCrCoefficients, - ExifTag.YCbCrSubsampling, - ExifTag.YCbCrSubsampling, - ExifTag.YCbCrPositioning, - ExifTag.ReferenceBlackWhite, - ExifTag.StripRowCounts, - ExifTag.XMP, - ExifTag.Rating, - ExifTag.RatingPercent, - ExifTag.ImageID, - ExifTag.CFARepeatPatternDim, - ExifTag.CFAPattern2, - ExifTag.BatteryLevel, - ExifTag.Copyright, - ExifTag.MDFileTag, - ExifTag.MDScalePixel, - ExifTag.MDLabName, - ExifTag.MDSampleInfo, - ExifTag.MDPrepDate, - ExifTag.MDPrepTime, - ExifTag.MDFileUnits, - ExifTag.PixelScale, - ExifTag.IntergraphPacketData, - ExifTag.IntergraphRegisters, - ExifTag.IntergraphMatrix, - ExifTag.ModelTiePoint, - ExifTag.SEMInfo, - ExifTag.ModelTransform, - ExifTag.ImageLayer, - ExifTag.FaxRecvParams, - ExifTag.FaxSubaddress, - ExifTag.FaxRecvTime, - ExifTag.ImageSourceData, - ExifTag.XPTitle, - ExifTag.XPComment, - ExifTag.XPAuthor, - ExifTag.XPKeywords, - ExifTag.XPSubject, - ExifTag.GDALMetadata, - ExifTag.GDALNoData - }; - - /// - /// The collection of Exif tags - /// - private static readonly ExifTag[] ExifTags = - { - ExifTag.ExposureTime, - ExifTag.FNumber, - ExifTag.ExposureProgram, - ExifTag.SpectralSensitivity, - ExifTag.ISOSpeedRatings, - ExifTag.OECF, - ExifTag.Interlace, - ExifTag.TimeZoneOffset, - ExifTag.SelfTimerMode, - ExifTag.SensitivityType, - ExifTag.StandardOutputSensitivity, - ExifTag.RecommendedExposureIndex, - ExifTag.ISOSpeed, - ExifTag.ISOSpeedLatitudeyyy, - ExifTag.ISOSpeedLatitudezzz, - ExifTag.ExifVersion, - ExifTag.DateTimeOriginal, - ExifTag.DateTimeDigitized, - ExifTag.OffsetTime, - ExifTag.OffsetTimeOriginal, - ExifTag.OffsetTimeDigitized, - ExifTag.ComponentsConfiguration, - ExifTag.CompressedBitsPerPixel, - ExifTag.ShutterSpeedValue, - ExifTag.ApertureValue, - ExifTag.BrightnessValue, - ExifTag.ExposureBiasValue, - ExifTag.MaxApertureValue, - ExifTag.SubjectDistance, - ExifTag.MeteringMode, - ExifTag.LightSource, - ExifTag.Flash, - ExifTag.FocalLength, - ExifTag.FlashEnergy2, - ExifTag.SpatialFrequencyResponse2, - ExifTag.Noise, - ExifTag.FocalPlaneXResolution2, - ExifTag.FocalPlaneYResolution2, - ExifTag.FocalPlaneResolutionUnit2, - ExifTag.ImageNumber, - ExifTag.SecurityClassification, - ExifTag.ImageHistory, - ExifTag.SubjectArea, - ExifTag.ExposureIndex2, - ExifTag.TIFFEPStandardID, - ExifTag.SensingMethod2, - ExifTag.MakerNote, - ExifTag.UserComment, - ExifTag.SubsecTime, - ExifTag.SubsecTimeOriginal, - ExifTag.SubsecTimeDigitized, - ExifTag.AmbientTemperature, - ExifTag.Humidity, - ExifTag.Pressure, - ExifTag.WaterDepth, - ExifTag.Acceleration, - ExifTag.CameraElevationAngle, - ExifTag.FlashpixVersion, - ExifTag.ColorSpace, - ExifTag.PixelXDimension, - ExifTag.PixelYDimension, - ExifTag.RelatedSoundFile, - ExifTag.FlashEnergy, - ExifTag.SpatialFrequencyResponse, - ExifTag.FocalPlaneXResolution, - ExifTag.FocalPlaneYResolution, - ExifTag.FocalPlaneResolutionUnit, - ExifTag.SubjectLocation, - ExifTag.ExposureIndex, - ExifTag.SensingMethod, - ExifTag.FileSource, - ExifTag.SceneType, - ExifTag.CFAPattern, - ExifTag.CustomRendered, - ExifTag.ExposureMode, - ExifTag.WhiteBalance, - ExifTag.DigitalZoomRatio, - ExifTag.FocalLengthIn35mmFilm, - ExifTag.SceneCaptureType, - ExifTag.GainControl, - ExifTag.Contrast, - ExifTag.Saturation, - ExifTag.Sharpness, - ExifTag.DeviceSettingDescription, - ExifTag.SubjectDistanceRange, - ExifTag.ImageUniqueID, - ExifTag.OwnerName, - ExifTag.SerialNumber, - ExifTag.LensInfo, - ExifTag.LensMake, - ExifTag.LensModel, - ExifTag.LensSerialNumber - }; - - /// - /// The collection of GPS tags - /// - private static readonly ExifTag[] GPSTags = - { - ExifTag.GPSVersionID, - ExifTag.GPSLatitudeRef, - ExifTag.GPSLatitude, - ExifTag.GPSLongitudeRef, - ExifTag.GPSLongitude, - ExifTag.GPSAltitudeRef, - ExifTag.GPSAltitude, - ExifTag.GPSTimestamp, - ExifTag.GPSSatellites, - ExifTag.GPSStatus, - ExifTag.GPSMeasureMode, - ExifTag.GPSDOP, - ExifTag.GPSSpeedRef, - ExifTag.GPSSpeed, - ExifTag.GPSTrackRef, - ExifTag.GPSTrack, - ExifTag.GPSImgDirectionRef, - ExifTag.GPSImgDirection, - ExifTag.GPSMapDatum, - ExifTag.GPSDestLatitudeRef, - ExifTag.GPSDestLatitude, - ExifTag.GPSDestLongitudeRef, - ExifTag.GPSDestLongitude, - ExifTag.GPSDestBearingRef, - ExifTag.GPSDestBearing, - ExifTag.GPSDestDistanceRef, - ExifTag.GPSDestDistance, - ExifTag.GPSProcessingMethod, - ExifTag.GPSAreaInformation, - ExifTag.GPSDateStamp, - ExifTag.GPSDifferential - }; - /// /// Which parts will be written. /// @@ -309,9 +38,9 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif { this.values = values; this.allowedParts = allowedParts; - this.ifdIndexes = this.GetIndexes(ExifParts.IfdTags, IfdTags); - this.exifIndexes = this.GetIndexes(ExifParts.ExifTags, ExifTags); - this.gpsIndexes = this.GetIndexes(ExifParts.GPSTags, GPSTags); + this.ifdIndexes = this.GetIndexes(ExifParts.IfdTags, ExifTags.Ifd); + this.exifIndexes = this.GetIndexes(ExifParts.ExifTags, ExifTags.Exif); + this.gpsIndexes = this.GetIndexes(ExifParts.GPSTags, ExifTags.Gps); } /// @@ -430,14 +159,14 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif return newIndex; } - private Collection GetIndexes(ExifParts part, ExifTag[] tags) + private List GetIndexes(ExifParts part, ExifTag[] tags) { if (((int)this.allowedParts & (int)part) == 0) { return new Collection(); } - var result = new Collection(); + var result = new List(); for (int i = 0; i < this.values.Count; i++) { ExifValue value = this.values[i]; From 291f5a5199b95ff1dba2925d3256debe06208a99 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Wed, 28 Mar 2018 10:05:05 -0700 Subject: [PATCH 27/32] First pass on ExifWriter spanification --- .../MetaData/Profiles/Exif/ExifReader.cs | 6 +- .../MetaData/Profiles/Exif/ExifValue.cs | 2 +- .../MetaData/Profiles/Exif/ExifWriter.cs | 115 ++++++++++++------ 3 files changed, 82 insertions(+), 41 deletions(-) diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs index 407030196a..05d6819b5a 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs @@ -19,8 +19,6 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif /// internal sealed class ExifReader { - private delegate TDataType ConverterMethod(ReadOnlySpan data); - private readonly List invalidTags = new List(); private readonly byte[] exifData; private int position; @@ -36,6 +34,8 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif this.exifData = exifData; } + private delegate TDataType ConverterMethod(ReadOnlySpan data); + /// /// Gets the invalid tags. /// @@ -412,7 +412,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif } span = new ReadOnlySpan(this.exifData, this.position, length); - + this.position += length; return true; diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs index 7b51c6d21c..6367cbb83d 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs @@ -696,7 +696,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif { return description; } - + switch (this.DataType) { case ExifDataType.Ascii: diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifWriter.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifWriter.cs index 8d8f019c9e..f7363ef314 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifWriter.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifWriter.cs @@ -2,8 +2,8 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers.Binary; using System.Collections.Generic; -using System.Collections.ObjectModel; using System.Text; using SixLabors.ImageSharp.Primitives; @@ -24,10 +24,10 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif /// private ExifParts allowedParts; private IList values; - private IList dataOffsets; - private IList ifdIndexes; - private IList exifIndexes; - private IList gpsIndexes; + private List dataOffsets; + private List ifdIndexes; + private List exifIndexes; + private List gpsIndexes; /// /// Initializes a new instance of the class. @@ -89,6 +89,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif length += 10 + 4 + 2; byte[] result = new byte[length]; + result[0] = (byte)'E'; result[1] = (byte)'x'; result[2] = (byte)'i'; @@ -114,9 +115,9 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif this.values[gpsIndex] = this.values[gpsIndex].WithValue(ifdOffset + ifdLength + exifLength); } - i = Write(BitConverter.GetBytes(ifdOffset), result, i); + i = WriteUInt32(ifdOffset, result, i); i = this.WriteHeaders(this.ifdIndexes, result, i); - i = Write(BitConverter.GetBytes(thumbnailOffset), result, i); + i = WriteUInt32(thumbnailOffset, result, i); i = this.WriteData(this.ifdIndexes, result, i); if (exifLength > 0) @@ -131,18 +132,60 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif i = this.WriteData(this.gpsIndexes, result, i); } - Write(BitConverter.GetBytes((ushort)0), result, i); + WriteUInt16((ushort)0, result, i); return result; } - private static int Write(byte[] source, byte[] destination, int offset) + private static unsafe int WriteSingle(float value, Span destination, int offset) + { + BinaryPrimitives.WriteInt32LittleEndian(destination.Slice(offset, 4), *((int*)&value)); + + return offset + 4; + } + + private static unsafe int WriteDouble(double value, Span destination, int offset) { - Buffer.BlockCopy(source, 0, destination, offset, source.Length); + BinaryPrimitives.WriteInt64LittleEndian(destination.Slice(offset, 8), *((long*)&value)); + + return offset + 8; + } + + private static int Write(ReadOnlySpan source, Span destination, int offset) + { + source.CopyTo(destination.Slice(offset, source.Length)); return offset + source.Length; } + private static int WriteInt16(short value, Span destination, int offset) + { + BinaryPrimitives.WriteInt16LittleEndian(destination.Slice(offset, 2), value); + + return offset + 2; + } + + private static int WriteUInt16(ushort value, Span destination, int offset) + { + BinaryPrimitives.WriteUInt16LittleEndian(destination.Slice(offset, 2), value); + + return offset + 2; + } + + private static int WriteUInt32(uint value, Span destination, int offset) + { + BinaryPrimitives.WriteUInt32LittleEndian(destination.Slice(offset, 4), value); + + return offset + 4; + } + + private static int WriteInt32(int value, Span destination, int offset) + { + BinaryPrimitives.WriteInt32LittleEndian(destination.Slice(offset, 4), value); + + return offset + 4; + } + private int GetIndex(IList indexes, ExifTag tag) { foreach (int index in indexes) @@ -163,7 +206,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif { if (((int)this.allowedParts & (int)part) == 0) { - return new Collection(); + return new List(); } var result = new List(); @@ -223,7 +266,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif return newOffset; } - private int WriteData(IList indexes, byte[] destination, int offset) + private int WriteData(List indexes, byte[] destination, int offset) { if (this.dataOffsets.Count == 0) { @@ -238,7 +281,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif ExifValue value = this.values[index]; if (value.Length > 4) { - Write(BitConverter.GetBytes(newOffset - StartIndex), destination, this.dataOffsets[i++]); + WriteUInt32((uint)(newOffset - StartIndex), destination, this.dataOffsets[i++]); newOffset = this.WriteValue(value, destination, newOffset); } } @@ -246,11 +289,11 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif return newOffset; } - private int WriteHeaders(IList indexes, byte[] destination, int offset) + private int WriteHeaders(List indexes, byte[] destination, int offset) { this.dataOffsets = new List(); - int newOffset = Write(BitConverter.GetBytes((ushort)indexes.Count), destination, offset); + int newOffset = WriteUInt16((ushort)indexes.Count, destination, offset); if (indexes.Count == 0) { @@ -260,9 +303,9 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif foreach (int index in indexes) { ExifValue value = this.values[index]; - newOffset = Write(BitConverter.GetBytes((ushort)value.Tag), destination, newOffset); - newOffset = Write(BitConverter.GetBytes((ushort)value.DataType), destination, newOffset); - newOffset = Write(BitConverter.GetBytes((uint)value.NumberOfComponents), destination, newOffset); + newOffset = WriteUInt16((ushort)value.Tag, destination, newOffset); + newOffset = WriteUInt16((ushort)value.DataType, destination, newOffset); + newOffset = WriteUInt32((uint)value.NumberOfComponents, destination, newOffset); if (value.Length > 4) { @@ -279,23 +322,19 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif return newOffset; } - private int WriteRational(in Rational value, byte[] destination, int offset) + private static void WriteRational(Span destination, in Rational value) { - Write(BitConverter.GetBytes(value.Numerator), destination, offset); - Write(BitConverter.GetBytes(value.Denominator), destination, offset + 4); - - return offset + 8; + BinaryPrimitives.WriteUInt32LittleEndian(destination.Slice(0, 4), value.Numerator); + BinaryPrimitives.WriteUInt32LittleEndian(destination.Slice(4, 4), value.Denominator); } - private int WriteSignedRational(in SignedRational value, byte[] destination, int offset) + private static void WriteSignedRational(Span destination, in SignedRational value) { - Write(BitConverter.GetBytes(value.Numerator), destination, offset); - Write(BitConverter.GetBytes(value.Denominator), destination, offset + 4); - - return offset + 8; + BinaryPrimitives.WriteInt32LittleEndian(destination.Slice(0, 4), value.Numerator); + BinaryPrimitives.WriteInt32LittleEndian(destination.Slice(4, 4), value.Denominator); } - private int WriteValue(ExifDataType dataType, object value, byte[] destination, int offset) + private int WriteValue(ExifDataType dataType, object value, Span destination, int offset) { switch (dataType) { @@ -306,24 +345,26 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif destination[offset] = (byte)value; return offset + 1; case ExifDataType.DoubleFloat: - return Write(BitConverter.GetBytes((double)value), destination, offset); + return WriteDouble((double)value, destination, offset); case ExifDataType.Short: - return Write(BitConverter.GetBytes((ushort)value), destination, offset); + return WriteUInt16((ushort)value, destination, offset); case ExifDataType.Long: - return Write(BitConverter.GetBytes((uint)value), destination, offset); + return WriteUInt32((uint)value, destination, offset); case ExifDataType.Rational: - return this.WriteRational((Rational)value, destination, offset); + WriteRational(destination.Slice(offset, 8), (Rational)value); + return offset + 8; case ExifDataType.SignedByte: destination[offset] = unchecked((byte)((sbyte)value)); return offset + 1; case ExifDataType.SignedLong: - return Write(BitConverter.GetBytes((int)value), destination, offset); + return WriteInt32((int)value, destination, offset); case ExifDataType.SignedShort: - return Write(BitConverter.GetBytes((short)value), destination, offset); + return WriteInt16((short)value, destination, offset); case ExifDataType.SignedRational: - return this.WriteSignedRational((SignedRational)value, destination, offset); + WriteSignedRational(destination.Slice(offset, 8), (SignedRational)value); + return offset + 8; case ExifDataType.SingleFloat: - return Write(BitConverter.GetBytes((float)value), destination, offset); + return WriteSingle((float)value, destination, offset); default: throw new NotImplementedException(); } From 71741ffb870da680d03d7c867a1d13bca20dce13 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Fri, 30 Mar 2018 12:02:02 -0700 Subject: [PATCH 28/32] Add and utilize TryGetValue on ExifProfile --- .../Jpeg/GolangPort/OrigJpegDecoderCore.cs | 11 +++++--- .../Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs | 11 +++++--- .../MetaData/Profiles/Exif/ExifProfile.cs | 25 +++++++++++++++++++ .../MetaData/Profiles/Exif/ExifValue.cs | 3 +-- 4 files changed, 40 insertions(+), 10 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/GolangPort/OrigJpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/GolangPort/OrigJpegDecoderCore.cs index 0125d2703b..183076ac58 100644 --- a/src/ImageSharp/Formats/Jpeg/GolangPort/OrigJpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/GolangPort/OrigJpegDecoderCore.cs @@ -427,10 +427,13 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort { if (this.isExif) { - ExifValue horizontal = this.MetaData.ExifProfile.GetValue(ExifTag.XResolution); - ExifValue vertical = this.MetaData.ExifProfile.GetValue(ExifTag.YResolution); - double horizontalValue = horizontal != null ? ((Rational)horizontal.Value).ToDouble() : 0; - double verticalValue = vertical != null ? ((Rational)vertical.Value).ToDouble() : 0; + double horizontalValue = this.MetaData.ExifProfile.TryGetValue(ExifTag.XResolution, out var horizonalTag) + ? ((Rational)horizonalTag.Value).ToDouble() + : 0; + + double verticalValue = this.MetaData.ExifProfile.TryGetValue(ExifTag.YResolution, out var verticalTag) + ? ((Rational)verticalTag.Value).ToDouble() + : 0; if (horizontalValue > 0 && verticalValue > 0) { diff --git a/src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs index a600658b02..ba5362993f 100644 --- a/src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs @@ -380,10 +380,13 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort { if (this.isExif) { - ExifValue horizontal = image.MetaData.ExifProfile.GetValue(ExifTag.XResolution); - ExifValue vertical = image.MetaData.ExifProfile.GetValue(ExifTag.YResolution); - double horizontalValue = horizontal != null ? ((Rational)horizontal.Value).ToDouble() : 0; - double verticalValue = vertical != null ? ((Rational)vertical.Value).ToDouble() : 0; + double horizontalValue = image.MetaData.ExifProfile.TryGetValue(ExifTag.XResolution, out var horizontalTag) + ? ((Rational)horizontalTag.Value).ToDouble() + : 0; + + double verticalValue = image.MetaData.ExifProfile.TryGetValue(ExifTag.YResolution, out var verticalTag) + ? ((Rational)verticalTag.Value).ToDouble() + : 0; if (horizontalValue > 0 && verticalValue > 0) { diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs index de70c41f52..4178bcec80 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs @@ -160,6 +160,31 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif return null; } + /// + /// Conditionally the value of the tag if it exists. + /// + /// The tag of the EXIF value. + /// The value of the tag, if found. + /// + /// The . + /// + public bool TryGetValue(ExifTag tag, out ExifValue value) + { + foreach (ExifValue exifValue in this.Values) + { + if (exifValue.Tag == tag) + { + value = exifValue; + + return true; + } + } + + value = default; + + return false; + } + /// /// Removes the value with the specified tag. /// diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs index 6367cbb83d..bdd902e239 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs @@ -691,8 +691,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif /// The private string ToString(object value) { - string description = ExifTagDescriptionAttribute.GetDescription(this.Tag, value); - if (description != null) + if (ExifTagDescriptionAttribute.GetDescription(this.Tag, value) is string description) { return description; } From 04ad13f07edbc5e0fa95858cb23ae1646ca86529 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Fri, 30 Mar 2018 13:54:39 -0700 Subject: [PATCH 29/32] Make LongRational immutable --- src/ImageSharp/Primitives/LongRational.cs | 271 ++++++-------------- src/ImageSharp/Primitives/Rational.cs | 18 +- src/ImageSharp/Primitives/SignedRational.cs | 18 +- 3 files changed, 98 insertions(+), 209 deletions(-) diff --git a/src/ImageSharp/Primitives/LongRational.cs b/src/ImageSharp/Primitives/LongRational.cs index 9addf1e18a..d790b110d0 100644 --- a/src/ImageSharp/Primitives/LongRational.cs +++ b/src/ImageSharp/Primitives/LongRational.cs @@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.Primitives /// /// This is a very simplified implementation of a rational number designed for use with metadata only. /// - internal struct LongRational : IEquatable + internal readonly struct LongRational : IEquatable { /// /// Initializes a new instance of the struct. @@ -26,126 +26,25 @@ namespace SixLabors.ImageSharp.Primitives /// The number below the line in a vulgar fraction; a divisor. /// public LongRational(long numerator, long denominator) - : this(numerator, denominator, false) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// - /// The number above the line in a vulgar fraction showing how many of the parts - /// indicated by the denominator are taken. - /// - /// - /// The number below the line in a vulgar fraction; a divisor. - /// - /// - /// Whether to attempt to simplify the fractional parts. - /// - public LongRational(long numerator, long denominator, bool simplify) - : this() { this.Numerator = numerator; this.Denominator = denominator; - - if (simplify) - { - this.Simplify(); - } - } - - /// - /// Initializes a new instance of the struct. - /// - /// The to create the instance from. - /// Whether to use the best possible precision when parsing the value. - public LongRational(double value, bool bestPrecision) - : this() - { - if (double.IsNaN(value)) - { - this.Numerator = this.Denominator = 0; - return; - } - - if (double.IsPositiveInfinity(value)) - { - this.Numerator = 1; - this.Denominator = 0; - return; - } - - if (double.IsNegativeInfinity(value)) - { - this.Numerator = -1; - this.Denominator = 0; - return; - } - - this.Numerator = 1; - this.Denominator = 1; - - double val = Math.Abs(value); - double df = this.Numerator / (double)this.Denominator; - double epsilon = bestPrecision ? double.Epsilon : .000001; - - while (Math.Abs(df - val) > epsilon) - { - if (df < val) - { - this.Numerator++; - } - else - { - this.Denominator++; - this.Numerator = (int)(val * this.Denominator); - } - - df = this.Numerator / (double)this.Denominator; - } - - if (value < 0.0) - { - this.Numerator *= -1; - } - - this.Simplify(); } /// /// Gets the numerator of a number. /// - public long Numerator - { - get; - private set; - } + public long Numerator { get; } /// /// Gets the denominator of a number. /// - public long Denominator - { - get; - private set; - } + public long Denominator { get; } /// /// Gets a value indicating whether this instance is indeterminate. /// - public bool IsIndeterminate - { - get - { - if (this.Denominator != 0) - { - return false; - } - - return this.Numerator == 0; - } - } + public bool IsIndeterminate => this.Denominator == 0 && this.Numerator == 0; /// /// Gets a value indicating whether this instance is an integer (n, 1) @@ -155,76 +54,28 @@ namespace SixLabors.ImageSharp.Primitives /// /// Gets a value indicating whether this instance is equal to negative infinity (-1, 0) /// - public bool IsNegativeInfinity - { - get - { - if (this.Denominator != 0) - { - return false; - } - - return this.Numerator == -1; - } - } + public bool IsNegativeInfinity => this.Denominator == 0 && this.Numerator == -1; /// /// Gets a value indicating whether this instance is equal to positive infinity (1, 0) /// - public bool IsPositiveInfinity - { - get - { - if (this.Denominator != 0) - { - return false; - } - - return this.Numerator == 1; - } - } + public bool IsPositiveInfinity => this.Denominator == 0 && this.Numerator == 1; /// /// Gets a value indicating whether this instance is equal to 0 (0, 1) /// - public bool IsZero - { - get - { - if (this.Denominator != 1) - { - return false; - } - - return this.Numerator == 0; - } - } + public bool IsZero => this.Denominator == 1 && this.Numerator == 0; /// public bool Equals(LongRational other) { - if (this.Denominator == other.Denominator) - { - return this.Numerator == other.Numerator; - } - - if (this.Numerator == 0 && this.Denominator == 0) - { - return other.Numerator == 0 && other.Denominator == 0; - } - - if (other.Numerator == 0 && other.Denominator == 0) - { - return this.Numerator == 0 && this.Denominator == 0; - } - - return (this.Numerator * other.Denominator) == (this.Denominator * other.Numerator); + return this.Numerator == other.Numerator && this.Denominator == other.Denominator; } /// public override int GetHashCode() { - return this.GetHashCode(this); + return ((this.Numerator * 397) ^ this.Denominator).GetHashCode(); } /// @@ -276,78 +127,100 @@ namespace SixLabors.ImageSharp.Primitives } /// - /// Finds the greatest common divisor of two values. + /// Create a new instance of the struct from a double value. /// - /// The first value - /// The second value - /// The - private static long GreatestCommonDivisor(long left, long right) + /// The to create the instance from. + /// Whether to use the best possible precision when parsing the value. + public static LongRational FromDouble(double value, bool bestPrecision) { - return right == 0 ? left : GreatestCommonDivisor(right, left % right); - } + if (double.IsNaN(value)) + { + return new LongRational(0, 0); + } - /// - /// Simplifies the - /// - private void Simplify() - { - if (this.IsIndeterminate) + if (double.IsPositiveInfinity(value)) { - return; + return new LongRational(1, 0); } - if (this.IsNegativeInfinity) + if (double.IsNegativeInfinity(value)) { - return; + return new LongRational(-1, 0); } - if (this.IsPositiveInfinity) + long numerator = 1; + long denominator = 1; + + double val = Math.Abs(value); + double df = numerator / (double)denominator; + double epsilon = bestPrecision ? double.Epsilon : .000001; + + while (Math.Abs(df - val) > epsilon) { - return; + if (df < val) + { + numerator++; + } + else + { + denominator++; + numerator = (int)(val * denominator); + } + + df = numerator / (double)denominator; } - if (this.IsInteger) + if (value < 0.0) { - return; + numerator *= -1; } - if (this.IsZero) + return new LongRational(numerator, denominator).Simplify(); + } + + /// + /// Finds the greatest common divisor of two values. + /// + /// The first value + /// The second value + /// The + private static long GreatestCommonDivisor(long left, long right) + { + return right == 0 ? left : GreatestCommonDivisor(right, left % right); + } + + /// + /// Simplifies the + /// + public LongRational Simplify() + { + if (this.IsIndeterminate || + this.IsNegativeInfinity || + this.IsPositiveInfinity || + this.IsInteger || + this.IsZero) { - return; + return this; } if (this.Numerator == 0) { - this.Denominator = 0; - return; + return new LongRational(0, 0); } if (this.Numerator == this.Denominator) { - this.Numerator = 1; - this.Denominator = 1; + return new LongRational(1, 1); } long gcd = GreatestCommonDivisor(Math.Abs(this.Numerator), Math.Abs(this.Denominator)); + if (gcd > 1) { - this.Numerator = this.Numerator / gcd; - this.Denominator = this.Denominator / gcd; + return new LongRational(this.Numerator / gcd, this.Denominator / gcd); } - } - /// - /// Returns the hash code for this instance. - /// - /// - /// The instance of to return the hash code for. - /// - /// - /// A 32-bit signed integer that is the hash code for this instance. - /// - private int GetHashCode(LongRational rational) - { - return ((rational.Numerator * 397) ^ rational.Denominator).GetHashCode(); + return this; } } } \ No newline at end of file diff --git a/src/ImageSharp/Primitives/Rational.cs b/src/ImageSharp/Primitives/Rational.cs index fa3961ffa8..b598f0e02f 100644 --- a/src/ImageSharp/Primitives/Rational.cs +++ b/src/ImageSharp/Primitives/Rational.cs @@ -41,10 +41,18 @@ namespace SixLabors.ImageSharp.Primitives /// Specified if the rational should be simplified. public Rational(uint numerator, uint denominator, bool simplify) { - var rational = new LongRational(numerator, denominator, simplify); - - this.Numerator = (uint)rational.Numerator; - this.Denominator = (uint)rational.Denominator; + if (simplify) + { + LongRational rational = new LongRational(numerator, denominator).Simplify(); + + this.Numerator = (uint)rational.Numerator; + this.Denominator = (uint)rational.Denominator; + } + else + { + this.Numerator = numerator; + this.Denominator = denominator; + } } /// @@ -63,7 +71,7 @@ namespace SixLabors.ImageSharp.Primitives /// Whether to use the best possible precision when parsing the value. public Rational(double value, bool bestPrecision) { - var rational = new LongRational(Math.Abs(value), bestPrecision); + var rational = LongRational.FromDouble(Math.Abs(value), bestPrecision); this.Numerator = (uint)rational.Numerator; this.Denominator = (uint)rational.Denominator; diff --git a/src/ImageSharp/Primitives/SignedRational.cs b/src/ImageSharp/Primitives/SignedRational.cs index bc0e41966e..7e486e4f22 100644 --- a/src/ImageSharp/Primitives/SignedRational.cs +++ b/src/ImageSharp/Primitives/SignedRational.cs @@ -41,10 +41,18 @@ namespace SixLabors.ImageSharp.Primitives /// Specified if the rational should be simplified. public SignedRational(int numerator, int denominator, bool simplify) { - var rational = new LongRational(numerator, denominator, simplify); - - this.Numerator = (int)rational.Numerator; - this.Denominator = (int)rational.Denominator; + if (simplify) + { + LongRational rational = new LongRational(numerator, denominator).Simplify(); + + this.Numerator = (int)rational.Numerator; + this.Denominator = (int)rational.Denominator; + } + else + { + this.Numerator = numerator; + this.Denominator = denominator; + } } /// @@ -63,7 +71,7 @@ namespace SixLabors.ImageSharp.Primitives /// Whether to use the best possible precision when parsing the value. public SignedRational(double value, bool bestPrecision) { - var rational = new LongRational(value, bestPrecision); + var rational = LongRational.FromDouble(value, bestPrecision); this.Numerator = (int)rational.Numerator; this.Denominator = (int)rational.Denominator; From a79cf0ee22c93e64082c1bb415635e0ce0d0dd48 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Fri, 30 Mar 2018 16:26:15 -0700 Subject: [PATCH 30/32] Remove leading space --- .../Formats/Jpeg/GolangPort/OrigJpegDecoderCore.cs | 8 ++++---- .../Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/GolangPort/OrigJpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/GolangPort/OrigJpegDecoderCore.cs index 183076ac58..a4fbb17be3 100644 --- a/src/ImageSharp/Formats/Jpeg/GolangPort/OrigJpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/GolangPort/OrigJpegDecoderCore.cs @@ -427,12 +427,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort { if (this.isExif) { - double horizontalValue = this.MetaData.ExifProfile.TryGetValue(ExifTag.XResolution, out var horizonalTag) - ? ((Rational)horizonalTag.Value).ToDouble() + double horizontalValue = this.MetaData.ExifProfile.TryGetValue(ExifTag.XResolution, out ExifValue horizonalTag) + ? ((Rational)horizonalTag.Value).ToDouble() : 0; - double verticalValue = this.MetaData.ExifProfile.TryGetValue(ExifTag.YResolution, out var verticalTag) - ? ((Rational)verticalTag.Value).ToDouble() + double verticalValue = this.MetaData.ExifProfile.TryGetValue(ExifTag.YResolution, out ExifValue verticalTag) + ? ((Rational)verticalTag.Value).ToDouble() : 0; if (horizontalValue > 0 && verticalValue > 0) diff --git a/src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs index ba5362993f..30b8158e73 100644 --- a/src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs @@ -380,12 +380,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort { if (this.isExif) { - double horizontalValue = image.MetaData.ExifProfile.TryGetValue(ExifTag.XResolution, out var horizontalTag) - ? ((Rational)horizontalTag.Value).ToDouble() + double horizontalValue = image.MetaData.ExifProfile.TryGetValue(ExifTag.XResolution, out ExifValue horizontalTag) + ? ((Rational)horizontalTag.Value).ToDouble() : 0; - double verticalValue = image.MetaData.ExifProfile.TryGetValue(ExifTag.YResolution, out var verticalTag) - ? ((Rational)verticalTag.Value).ToDouble() + double verticalValue = image.MetaData.ExifProfile.TryGetValue(ExifTag.YResolution, out ExifValue verticalTag) + ? ((Rational)verticalTag.Value).ToDouble() : 0; if (horizontalValue > 0 && verticalValue > 0) From 38b24c992a2ccf2ae22f43670b126ad6548fd05d Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 2 Apr 2018 13:00:17 -0700 Subject: [PATCH 31/32] Change InvalidTags to ReadOnlyList & pin pointer. --- src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs index 05d6819b5a..c00eec6010 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs @@ -6,7 +6,6 @@ using System.Buffers.Binary; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; using SixLabors.ImageSharp.IO; @@ -39,7 +38,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif /// /// Gets the invalid tags. /// - public IList InvalidTags => this.invalidTags; + public IReadOnlyList InvalidTags => this.invalidTags; /// /// Gets the thumbnail length in the byte stream @@ -147,9 +146,12 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif string result = Encoding.UTF8.GetString(bytes, 0, buffer.Length); #else - byte* pointer = (byte*)Unsafe.AsPointer(ref MemoryMarshal.GetReference(buffer)); + string result; - string result = Encoding.UTF8.GetString(pointer, buffer.Length); + fixed (byte* pointer = &MemoryMarshal.GetReference(buffer)) + { + result = Encoding.UTF8.GetString(pointer, buffer.Length); + } #endif int nullCharIndex = result.IndexOf('\0'); if (nullCharIndex != -1) From e79f2d8ae4fdd828b9a67328757f022a4a0ff850 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 2 Apr 2018 13:03:19 -0700 Subject: [PATCH 32/32] Fix typo --- src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs index 4178bcec80..0f19083e53 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs @@ -161,7 +161,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif } /// - /// Conditionally the value of the tag if it exists. + /// Conditionally returns the value of the tag if it exists. /// /// The tag of the EXIF value. /// The value of the tag, if found.