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/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/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..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
{
@@ -16,8 +15,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;
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/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/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);
}
diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
index 9f4dba5b4f..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++)
{
@@ -581,13 +581,11 @@ 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/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/Formats/Bmp/BmpEncoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs
index 66c8b6c086..be7c1d2e55 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,11 @@ 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 +91,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
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..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();
}
///
@@ -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/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/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/Formats/Jpeg/GolangPort/OrigJpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/GolangPort/OrigJpegDecoderCore.cs
index 0125d2703b..a4fbb17be3 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 ExifValue horizonalTag)
+ ? ((Rational)horizonalTag.Value).ToDouble()
+ : 0;
+
+ 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/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/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs
index a600658b02..30b8158e73 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 ExifValue horizontalTag)
+ ? ((Rational)horizontalTag.Value).ToDouble()
+ : 0;
+
+ double verticalValue = image.MetaData.ExifProfile.TryGetValue(ExifTag.YResolution, out ExifValue verticalTag)
+ ? ((Rational)verticalTag.Value).ToDouble()
+ : 0;
if (horizontalValue > 0 && verticalValue > 0)
{
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..234ed6bbd0 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);
}
}
}
@@ -338,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");
}
@@ -1159,16 +1157,14 @@ 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]);
}
///
@@ -1208,36 +1204,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 +1314,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);
}
///
diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs
index 0cded1d80c..17aae17620 100644
--- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs
+++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs
@@ -212,16 +212,14 @@ 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 +413,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 +434,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; }
}
}
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/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/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/src/ImageSharp/MetaData/ImageProperty.cs b/src/ImageSharp/MetaData/ImageProperty.cs
index c60aaecfba..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,9 +105,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 && this.Equals(other);
}
///
@@ -155,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/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
diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs
index 7cd2d002d7..0f19083e53 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 IEnumerable Values
+ public IReadOnlyList Values
{
get
{
@@ -163,6 +160,31 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif
return null;
}
+ ///
+ /// Conditionally returns 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.
///
@@ -193,16 +215,18 @@ 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);
}
@@ -262,12 +286,14 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif
if (this.data == null)
{
- this.values = new Collection();
+ this.values = new List();
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 8a7b1f7d7e..c00eec6010 100644
--- a/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs
+++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs
@@ -2,10 +2,13 @@
// 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.Runtime.InteropServices;
using System.Text;
+using SixLabors.ImageSharp.IO;
using SixLabors.ImageSharp.Primitives;
namespace SixLabors.ImageSharp.MetaData.Profiles.Exif
@@ -15,38 +18,37 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif
///
internal sealed class ExifReader
{
- private readonly Collection invalidTags = new Collection();
- private byte[] exifData;
- private uint currentIndex;
- private bool isLittleEndian;
+ private readonly List invalidTags = new List();
+ private readonly byte[] exifData;
+ 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);
+ public ExifReader(byte[] exifData)
+ {
+ DebugGuard.NotNull(exifData, nameof(exifData));
+
+ this.exifData = exifData;
+ }
+
+ private delegate TDataType ConverterMethod(ReadOnlySpan data);
///
/// Gets the invalid tags.
///
- public IEnumerable InvalidTags => this.invalidTags;
+ public IReadOnlyList InvalidTags => this.invalidTags;
///
/// 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.
@@ -55,81 +57,78 @@ 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 - this.position;
}
}
///
/// Reads and returns the collection of EXIF values.
///
- /// The data.
///
/// The .
///
- public Collection Read(byte[] data)
+ public List ReadValues()
{
- DebugGuard.NotNull(data, nameof(data));
-
- var result = new Collection();
+ var values = new List();
- this.exifData = data;
-
- if (this.GetString(4) == "Exif")
+ if (this.ReadString(4) == "Exif")
{
- if (this.GetShort() != 0)
+ if (this.ReadUInt16() != 0)
{
- return result;
+ return values;
}
this.startIndex = 6;
}
else
{
- this.currentIndex = 0;
+ this.position = 0;
}
- this.isLittleEndian = this.GetString(2) == "II";
+ if (this.ReadString(2) == "II")
+ {
+ this.endianness = Endianness.LittleEndian;
+ }
- if (this.GetShort() != 0x002A)
+ if (this.ReadUInt16() != 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;
- TDataType[] result = new TDataType[length];
- byte[] buffer = new byte[dataTypeSize];
+ var result = new TDataType[length];
for (int i = 0; i < length; i++)
{
- Array.Copy(data, i * dataTypeSize, buffer, 0, dataTypeSize);
+ ReadOnlySpan buffer = data.Slice(i * dataTypeSize, dataTypeSize);
result.SetValue(converter(buffer), i);
}
@@ -137,14 +136,23 @@ 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);
+#if NETSTANDARD1_1
+ byte[] bytes = buffer.ToArray();
+
+ string result = Encoding.UTF8.GetString(bytes, 0, buffer.Length);
+
+#else
+ string result;
+
+ fixed (byte* pointer = &MemoryMarshal.GetReference(buffer))
+ {
+ result = Encoding.UTF8.GetString(pointer, buffer.Length);
+ }
+#endif
int nullCharIndex = result.IndexOf('\0');
if (nullCharIndex != -1)
{
@@ -159,15 +167,14 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif
///
/// The values.
/// The index.
- private void AddValues(Collection values, uint index)
+ private void AddValues(List values, int index)
{
- this.currentIndex = this.startIndex + index;
- ushort count = this.GetShort();
+ this.position = this.startIndex + index;
+ int count = this.ReadUInt16();
- for (ushort i = 0; i < count; i++)
+ for (int i = 0; i < count; i++)
{
- ExifValue value = this.CreateValue();
- if (value == null)
+ if (!this.TryReadValue(out ExifValue value))
{
continue;
}
@@ -208,9 +215,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;
}
@@ -220,106 +227,116 @@ 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.ConvertToUInt32(buffer);
}
- return ToArray(dataType, data, this.ToLong);
+ return ToArray(dataType, buffer, this.ConvertToUInt32);
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.ConvertToInt32(buffer);
}
- return ToArray(dataType, data, this.ToSignedLong);
+ return ToArray(dataType, buffer, this.ConvertToInt32);
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 this.ConvertToByte(buffer);
}
- return data;
+ return buffer.ToArray();
default:
throw new NotSupportedException();
}
}
- private ExifValue CreateValue()
+ private bool TryReadValue(out ExifValue exifValue)
{
+ // 2 | 2 | 4 | 4
+ // tag | type | count | value offset
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);
- 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)
{
- return new ExifValue(tag, dataType, null, false);
+ exifValue = new ExifValue(tag, ExifDataType.Unknown, null, false);
+
+ return true;
}
- uint numberOfComponents = this.GetLong();
+ var dataType = (ExifDataType)type;
+
+ object value;
+
+ 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)
@@ -329,29 +346,50 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif
}
uint size = numberOfComponents * ExifValue.GetSize(dataType);
- byte[] data = this.GetBytes(4);
+
+ this.TryReadSpan(4, out ReadOnlySpan offsetBuffer);
if (size > 4)
{
- uint oldIndex = this.currentIndex;
- this.currentIndex = this.ToLong(data) + this.startIndex;
+ int oldIndex = this.position;
+
+ 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);
- 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 dataBuffer);
+
+ value = this.ConvertValue(dataType, dataBuffer, numberOfComponents);
+ this.position = oldIndex;
}
else
{
- value = this.ConvertValue(dataType, data, numberOfComponents);
+ value = this.ConvertValue(dataType, offsetBuffer, 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)
@@ -366,51 +404,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.RemainingLength < length)
{
- 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);
- return data;
+ this.position += length;
+
+ 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.ConvertToUInt32(span)
+ : default;
}
- private ushort GetShort()
+ private ushort ReadUInt16()
{
- return this.ToShort(this.GetBytes(2));
+ return this.TryReadSpan(2, out ReadOnlySpan span)
+ ? this.ConvertToShort(span)
+ : default;
}
- private string GetString(uint length)
+ private string ReadString(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)
{
@@ -419,120 +463,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(double);
+ 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 ConvertToUInt32(ReadOnlySpan buffer)
{
- if (!this.ValidateArray(data, 4))
+ // Known as Long in Exif Specification
+ if (buffer.Length < 4)
{
- return default(uint);
+ 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(ushort);
+ 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(float);
+ 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 = this.ConvertToUInt32(buffer.Slice(0, 4));
+ uint denominator = this.ConvertToUInt32(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 ConvertToInt32(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(SignedRational);
+ return default;
}
- int numerator = BitConverter.ToInt32(data, 0);
- int denominator = BitConverter.ToInt32(data, 4);
+ int numerator = this.ConvertToInt32(buffer.Slice(0, 4));
+ int denominator = this.ConvertToInt32(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(short);
+ 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
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/ExifValue.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs
index 3c2b23f37f..bdd902e239 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.
@@ -34,30 +29,12 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif
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,51 +46,32 @@ 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;
}
///
/// 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.
+ /// Gets the value.
///
- public object Value
- {
- get
- {
- return this.exifValue;
- }
-
- set
- {
- this.CheckValue(value);
- this.exifValue = value;
- }
- }
+ public object Value { get; }
///
/// Gets a value indicating whether the EXIF value has a value.
@@ -122,14 +80,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;
@@ -143,7 +101,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif
{
get
{
- if (this.exifValue == null)
+ if (this.Value == null)
{
return 4;
}
@@ -163,12 +121,12 @@ 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;
@@ -217,12 +175,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);
}
///
@@ -241,7 +194,19 @@ 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);
+ }
+
+ ///
+ /// 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);
}
///
@@ -253,26 +218,26 @@ 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(" ");
+ sb.Append(' ');
}
return sb.ToString();
@@ -293,13 +258,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:
@@ -355,8 +313,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:
@@ -369,13 +326,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:
@@ -389,8 +345,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:
@@ -412,8 +367,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:
@@ -428,8 +382,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:
@@ -463,8 +417,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:
@@ -487,8 +440,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:
@@ -535,20 +488,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:
@@ -565,18 +516,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:
@@ -585,15 +535,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;
}
///
@@ -635,29 +581,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);
}
///
@@ -739,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;
}
@@ -788,7 +739,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..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;
@@ -19,299 +19,28 @@ 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.
///
private ExifParts allowedParts;
- private Collection values;
- private Collection dataOffsets;
- private Collection ifdIndexes;
- private Collection exifIndexes;
- private Collection gpsIndexes;
+ private IList values;
+ private List dataOffsets;
+ private List ifdIndexes;
+ private List exifIndexes;
+ private List 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;
- 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);
}
///
@@ -360,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';
@@ -377,17 +107,17 @@ 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);
+ 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)
@@ -402,19 +132,61 @@ 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)
+ {
+ BinaryPrimitives.WriteInt64LittleEndian(destination.Slice(offset, 8), *((long*)&value));
+
+ return offset + 8;
+ }
+
+ private static int Write(ReadOnlySpan source, Span destination, int offset)
{
- Buffer.BlockCopy(source, 0, destination, offset, source.Length);
+ source.CopyTo(destination.Slice(offset, source.Length));
return offset + source.Length;
}
- private int GetIndex(Collection indexes, ExifTag tag)
+ 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)
{
@@ -430,14 +202,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();
+ return new List();
}
- Collection result = new Collection();
+ var result = new List();
for (int i = 0; i < this.values.Count; i++)
{
ExifValue value = this.values[i];
@@ -457,7 +229,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif
return result;
}
- private uint GetLength(IEnumerable indexes)
+ private uint GetLength(IList indexes)
{
uint length = 0;
@@ -494,7 +266,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif
return newOffset;
}
- private int WriteData(Collection indexes, byte[] destination, int offset)
+ private int WriteData(List indexes, byte[] destination, int offset)
{
if (this.dataOffsets.Count == 0)
{
@@ -509,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);
}
}
@@ -517,11 +289,11 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif
return newOffset;
}
- private int WriteHeaders(Collection indexes, byte[] destination, int offset)
+ private int WriteHeaders(List indexes, byte[] destination, int offset)
{
- this.dataOffsets = new Collection();
+ 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)
{
@@ -531,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)
{
@@ -550,23 +322,19 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif
return newOffset;
}
- private int WriteRational(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(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)
{
@@ -577,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();
}
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 922926e385..57e2e984be 100644
--- a/src/ImageSharp/PixelFormats/Alpha8.cs
+++ b/src/ImageSharp/PixelFormats/Alpha8.cs
@@ -138,7 +138,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 e8fc24b31c..61b447b882 100644
--- a/src/ImageSharp/PixelFormats/Bgr24.cs
+++ b/src/ImageSharp/PixelFormats/Bgr24.cs
@@ -59,7 +59,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 2b9a447bd9..ad5efa2578 100644
--- a/src/ImageSharp/PixelFormats/Bgra32.cs
+++ b/src/ImageSharp/PixelFormats/Bgra32.cs
@@ -104,7 +104,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 f339881d0c..0f52d00687 100644
--- a/src/ImageSharp/PixelFormats/Bgra4444.cs
+++ b/src/ImageSharp/PixelFormats/Bgra4444.cs
@@ -156,7 +156,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 ea1d7446d5..d24bab848e 100644
--- a/src/ImageSharp/PixelFormats/Bgra5551.cs
+++ b/src/ImageSharp/PixelFormats/Bgra5551.cs
@@ -156,7 +156,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/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/HalfVector4.cs b/src/ImageSharp/PixelFormats/HalfVector4.cs
index f19d1ec952..c92de4ef13 100644
--- a/src/ImageSharp/PixelFormats/HalfVector4.cs
+++ b/src/ImageSharp/PixelFormats/HalfVector4.cs
@@ -191,7 +191,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/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/PixelFormats/NormalizedByte2.cs b/src/ImageSharp/PixelFormats/NormalizedByte2.cs
index 69ed25e439..9bac828560 100644
--- a/src/ImageSharp/PixelFormats/NormalizedByte2.cs
+++ b/src/ImageSharp/PixelFormats/NormalizedByte2.cs
@@ -194,7 +194,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 18af886dfe..a3aa60fd21 100644
--- a/src/ImageSharp/PixelFormats/NormalizedByte4.cs
+++ b/src/ImageSharp/PixelFormats/NormalizedByte4.cs
@@ -187,7 +187,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 157f7419be..87c92cb73b 100644
--- a/src/ImageSharp/PixelFormats/NormalizedShort4.cs
+++ b/src/ImageSharp/PixelFormats/NormalizedShort4.cs
@@ -189,7 +189,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 bb31d9ae97..f07eadd56e 100644
--- a/src/ImageSharp/PixelFormats/Rgb24.cs
+++ b/src/ImageSharp/PixelFormats/Rgb24.cs
@@ -60,7 +60,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.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
{
diff --git a/src/ImageSharp/PixelFormats/RgbaVector.cs b/src/ImageSharp/PixelFormats/RgbaVector.cs
index 0234a48268..92faa4e27b 100644
--- a/src/ImageSharp/PixelFormats/RgbaVector.cs
+++ b/src/ImageSharp/PixelFormats/RgbaVector.cs
@@ -304,7 +304,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 16151256df..75429c0afb 100644
--- a/src/ImageSharp/PixelFormats/Short2.cs
+++ b/src/ImageSharp/PixelFormats/Short2.cs
@@ -190,7 +190,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 6eab376170..0ea2b10c29 100644
--- a/src/ImageSharp/PixelFormats/Short4.cs
+++ b/src/ImageSharp/PixelFormats/Short4.cs
@@ -185,7 +185,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();
diff --git a/src/ImageSharp/Primitives/LongRational.cs b/src/ImageSharp/Primitives/LongRational.cs
index 641a1e5e53..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();
}
///
@@ -268,86 +119,108 @@ 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();
}
///
- /// 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 6678eb9540..b598f0e02f 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,10 +41,18 @@ 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);
+ if (simplify)
+ {
+ LongRational rational = new LongRational(numerator, denominator).Simplify();
- this.Numerator = (uint)rational.Numerator;
- this.Denominator = (uint)rational.Denominator;
+ 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)
{
- LongRational 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;
@@ -129,19 +137,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 +152,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 +183,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..7e486e4f22 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,10 +41,18 @@ 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);
+ if (simplify)
+ {
+ LongRational rational = new LongRational(numerator, denominator).Simplify();
- this.Numerator = (int)rational.Numerator;
- this.Denominator = (int)rational.Denominator;
+ 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)
{
- LongRational rational = new LongRational(value, bestPrecision);
+ var rational = LongRational.FromDouble(value, bestPrecision);
this.Numerator = (int)rational.Numerator;
this.Denominator = (int)rational.Denominator;
@@ -129,19 +137,14 @@ 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 && this.Equals(other);
}
///
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);
}
@@ -149,7 +152,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 +183,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/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);
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);
diff --git a/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs b/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs
index 65a469b6f1..d98c61279b 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;
@@ -255,17 +255,17 @@ 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");
}
- 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 dee6d5ff39..c9542a98a9 100644
--- a/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifReaderTests.cs
+++ b/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifReaderTests.cs
@@ -1,7 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
-using System.Collections.ObjectModel;
+using System.Collections.Generic;
using SixLabors.ImageSharp.MetaData.Profiles.Exif;
using Xunit;
@@ -12,10 +12,9 @@ namespace SixLabors.ImageSharp.Tests
[Fact]
public void Read_DataIsEmpty_ReturnsEmptyCollection()
{
- ExifReader reader = new ExifReader();
- byte[] data = new byte[] { };
+ var reader = new ExifReader(new byte[] { });
- Collection result = reader.Read(data);
+ IList result = reader.ReadValues();
Assert.Equal(0, result.Count);
}
@@ -23,10 +22,9 @@ namespace SixLabors.ImageSharp.Tests
[Fact]
public void Read_DataIsMinimal_ReturnsEmptyCollection()
{
- ExifReader 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 });
- Collection result = reader.Read(data);
+ IList result = reader.ReadValues();
Assert.Equal(0, result.Count);
}