diff --git a/shared-infrastructure b/shared-infrastructure
index bf398a9b6b..47ff841e1d 160000
--- a/shared-infrastructure
+++ b/shared-infrastructure
@@ -1 +1 @@
-Subproject commit bf398a9b6bb6d0acfe0525ee109276b4ef74646c
+Subproject commit 47ff841e1d2226a0fc5953e3d79ab6c9f6a24a46
diff --git a/src/ImageSharp/Advanced/AdvancedImageExtensions.cs b/src/ImageSharp/Advanced/AdvancedImageExtensions.cs
index 10267c8ef7..f0d71f212d 100644
--- a/src/ImageSharp/Advanced/AdvancedImageExtensions.cs
+++ b/src/ImageSharp/Advanced/AdvancedImageExtensions.cs
@@ -27,7 +27,7 @@ public static IImageEncoder DetectEncoder(this Image source, string filePath)
Guard.NotNull(filePath, nameof(filePath));
string ext = Path.GetExtension(filePath);
- IImageFormat format = source.GetConfiguration().ImageFormatsManager.FindFormatByFileExtension(ext);
+ IImageFormat? format = source.GetConfiguration().ImageFormatsManager.FindFormatByFileExtension(ext);
if (format is null)
{
StringBuilder sb = new();
@@ -40,7 +40,7 @@ public static IImageEncoder DetectEncoder(this Image source, string filePath)
throw new NotSupportedException(sb.ToString());
}
- IImageEncoder encoder = source.GetConfiguration().ImageFormatsManager.FindEncoder(format);
+ IImageEncoder? encoder = source.GetConfiguration().ImageFormatsManager.FindEncoder(format);
if (encoder is null)
{
@@ -99,7 +99,7 @@ public static Configuration GetConfiguration(this ImageFrame source)
/// The source image
/// Returns the bounds of the image
private static Configuration GetConfiguration(IConfigurationProvider source)
- => source?.Configuration ?? Configuration.Default;
+ => source.Configuration ?? Configuration.Default;
///
/// Gets the representation of the pixels as a containing the backing pixel data of the image
@@ -115,7 +115,7 @@ private static Configuration GetConfiguration(IConfigurationProvider source)
/// Thrown when the in .
public static IMemoryGroup GetPixelMemoryGroup(this ImageFrame source)
where TPixel : unmanaged, IPixel
- => source?.PixelBuffer.FastMemoryGroup.View ?? throw new ArgumentNullException(nameof(source));
+ => source.PixelBuffer!.FastMemoryGroup.View ?? throw new ArgumentNullException(nameof(source));
///
/// Gets the representation of the pixels as a containing the backing pixel data of the image
@@ -131,7 +131,7 @@ public static IMemoryGroup GetPixelMemoryGroup(this ImageFrameThrown when the in .
public static IMemoryGroup GetPixelMemoryGroup(this Image source)
where TPixel : unmanaged, IPixel
- => source?.Frames.RootFrame.GetPixelMemoryGroup() ?? throw new ArgumentNullException(nameof(source));
+ => source.Frames.RootFrame.GetPixelMemoryGroup() ?? throw new ArgumentNullException(nameof(source));
///
/// Gets the representation of the pixels as a of contiguous memory
@@ -148,7 +148,7 @@ public static Memory DangerousGetPixelRowMemory(this ImageFrame<
Guard.MustBeGreaterThanOrEqualTo(rowIndex, 0, nameof(rowIndex));
Guard.MustBeLessThan(rowIndex, source.Height, nameof(rowIndex));
- return source.PixelBuffer.GetSafeRowMemory(rowIndex);
+ return source.PixelBuffer!.GetSafeRowMemory(rowIndex);
}
///
@@ -166,7 +166,7 @@ public static Memory DangerousGetPixelRowMemory(this Image
diff --git a/src/ImageSharp/Advanced/AotCompilerTools.cs b/src/ImageSharp/Advanced/AotCompilerTools.cs
index 9c285e21de..223b7d275a 100644
--- a/src/ImageSharp/Advanced/AotCompilerTools.cs
+++ b/src/ImageSharp/Advanced/AotCompilerTools.cs
@@ -1,6 +1,7 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
+#nullable disable
using System.Diagnostics.CodeAnalysis;
using System.Numerics;
using System.Runtime.CompilerServices;
diff --git a/src/ImageSharp/Advanced/IConfigurationProvider.cs b/src/ImageSharp/Advanced/IConfigurationProvider.cs
index 086461f448..1191c9bdfa 100644
--- a/src/ImageSharp/Advanced/IConfigurationProvider.cs
+++ b/src/ImageSharp/Advanced/IConfigurationProvider.cs
@@ -11,5 +11,5 @@ internal interface IConfigurationProvider
///
/// Gets the configuration which allows altering default behaviour or extending the library.
///
- Configuration Configuration { get; }
+ Configuration? Configuration { get; }
}
diff --git a/src/ImageSharp/Advanced/IPixelSource.cs b/src/ImageSharp/Advanced/IPixelSource.cs
index a46f7d4080..93d5467ffd 100644
--- a/src/ImageSharp/Advanced/IPixelSource.cs
+++ b/src/ImageSharp/Advanced/IPixelSource.cs
@@ -27,5 +27,5 @@ internal interface IPixelSource
///
/// Gets the pixel buffer.
///
- Buffer2D PixelBuffer { get; }
+ Buffer2D? PixelBuffer { get; }
}
diff --git a/src/ImageSharp/Color/Color.cs b/src/ImageSharp/Color/Color.cs
index 28dc1cf924..99a271bcf7 100644
--- a/src/ImageSharp/Color/Color.cs
+++ b/src/ImageSharp/Color/Color.cs
@@ -19,7 +19,7 @@ namespace SixLabors.ImageSharp;
public readonly partial struct Color : IEquatable
{
private readonly Rgba64 data;
- private readonly IPixel boxedHighPrecisionPixel;
+ private readonly IPixel? boxedHighPrecisionPixel;
[MethodImpl(InliningOptions.ShortMethod)]
private Color(byte r, byte g, byte b, byte a)
@@ -316,7 +316,7 @@ public bool Equals(Color other)
}
///
- public override bool Equals(object obj) => obj is Color other && this.Equals(other);
+ public override bool Equals(object? obj) => obj is Color other && this.Equals(other);
///
[MethodImpl(InliningOptions.ShortMethod)]
diff --git a/src/ImageSharp/ColorSpaces/CieLab.cs b/src/ImageSharp/ColorSpaces/CieLab.cs
index 35b664e8a3..2346b395c0 100644
--- a/src/ImageSharp/ColorSpaces/CieLab.cs
+++ b/src/ImageSharp/ColorSpaces/CieLab.cs
@@ -123,7 +123,7 @@ public CieLab(Vector3 vector, CieXyz whitePoint)
public override string ToString() => FormattableString.Invariant($"CieLab({this.L:#0.##}, {this.A:#0.##}, {this.B:#0.##})");
///
- public override bool Equals(object obj) => obj is CieLab other && this.Equals(other);
+ public override bool Equals(object? obj) => obj is CieLab other && this.Equals(other);
///
[MethodImpl(InliningOptions.ShortMethod)]
diff --git a/src/ImageSharp/ColorSpaces/CieLch.cs b/src/ImageSharp/ColorSpaces/CieLch.cs
index e6f53cbb42..48e8e2c6d9 100644
--- a/src/ImageSharp/ColorSpaces/CieLch.cs
+++ b/src/ImageSharp/ColorSpaces/CieLch.cs
@@ -127,7 +127,7 @@ public override int GetHashCode()
///
[MethodImpl(InliningOptions.ShortMethod)]
- public override bool Equals(object obj) => obj is CieLch other && this.Equals(other);
+ public override bool Equals(object? obj) => obj is CieLch other && this.Equals(other);
///
[MethodImpl(InliningOptions.ShortMethod)]
diff --git a/src/ImageSharp/ColorSpaces/CieLchuv.cs b/src/ImageSharp/ColorSpaces/CieLchuv.cs
index de669e7ed9..4d47be5aa3 100644
--- a/src/ImageSharp/ColorSpaces/CieLchuv.cs
+++ b/src/ImageSharp/ColorSpaces/CieLchuv.cs
@@ -124,7 +124,7 @@ public CieLchuv(Vector3 vector, CieXyz whitePoint)
public override string ToString() => FormattableString.Invariant($"CieLchuv({this.L:#0.##}, {this.C:#0.##}, {this.H:#0.##})");
///
- public override bool Equals(object obj) => obj is CieLchuv other && this.Equals(other);
+ public override bool Equals(object? obj) => obj is CieLchuv other && this.Equals(other);
///
[MethodImpl(InliningOptions.ShortMethod)]
diff --git a/src/ImageSharp/ColorSpaces/CieLuv.cs b/src/ImageSharp/ColorSpaces/CieLuv.cs
index f4de5198e0..04bc96cfa2 100644
--- a/src/ImageSharp/ColorSpaces/CieLuv.cs
+++ b/src/ImageSharp/ColorSpaces/CieLuv.cs
@@ -124,7 +124,7 @@ public CieLuv(Vector3 vector, CieXyz whitePoint)
public override string ToString() => FormattableString.Invariant($"CieLuv({this.L:#0.##}, {this.U:#0.##}, {this.V:#0.##})");
///
- public override bool Equals(object obj) => obj is CieLuv other && this.Equals(other);
+ public override bool Equals(object? obj) => obj is CieLuv other && this.Equals(other);
///
[MethodImpl(InliningOptions.ShortMethod)]
diff --git a/src/ImageSharp/ColorSpaces/CieXyy.cs b/src/ImageSharp/ColorSpaces/CieXyy.cs
index 2e725a5011..6b7d2e6cbd 100644
--- a/src/ImageSharp/ColorSpaces/CieXyy.cs
+++ b/src/ImageSharp/ColorSpaces/CieXyy.cs
@@ -88,7 +88,7 @@ public CieXyy(Vector3 vector)
public override string ToString() => FormattableString.Invariant($"CieXyy({this.X:#0.##}, {this.Y:#0.##}, {this.Yl:#0.##})");
///
- public override bool Equals(object obj) => obj is CieXyy other && this.Equals(other);
+ public override bool Equals(object? obj) => obj is CieXyy other && this.Equals(other);
///
[MethodImpl(InliningOptions.ShortMethod)]
diff --git a/src/ImageSharp/ColorSpaces/CieXyz.cs b/src/ImageSharp/ColorSpaces/CieXyz.cs
index 53d93c32b8..2ac9c9f286 100644
--- a/src/ImageSharp/ColorSpaces/CieXyz.cs
+++ b/src/ImageSharp/ColorSpaces/CieXyz.cs
@@ -91,7 +91,7 @@ public CieXyz(Vector3 vector)
public override string ToString() => FormattableString.Invariant($"CieXyz({this.X:#0.##}, {this.Y:#0.##}, {this.Z:#0.##})");
///
- public override bool Equals(object obj) => obj is CieXyz other && this.Equals(other);
+ public override bool Equals(object? obj) => obj is CieXyz other && this.Equals(other);
///
[MethodImpl(InliningOptions.ShortMethod)]
diff --git a/src/ImageSharp/ColorSpaces/Cmyk.cs b/src/ImageSharp/ColorSpaces/Cmyk.cs
index 615b6d34dc..a5aacf38ad 100644
--- a/src/ImageSharp/ColorSpaces/Cmyk.cs
+++ b/src/ImageSharp/ColorSpaces/Cmyk.cs
@@ -95,7 +95,7 @@ public Cmyk(Vector4 vector)
public override string ToString() => FormattableString.Invariant($"Cmyk({this.C:#0.##}, {this.M:#0.##}, {this.Y:#0.##}, {this.K:#0.##})");
///
- public override bool Equals(object obj) => obj is Cmyk other && this.Equals(other);
+ public override bool Equals(object? obj) => obj is Cmyk other && this.Equals(other);
///
[MethodImpl(InliningOptions.ShortMethod)]
diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs
index 52a9ef27ee..f4f0ed35d0 100644
--- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs
+++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs
@@ -32,7 +32,7 @@ public CieXyz Adapt(in CieXyz color, in CieXyz sourceWhitePoint, in CieXyz targe
return color;
}
- return this.chromaticAdaptation.Transform(color, sourceWhitePoint, targetWhitePoint);
+ return this.chromaticAdaptation!.Transform(color, sourceWhitePoint, targetWhitePoint);
}
///
@@ -132,7 +132,7 @@ public LinearRgb Adapt(in LinearRgb color)
CieXyz unadapted = converterToXYZ.Convert(color);
// Adaptation
- CieXyz adapted = this.chromaticAdaptation.Transform(unadapted, color.WorkingSpace.WhitePoint, this.targetRgbWorkingSpace.WhitePoint);
+ CieXyz adapted = this.chromaticAdaptation!.Transform(unadapted, color.WorkingSpace.WhitePoint, this.targetRgbWorkingSpace.WhitePoint);
// Conversion back to RGB
return this.cieXyzToLinearRgbConverter.Convert(adapted);
diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs
index ac1fa8ed0a..65298597c3 100644
--- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs
+++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs
@@ -13,7 +13,7 @@ public partial class ColorSpaceConverter
{
private static readonly HunterLabToCieXyzConverter HunterLabToCieXyzConverter = new();
- private LinearRgbToCieXyzConverter linearRgbToCieXyzConverter;
+ private LinearRgbToCieXyzConverter? linearRgbToCieXyzConverter;
///
/// Converts a into a .
diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs
index fbe441a8c7..9aecf7dbed 100644
--- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs
+++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs
@@ -18,7 +18,7 @@ public partial class ColorSpaceConverter
private readonly CieXyz targetLabWhitePoint;
private readonly CieXyz targetHunterLabWhitePoint;
private readonly RgbWorkingSpace targetRgbWorkingSpace;
- private readonly IChromaticAdaptation chromaticAdaptation;
+ private readonly IChromaticAdaptation? chromaticAdaptation;
private readonly bool performChromaticAdaptation;
private readonly CieXyzAndLmsConverter cieXyzAndLmsConverter;
private readonly CieXyzToCieLabConverter cieXyzToCieLabConverter;
diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyChromaticityCoordinates.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyChromaticityCoordinates.cs
index abcff202f5..2cc785d53b 100644
--- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyChromaticityCoordinates.cs
+++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyChromaticityCoordinates.cs
@@ -73,7 +73,7 @@ public override string ToString()
=> FormattableString.Invariant($"CieXyChromaticityCoordinates({this.X:#0.##}, {this.Y:#0.##})");
///
- public override bool Equals(object obj)
+ public override bool Equals(object? obj)
=> obj is CieXyChromaticityCoordinates other && this.Equals(other);
///
diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/RGBPrimariesChromaticityCoordinates.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/RGBPrimariesChromaticityCoordinates.cs
index 9dace7c41d..625e6c551a 100644
--- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/RGBPrimariesChromaticityCoordinates.cs
+++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/RGBPrimariesChromaticityCoordinates.cs
@@ -72,7 +72,7 @@ public RgbPrimariesChromaticityCoordinates(CieXyChromaticityCoordinates r, CieXy
}
///
- public override bool Equals(object obj)
+ public override bool Equals(object? obj)
{
return obj is RgbPrimariesChromaticityCoordinates other && this.Equals(other);
}
diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/GammaWorkingSpace.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/GammaWorkingSpace.cs
index 87b0ce8065..e95f1f2b47 100644
--- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/GammaWorkingSpace.cs
+++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/GammaWorkingSpace.cs
@@ -34,7 +34,7 @@ public GammaWorkingSpace(float gamma, CieXyz referenceWhite, RgbPrimariesChromat
public override float Expand(float channel) => GammaCompanding.Expand(channel, this.Gamma);
///
- public override bool Equals(object obj)
+ public override bool Equals(object? obj)
{
if (obj is null)
{
diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/RgbWorkingSpace.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/RgbWorkingSpace.cs
index 44893e19da..f22f2ff1fa 100644
--- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/RgbWorkingSpace.cs
+++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/RgbWorkingSpace.cs
@@ -52,7 +52,7 @@ protected RgbWorkingSpace(CieXyz referenceWhite, RgbPrimariesChromaticityCoordin
public abstract float Compress(float channel);
///
- public override bool Equals(object obj)
+ public override bool Equals(object? obj)
{
if (obj is null)
{
diff --git a/src/ImageSharp/ColorSpaces/Hsl.cs b/src/ImageSharp/ColorSpaces/Hsl.cs
index e34a7945a9..cf18c70c78 100644
--- a/src/ImageSharp/ColorSpaces/Hsl.cs
+++ b/src/ImageSharp/ColorSpaces/Hsl.cs
@@ -89,7 +89,7 @@ public Hsl(Vector3 vector)
public override string ToString() => FormattableString.Invariant($"Hsl({this.H:#0.##}, {this.S:#0.##}, {this.L:#0.##})");
///
- public override bool Equals(object obj) => obj is Hsl other && this.Equals(other);
+ public override bool Equals(object? obj) => obj is Hsl other && this.Equals(other);
///
[MethodImpl(InliningOptions.ShortMethod)]
diff --git a/src/ImageSharp/ColorSpaces/Hsv.cs b/src/ImageSharp/ColorSpaces/Hsv.cs
index 501d421e5e..87c16c0b6a 100644
--- a/src/ImageSharp/ColorSpaces/Hsv.cs
+++ b/src/ImageSharp/ColorSpaces/Hsv.cs
@@ -87,7 +87,7 @@ public Hsv(Vector3 vector)
public override string ToString() => FormattableString.Invariant($"Hsv({this.H:#0.##}, {this.S:#0.##}, {this.V:#0.##})");
///
- public override bool Equals(object obj) => obj is Hsv other && this.Equals(other);
+ public override bool Equals(object? obj) => obj is Hsv other && this.Equals(other);
///
[MethodImpl(InliningOptions.ShortMethod)]
diff --git a/src/ImageSharp/ColorSpaces/HunterLab.cs b/src/ImageSharp/ColorSpaces/HunterLab.cs
index a1039b2359..516574b098 100644
--- a/src/ImageSharp/ColorSpaces/HunterLab.cs
+++ b/src/ImageSharp/ColorSpaces/HunterLab.cs
@@ -122,7 +122,7 @@ public HunterLab(Vector3 vector, CieXyz whitePoint)
public override string ToString() => FormattableString.Invariant($"HunterLab({this.L:#0.##}, {this.A:#0.##}, {this.B:#0.##})");
///
- public override bool Equals(object obj) => obj is HunterLab other && this.Equals(other);
+ public override bool Equals(object? obj) => obj is HunterLab other && this.Equals(other);
///
[MethodImpl(InliningOptions.ShortMethod)]
diff --git a/src/ImageSharp/ColorSpaces/LinearRgb.cs b/src/ImageSharp/ColorSpaces/LinearRgb.cs
index 52daf5d521..49c7814a0e 100644
--- a/src/ImageSharp/ColorSpaces/LinearRgb.cs
+++ b/src/ImageSharp/ColorSpaces/LinearRgb.cs
@@ -131,7 +131,7 @@ public LinearRgb(Vector3 vector, RgbWorkingSpace workingSpace)
public override string ToString() => FormattableString.Invariant($"LinearRgb({this.R:#0.##}, {this.G:#0.##}, {this.B:#0.##})");
///
- public override bool Equals(object obj) => obj is LinearRgb other && this.Equals(other);
+ public override bool Equals(object? obj) => obj is LinearRgb other && this.Equals(other);
///
[MethodImpl(InliningOptions.ShortMethod)]
diff --git a/src/ImageSharp/ColorSpaces/Lms.cs b/src/ImageSharp/ColorSpaces/Lms.cs
index 5a1727addb..99210ff6e4 100644
--- a/src/ImageSharp/ColorSpaces/Lms.cs
+++ b/src/ImageSharp/ColorSpaces/Lms.cs
@@ -92,7 +92,7 @@ public Lms(Vector3 vector)
public override string ToString() => FormattableString.Invariant($"Lms({this.L:#0.##}, {this.M:#0.##}, {this.S:#0.##})");
///
- public override bool Equals(object obj) => obj is Lms other && this.Equals(other);
+ public override bool Equals(object? obj) => obj is Lms other && this.Equals(other);
///
[MethodImpl(InliningOptions.ShortMethod)]
diff --git a/src/ImageSharp/ColorSpaces/Rgb.cs b/src/ImageSharp/ColorSpaces/Rgb.cs
index b70d96b647..55052a710e 100644
--- a/src/ImageSharp/ColorSpaces/Rgb.cs
+++ b/src/ImageSharp/ColorSpaces/Rgb.cs
@@ -152,7 +152,7 @@ public Rgb(Vector3 vector, RgbWorkingSpace workingSpace)
public override string ToString() => FormattableString.Invariant($"Rgb({this.R:#0.##}, {this.G:#0.##}, {this.B:#0.##})");
///
- public override bool Equals(object obj) => obj is Rgb other && this.Equals(other);
+ public override bool Equals(object? obj) => obj is Rgb other && this.Equals(other);
///
[MethodImpl(InliningOptions.ShortMethod)]
diff --git a/src/ImageSharp/ColorSpaces/YCbCr.cs b/src/ImageSharp/ColorSpaces/YCbCr.cs
index 459063fffa..acb59388fb 100644
--- a/src/ImageSharp/ColorSpaces/YCbCr.cs
+++ b/src/ImageSharp/ColorSpaces/YCbCr.cs
@@ -88,7 +88,7 @@ public YCbCr(Vector3 vector)
public override string ToString() => FormattableString.Invariant($"YCbCr({this.Y}, {this.Cb}, {this.Cr})");
///
- public override bool Equals(object obj) => obj is YCbCr other && this.Equals(other);
+ public override bool Equals(object? obj) => obj is YCbCr other && this.Equals(other);
///
[MethodImpl(InliningOptions.ShortMethod)]
diff --git a/src/ImageSharp/Common/Helpers/Guard.cs b/src/ImageSharp/Common/Helpers/Guard.cs
index cc10c6e00a..c2c4308ad3 100644
--- a/src/ImageSharp/Common/Helpers/Guard.cs
+++ b/src/ImageSharp/Common/Helpers/Guard.cs
@@ -17,6 +17,7 @@ internal static partial class Guard
/// is not a value type.
[MethodImpl(InliningOptions.ShortMethod)]
public static void MustBeValueType(TValue value, string parameterName)
+ where TValue : class
{
if (value.GetType().IsValueType)
{
diff --git a/src/ImageSharp/Common/Helpers/UnitConverter.cs b/src/ImageSharp/Common/Helpers/UnitConverter.cs
index 04ecb5afd0..983d86a711 100644
--- a/src/ImageSharp/Common/Helpers/UnitConverter.cs
+++ b/src/ImageSharp/Common/Helpers/UnitConverter.cs
@@ -91,7 +91,7 @@ internal static class UnitConverter
[MethodImpl(InliningOptions.ShortMethod)]
public static PixelResolutionUnit ExifProfileToResolutionUnit(ExifProfile profile)
{
- IExifValue resolution = profile.GetValue(ExifTag.ResolutionUnit);
+ IExifValue? resolution = profile.GetValue(ExifTag.ResolutionUnit);
// EXIF is 1, 2, 3 so we minus "1" off the result.
return resolution is null ? DefaultResolutionUnit : (PixelResolutionUnit)(byte)(resolution.Value - 1);
diff --git a/src/ImageSharp/Compression/Zlib/Deflater.cs b/src/ImageSharp/Compression/Zlib/Deflater.cs
index 78da8e8afe..f642ec85a7 100644
--- a/src/ImageSharp/Compression/Zlib/Deflater.cs
+++ b/src/ImageSharp/Compression/Zlib/Deflater.cs
@@ -284,7 +284,6 @@ public void Dispose()
if (!this.isDisposed)
{
this.engine.Dispose();
- this.engine = null;
this.isDisposed = true;
}
}
diff --git a/src/ImageSharp/Compression/Zlib/DeflaterEngine.cs b/src/ImageSharp/Compression/Zlib/DeflaterEngine.cs
index 2fc1d2743e..ec0f45abfd 100644
--- a/src/ImageSharp/Compression/Zlib/DeflaterEngine.cs
+++ b/src/ImageSharp/Compression/Zlib/DeflaterEngine.cs
@@ -86,7 +86,7 @@ internal sealed unsafe class DeflaterEngine : IDisposable
///
/// The input data for compression.
///
- private byte[] inputBuf;
+ private byte[]? inputBuf;
///
/// The offset into inputBuf, where input data starts.
@@ -221,12 +221,9 @@ public bool Deflate(bool flush, bool finish)
/// The buffer containing input data.
/// The offset of the first byte of data.
/// The number of bytes of data to use as input.
- public void SetInput(byte[] buffer, int offset, int count)
+ public void SetInput(byte[]? buffer, int offset, int count)
{
- if (buffer is null)
- {
- DeflateThrowHelper.ThrowNull(nameof(buffer));
- }
+ ArgumentNullException.ThrowIfNull(buffer);
if (offset < 0)
{
@@ -342,7 +339,7 @@ public void SetLevel(int level)
///
/// Fill the window
///
- public void FillWindow()
+ private void FillWindow()
{
// If the window is almost full and there is insufficient lookahead,
// move the upper half to the lower one to make room in the upper half.
@@ -361,6 +358,8 @@ public void FillWindow()
more = this.inputEnd - this.inputOff;
}
+ ArgumentNullException.ThrowIfNull(this.inputBuf);
+
Unsafe.CopyBlockUnaligned(
ref this.window.Span[this.strstart + this.lookahead],
ref this.inputBuf[this.inputOff],
@@ -392,11 +391,6 @@ public void Dispose()
this.prevMemoryHandle.Dispose();
this.prevMemoryOwner.Dispose();
- this.windowMemoryOwner = null;
- this.headMemoryOwner = null;
- this.prevMemoryOwner = null;
- this.huffman = null;
-
this.isDisposed = true;
}
}
diff --git a/src/ImageSharp/Compression/Zlib/DeflaterHuffman.cs b/src/ImageSharp/Compression/Zlib/DeflaterHuffman.cs
index 34058b43a8..dc11de4259 100644
--- a/src/ImageSharp/Compression/Zlib/DeflaterHuffman.cs
+++ b/src/ImageSharp/Compression/Zlib/DeflaterHuffman.cs
@@ -426,10 +426,6 @@ public void Dispose()
this.blTree.Dispose();
this.distTree.Dispose();
- this.Pending = null;
- this.literalTree = null;
- this.blTree = null;
- this.distTree = null;
this.isDisposed = true;
}
}
@@ -976,10 +972,6 @@ public void Dispose()
this.codesMemoryHandle.Dispose();
this.codesMemoryOwner.Dispose();
- this.frequenciesMemoryOwner = null;
- this.lengthsMemoryOwner = null;
- this.codesMemoryOwner = null;
-
this.isDisposed = true;
}
}
diff --git a/src/ImageSharp/Compression/Zlib/DeflaterOutputStream.cs b/src/ImageSharp/Compression/Zlib/DeflaterOutputStream.cs
index 6d7903caa1..de818fd8f5 100644
--- a/src/ImageSharp/Compression/Zlib/DeflaterOutputStream.cs
+++ b/src/ImageSharp/Compression/Zlib/DeflaterOutputStream.cs
@@ -136,8 +136,6 @@ protected override void Dispose(bool disposing)
this.memoryOwner.Dispose();
}
- this.deflater = null;
- this.memoryOwner = null;
this.isDisposed = true;
base.Dispose(disposing);
}
diff --git a/src/ImageSharp/Compression/Zlib/DeflaterPendingBuffer.cs b/src/ImageSharp/Compression/Zlib/DeflaterPendingBuffer.cs
index d2e0e27943..37e7404e40 100644
--- a/src/ImageSharp/Compression/Zlib/DeflaterPendingBuffer.cs
+++ b/src/ImageSharp/Compression/Zlib/DeflaterPendingBuffer.cs
@@ -179,7 +179,6 @@ public void Dispose()
{
this.bufferMemoryHandle.Dispose();
this.bufferMemoryOwner.Dispose();
- this.bufferMemoryOwner = null;
this.isDisposed = true;
}
}
diff --git a/src/ImageSharp/Compression/Zlib/ZlibDeflateStream.cs b/src/ImageSharp/Compression/Zlib/ZlibDeflateStream.cs
index b46283534d..2e52f84d7b 100644
--- a/src/ImageSharp/Compression/Zlib/ZlibDeflateStream.cs
+++ b/src/ImageSharp/Compression/Zlib/ZlibDeflateStream.cs
@@ -171,8 +171,6 @@ protected override void Dispose(bool disposing)
this.rawStream.WriteByte((byte)(crc & 0xFF));
}
- this.deflateStream = null;
-
base.Dispose(disposing);
this.isDisposed = true;
}
diff --git a/src/ImageSharp/Compression/Zlib/ZlibInflateStream.cs b/src/ImageSharp/Compression/Zlib/ZlibInflateStream.cs
index 410333dc48..66af8be78b 100644
--- a/src/ImageSharp/Compression/Zlib/ZlibInflateStream.cs
+++ b/src/ImageSharp/Compression/Zlib/ZlibInflateStream.cs
@@ -89,7 +89,7 @@ public ZlibInflateStream(BufferedReadStream innerStream, Func getData)
///
/// Gets the compressed stream over the deframed inner stream.
///
- public DeflateStream CompressedStream { get; private set; }
+ public DeflateStream? CompressedStream { get; private set; }
///
/// Adds new bytes from a frame found in the original stream.
diff --git a/src/ImageSharp/Diagnostics/MemoryDiagnostics.cs b/src/ImageSharp/Diagnostics/MemoryDiagnostics.cs
index b66cede3a0..8327daf23b 100644
--- a/src/ImageSharp/Diagnostics/MemoryDiagnostics.cs
+++ b/src/ImageSharp/Diagnostics/MemoryDiagnostics.cs
@@ -16,7 +16,7 @@ public static class MemoryDiagnostics
{
private static int totalUndisposedAllocationCount;
- private static UndisposedAllocationDelegate undisposedAllocation;
+ private static UndisposedAllocationDelegate? undisposedAllocation;
private static int undisposedAllocationSubscriptionCounter;
private static readonly object SyncRoot = new();
@@ -49,12 +49,12 @@ public static event UndisposedAllocationDelegate UndisposedAllocation
///
/// Fires when ImageSharp allocates memory from a MemoryAllocator
///
- internal static event Action MemoryAllocated;
+ internal static event Action? MemoryAllocated;
///
/// Fires when ImageSharp releases memory allocated from a MemoryAllocator
///
- internal static event Action MemoryReleased;
+ internal static event Action? MemoryReleased;
///
/// Gets a value indicating the total number of memory resource objects leaked to the finalizer.
diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoder.cs b/src/ImageSharp/Formats/Bmp/BmpDecoder.cs
index 35d5690c7d..982dc37cc4 100644
--- a/src/ImageSharp/Formats/Bmp/BmpDecoder.cs
+++ b/src/ImageSharp/Formats/Bmp/BmpDecoder.cs
@@ -35,6 +35,8 @@ Image IImageDecoderSpecialized.Decode(BmpDeco
Image image = new BmpDecoderCore(options).Decode(options.GeneralOptions.Configuration, stream, cancellationToken);
+ ArgumentNullException.ThrowIfNull(image);
+
ImageDecoderUtilities.Resize(options.GeneralOptions, image);
return image;
diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
index 1629d66843..a2ef44734a 100644
--- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
+++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
@@ -3,6 +3,7 @@
using System.Buffers;
using System.Buffers.Binary;
+using System.Diagnostics.CodeAnalysis;
using System.Numerics;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Common.Helpers;
@@ -57,20 +58,15 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals
///
private const int RleDelta = 0x02;
- ///
- /// The stream to decode from.
- ///
- private BufferedReadStream stream;
-
///
/// The metadata.
///
- private ImageMetadata metadata;
+ private ImageMetadata? metadata;
///
/// The bitmap specific metadata.
///
- private BmpMetadata bmpMetadata;
+ private BmpMetadata? bmpMetadata;
///
/// The file header containing general information.
@@ -119,13 +115,13 @@ public BmpDecoderCore(BmpDecoderOptions options)
public DecoderOptions Options { get; }
///
- public Size Dimensions => new(this.infoHeader.Width, this.infoHeader.Height);
+ public Size? Dimensions => new(this.infoHeader.Width, this.infoHeader.Height);
///
public Image Decode(BufferedReadStream stream, CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel
{
- Image image = null;
+ Image? image = null;
try
{
int bytesPerColorMapEntry = this.ReadImageHeaders(stream, out bool inverted, out byte[] palette);
@@ -141,24 +137,25 @@ public Image Decode(BufferedReadStream stream, CancellationToken
{
if (this.bmpMetadata.InfoHeaderType == BmpInfoHeaderType.WinVersion3)
{
- this.ReadRgb32Slow(pixels, this.infoHeader.Width, this.infoHeader.Height, inverted);
+ this.ReadRgb32Slow(stream, pixels, this.infoHeader.Width, this.infoHeader.Height, inverted);
}
else
{
- this.ReadRgb32Fast(pixels, this.infoHeader.Width, this.infoHeader.Height, inverted);
+ this.ReadRgb32Fast(stream, pixels, this.infoHeader.Width, this.infoHeader.Height, inverted);
}
}
else if (this.infoHeader.BitsPerPixel == 24)
{
- this.ReadRgb24(pixels, this.infoHeader.Width, this.infoHeader.Height, inverted);
+ this.ReadRgb24(stream, pixels, this.infoHeader.Width, this.infoHeader.Height, inverted);
}
else if (this.infoHeader.BitsPerPixel == 16)
{
- this.ReadRgb16(pixels, this.infoHeader.Width, this.infoHeader.Height, inverted);
+ this.ReadRgb16(stream, pixels, this.infoHeader.Width, this.infoHeader.Height, inverted);
}
else if (this.infoHeader.BitsPerPixel <= 8)
{
this.ReadRgbPalette(
+ stream,
pixels,
palette,
this.infoHeader.Width,
@@ -171,19 +168,19 @@ public Image Decode(BufferedReadStream stream, CancellationToken
break;
case BmpCompression.RLE24:
- this.ReadRle24(pixels, this.infoHeader.Width, this.infoHeader.Height, inverted);
+ this.ReadRle24(pixels, this.infoHeader.Width, this.infoHeader.Height, inverted, stream);
break;
case BmpCompression.RLE8:
case BmpCompression.RLE4:
- this.ReadRle(this.infoHeader.Compression, pixels, palette, this.infoHeader.Width, this.infoHeader.Height, inverted);
+ this.ReadRle(this.infoHeader.Compression, pixels, palette, this.infoHeader.Width, this.infoHeader.Height, inverted, stream);
break;
case BmpCompression.BitFields:
case BmpCompression.BI_ALPHABITFIELDS:
- this.ReadBitFields(pixels, inverted);
+ this.ReadBitFields(stream, pixels, inverted);
break;
@@ -251,12 +248,13 @@ private static int CalculatePadding(int width, int componentCount)
/// The pixel format.
/// The output pixel buffer containing the decoded image.
/// Whether the bitmap is inverted.
- private void ReadBitFields(Buffer2D pixels, bool inverted)
+ private void ReadBitFields(BufferedReadStream stream, Buffer2D pixels, bool inverted)
where TPixel : unmanaged, IPixel
{
if (this.infoHeader.BitsPerPixel == 16)
{
this.ReadRgb16(
+ stream,
pixels,
this.infoHeader.Width,
this.infoHeader.Height,
@@ -268,6 +266,7 @@ private void ReadBitFields(Buffer2D pixels, bool inverted)
else
{
this.ReadRgb32BitFields(
+ stream,
pixels,
this.infoHeader.Width,
this.infoHeader.Height,
@@ -291,7 +290,7 @@ private void ReadBitFields(Buffer2D pixels, bool inverted)
/// The width of the bitmap.
/// The height of the bitmap.
/// Whether the bitmap is inverted.
- private void ReadRle(BmpCompression compression, Buffer2D pixels, byte[] colors, int width, int height, bool inverted)
+ private void ReadRle(BmpCompression compression, Buffer2D pixels, byte[] colors, int width, int height, bool inverted, BufferedReadStream stream)
where TPixel : unmanaged, IPixel
{
TPixel color = default;
@@ -304,11 +303,11 @@ private void ReadRle(BmpCompression compression, Buffer2D pixels
Span bufferSpan = buffer.Memory.Span;
if (compression is BmpCompression.RLE8)
{
- this.UncompressRle8(width, bufferSpan, undefinedPixelsSpan, rowsWithUndefinedPixelsSpan);
+ this.UncompressRle8(width, bufferSpan, undefinedPixelsSpan, rowsWithUndefinedPixelsSpan, stream);
}
else
{
- this.UncompressRle4(width, bufferSpan, undefinedPixelsSpan, rowsWithUndefinedPixelsSpan);
+ this.UncompressRle4(width, bufferSpan, undefinedPixelsSpan, rowsWithUndefinedPixelsSpan, stream);
}
for (int y = 0; y < height; y++)
@@ -371,7 +370,7 @@ private void ReadRle(BmpCompression compression, Buffer2D pixels
/// The width of the bitmap.
/// The height of the bitmap.
/// Whether the bitmap is inverted.
- private void ReadRle24(Buffer2D pixels, int width, int height, bool inverted)
+ private void ReadRle24(Buffer2D pixels, int width, int height, bool inverted, BufferedReadStream stream)
where TPixel : unmanaged, IPixel
{
TPixel color = default;
@@ -383,7 +382,7 @@ private void ReadRle24(Buffer2D pixels, int width, int height, b
Span undefinedPixelsSpan = undefinedPixels.Memory.Span;
Span bufferSpan = buffer.GetSpan();
- this.UncompressRle24(width, bufferSpan, undefinedPixelsSpan, rowsWithUndefinedPixelsSpan);
+ this.UncompressRle24(width, bufferSpan, undefinedPixelsSpan, rowsWithUndefinedPixelsSpan, stream);
for (int y = 0; y < height; y++)
{
int newY = Invert(y, height, inverted);
@@ -449,14 +448,14 @@ private void ReadRle24(Buffer2D pixels, int width, int height, b
/// Buffer for uncompressed data.
/// Keeps track over skipped and therefore undefined pixels.
/// Keeps track of rows, which have undefined pixels.
- private void UncompressRle4(int w, Span buffer, Span undefinedPixels, Span rowsWithUndefinedPixels)
+ private void UncompressRle4(int w, Span buffer, Span undefinedPixels, Span rowsWithUndefinedPixels, BufferedReadStream stream)
{
Span cmd = stackalloc byte[2];
int count = 0;
while (count < buffer.Length)
{
- if (this.stream.Read(cmd, 0, cmd.Length) != 2)
+ if (stream.Read(cmd, 0, cmd.Length) != 2)
{
BmpThrowHelper.ThrowInvalidImageContentException("Failed to read 2 bytes from the stream while uncompressing RLE4 bitmap.");
}
@@ -477,8 +476,8 @@ private void UncompressRle4(int w, Span buffer, Span undefinedPixels
break;
case RleDelta:
- int dx = this.stream.ReadByte();
- int dy = this.stream.ReadByte();
+ int dx = stream.ReadByte();
+ int dy = stream.ReadByte();
count += RleSkipDelta(count, w, dx, dy, undefinedPixels, rowsWithUndefinedPixels);
break;
@@ -491,7 +490,7 @@ private void UncompressRle4(int w, Span buffer, Span undefinedPixels
byte[] run = new byte[bytesToRead];
- this.stream.Read(run, 0, run.Length);
+ stream.Read(run, 0, run.Length);
int idx = 0;
for (int i = 0; i < max; i++)
@@ -511,7 +510,7 @@ private void UncompressRle4(int w, Span buffer, Span undefinedPixels
// Absolute mode data is aligned to two-byte word-boundary.
int padding = bytesToRead & 1;
- this.stream.Skip(padding);
+ stream.Skip(padding);
break;
}
@@ -554,14 +553,14 @@ private void UncompressRle4(int w, Span buffer, Span undefinedPixels
/// Buffer for uncompressed data.
/// Keeps track of skipped and therefore undefined pixels.
/// Keeps track of rows, which have undefined pixels.
- private void UncompressRle8(int w, Span buffer, Span undefinedPixels, Span rowsWithUndefinedPixels)
+ private void UncompressRle8(int w, Span buffer, Span undefinedPixels, Span rowsWithUndefinedPixels, BufferedReadStream stream)
{
Span cmd = stackalloc byte[2];
int count = 0;
while (count < buffer.Length)
{
- if (this.stream.Read(cmd, 0, cmd.Length) != 2)
+ if (stream.Read(cmd, 0, cmd.Length) != 2)
{
BmpThrowHelper.ThrowInvalidImageContentException("Failed to read 2 bytes from stream while uncompressing RLE8 bitmap.");
}
@@ -582,8 +581,8 @@ private void UncompressRle8(int w, Span buffer, Span undefinedPixels
break;
case RleDelta:
- int dx = this.stream.ReadByte();
- int dy = this.stream.ReadByte();
+ int dx = stream.ReadByte();
+ int dy = stream.ReadByte();
count += RleSkipDelta(count, w, dx, dy, undefinedPixels, rowsWithUndefinedPixels);
break;
@@ -595,7 +594,7 @@ private void UncompressRle8(int w, Span buffer, Span undefinedPixels
byte[] run = new byte[length];
- this.stream.Read(run, 0, run.Length);
+ stream.Read(run, 0, run.Length);
run.AsSpan().CopyTo(buffer[count..]);
@@ -604,7 +603,7 @@ private void UncompressRle8(int w, Span buffer, Span undefinedPixels
// Absolute mode data is aligned to two-byte word-boundary.
int padding = length & 1;
- this.stream.Skip(padding);
+ stream.Skip(padding);
break;
}
@@ -633,14 +632,14 @@ private void UncompressRle8(int w, Span buffer, Span undefinedPixels
/// Buffer for uncompressed data.
/// Keeps track of skipped and therefore undefined pixels.
/// Keeps track of rows, which have undefined pixels.
- private void UncompressRle24(int w, Span buffer, Span undefinedPixels, Span rowsWithUndefinedPixels)
+ private void UncompressRle24(int w, Span buffer, Span undefinedPixels, Span rowsWithUndefinedPixels, BufferedReadStream stream)
{
Span cmd = stackalloc byte[2];
int uncompressedPixels = 0;
while (uncompressedPixels < buffer.Length)
{
- if (this.stream.Read(cmd, 0, cmd.Length) != 2)
+ if (stream.Read(cmd, 0, cmd.Length) != 2)
{
BmpThrowHelper.ThrowInvalidImageContentException("Failed to read 2 bytes from stream while uncompressing RLE24 bitmap.");
}
@@ -661,8 +660,8 @@ private void UncompressRle24(int w, Span buffer, Span undefinedPixel
break;
case RleDelta:
- int dx = this.stream.ReadByte();
- int dy = this.stream.ReadByte();
+ int dx = stream.ReadByte();
+ int dy = stream.ReadByte();
uncompressedPixels += RleSkipDelta(uncompressedPixels, w, dx, dy, undefinedPixels, rowsWithUndefinedPixels);
break;
@@ -674,7 +673,7 @@ private void UncompressRle24(int w, Span buffer, Span undefinedPixel
byte[] run = new byte[length * 3];
- this.stream.Read(run, 0, run.Length);
+ stream.Read(run, 0, run.Length);
run.AsSpan().CopyTo(buffer[(uncompressedPixels * 3)..]);
@@ -683,7 +682,7 @@ private void UncompressRle24(int w, Span buffer, Span undefinedPixel
// Absolute mode data is aligned to two-byte word-boundary.
int padding = run.Length & 1;
- this.stream.Skip(padding);
+ stream.Skip(padding);
break;
}
@@ -692,8 +691,8 @@ private void UncompressRle24(int w, Span buffer, Span undefinedPixel
{
int max = uncompressedPixels + cmd[0];
byte blueIdx = cmd[1];
- byte greenIdx = (byte)this.stream.ReadByte();
- byte redIdx = (byte)this.stream.ReadByte();
+ byte greenIdx = (byte)stream.ReadByte();
+ byte redIdx = (byte)stream.ReadByte();
int bufferIdx = uncompressedPixels * 3;
for (; uncompressedPixels < max; uncompressedPixels++)
@@ -807,7 +806,7 @@ private static int RleSkipDelta(
/// Usually 4 bytes, but in case of Windows 2.x bitmaps or OS/2 1.x bitmaps
/// the bytes per color palette entry's can be 3 bytes instead of 4.
/// Whether the bitmap is inverted.
- private void ReadRgbPalette(Buffer2D pixels, byte[] colors, int width, int height, int bitsPerPixel, int bytesPerColorMapEntry, bool inverted)
+ private void ReadRgbPalette( BufferedReadStream stream, Buffer2D pixels, byte[] colors, int width, int height, int bitsPerPixel, int bytesPerColorMapEntry, bool inverted)
where TPixel : unmanaged, IPixel
{
// Pixels per byte (bits per pixel).
@@ -832,7 +831,7 @@ private void ReadRgbPalette(Buffer2D pixels, byte[] colors, int
for (int y = 0; y < height; y++)
{
int newY = Invert(y, height, inverted);
- if (this.stream.Read(rowSpan) == 0)
+ if (stream.Read(rowSpan) == 0)
{
BmpThrowHelper.ThrowInvalidImageContentException("Could not read enough data for a pixel row!");
}
@@ -867,7 +866,7 @@ private void ReadRgbPalette(Buffer2D pixels, byte[] colors, int
/// The bitmask for the red channel.
/// The bitmask for the green channel.
/// The bitmask for the blue channel.
- private void ReadRgb16(Buffer2D pixels, int width, int height, bool inverted, int redMask = DefaultRgb16RMask, int greenMask = DefaultRgb16GMask, int blueMask = DefaultRgb16BMask)
+ private void ReadRgb16(BufferedReadStream stream, Buffer2D pixels, int width, int height, bool inverted, int redMask = DefaultRgb16RMask, int greenMask = DefaultRgb16GMask, int blueMask = DefaultRgb16BMask)
where TPixel : unmanaged, IPixel
{
int padding = CalculatePadding(width, 2);
@@ -888,7 +887,7 @@ private void ReadRgb16(Buffer2D pixels, int width, int height, b
for (int y = 0; y < height; y++)
{
- if (this.stream.Read(bufferSpan) == 0)
+ if (stream.Read(bufferSpan) == 0)
{
BmpThrowHelper.ThrowInvalidImageContentException("Could not read enough data for a pixel row!");
}
@@ -938,7 +937,7 @@ private void ReadRgb16(Buffer2D pixels, int width, int height, b
/// The width of the bitmap.
/// The height of the bitmap.
/// Whether the bitmap is inverted.
- private void ReadRgb24(Buffer2D pixels, int width, int height, bool inverted)
+ private void ReadRgb24(BufferedReadStream stream, Buffer2D pixels, int width, int height, bool inverted)
where TPixel : unmanaged, IPixel
{
int padding = CalculatePadding(width, 3);
@@ -947,7 +946,7 @@ private void ReadRgb24(Buffer2D pixels, int width, int height, b
for (int y = 0; y < height; y++)
{
- if (this.stream.Read(rowSpan) == 0)
+ if (stream.Read(rowSpan) == 0)
{
BmpThrowHelper.ThrowInvalidImageContentException("Could not read enough data for a pixel row!");
}
@@ -970,7 +969,7 @@ private void ReadRgb24(Buffer2D pixels, int width, int height, b
/// The width of the bitmap.
/// The height of the bitmap.
/// Whether the bitmap is inverted.
- private void ReadRgb32Fast(Buffer2D pixels, int width, int height, bool inverted)
+ private void ReadRgb32Fast(BufferedReadStream stream, Buffer2D pixels, int width, int height, bool inverted)
where TPixel : unmanaged, IPixel
{
int padding = CalculatePadding(width, 4);
@@ -979,7 +978,7 @@ private void ReadRgb32Fast(Buffer2D pixels, int width, int heigh
for (int y = 0; y < height; y++)
{
- if (this.stream.Read(rowSpan) == 0)
+ if (stream.Read(rowSpan) == 0)
{
BmpThrowHelper.ThrowInvalidImageContentException("Could not read enough data for a pixel row!");
}
@@ -1003,7 +1002,7 @@ private void ReadRgb32Fast(Buffer2D pixels, int width, int heigh
/// The width of the bitmap.
/// The height of the bitmap.
/// Whether the bitmap is inverted.
- private void ReadRgb32Slow(Buffer2D pixels, int width, int height, bool inverted)
+ private void ReadRgb32Slow(BufferedReadStream stream, Buffer2D pixels, int width, int height, bool inverted)
where TPixel : unmanaged, IPixel
{
int padding = CalculatePadding(width, 4);
@@ -1011,7 +1010,7 @@ private void ReadRgb32Slow(Buffer2D pixels, int width, int heigh
using IMemoryOwner bgraRow = this.memoryAllocator.Allocate(width);
Span rowSpan = row.GetSpan();
Span bgraRowSpan = bgraRow.GetSpan();
- long currentPosition = this.stream.Position;
+ long currentPosition = stream.Position;
bool hasAlpha = false;
// Loop though the rows checking each pixel. We start by assuming it's
@@ -1019,7 +1018,7 @@ private void ReadRgb32Slow(Buffer2D pixels, int width, int heigh
// actually a BGRA image, and change tactics accordingly.
for (int y = 0; y < height; y++)
{
- if (this.stream.Read(rowSpan) == 0)
+ if (stream.Read(rowSpan) == 0)
{
BmpThrowHelper.ThrowInvalidImageContentException("Could not read enough data for a pixel row!");
}
@@ -1048,14 +1047,14 @@ private void ReadRgb32Slow(Buffer2D pixels, int width, int heigh
}
// Reset our stream for a second pass.
- this.stream.Position = currentPosition;
+ stream.Position = currentPosition;
// Process the pixels in bulk taking the raw alpha component value.
if (hasAlpha)
{
for (int y = 0; y < height; y++)
{
- if (this.stream.Read(rowSpan) == 0)
+ if (stream.Read(rowSpan) == 0)
{
BmpThrowHelper.ThrowInvalidImageContentException("Could not read enough data for a pixel row!");
}
@@ -1076,7 +1075,7 @@ private void ReadRgb32Slow(Buffer2D pixels, int width, int heigh
// Slow path. We need to set each alpha component value to fully opaque.
for (int y = 0; y < height; y++)
{
- if (this.stream.Read(rowSpan) == 0)
+ if (stream.Read(rowSpan) == 0)
{
BmpThrowHelper.ThrowInvalidImageContentException("Could not read enough data for a pixel row!");
}
@@ -1112,7 +1111,7 @@ private void ReadRgb32Slow(Buffer2D pixels, int width, int heigh
/// The bitmask for the green channel.
/// The bitmask for the blue channel.
/// The bitmask for the alpha channel.
- private void ReadRgb32BitFields(Buffer2D pixels, int width, int height, bool inverted, int redMask, int greenMask, int blueMask, int alphaMask)
+ private void ReadRgb32BitFields(BufferedReadStream stream, Buffer2D pixels, int width, int height, bool inverted, int redMask, int greenMask, int blueMask, int alphaMask)
where TPixel : unmanaged, IPixel
{
TPixel color = default;
@@ -1141,7 +1140,7 @@ private void ReadRgb32BitFields(Buffer2D pixels, int width, int
for (int y = 0; y < height; y++)
{
- if (this.stream.Read(bufferSpan) == 0)
+ if (stream.Read(bufferSpan) == 0)
{
BmpThrowHelper.ThrowInvalidImageContentException("Could not read enough data for a pixel row!");
}
@@ -1227,10 +1226,12 @@ private static int CountBits(uint n)
///
/// Reads the from the stream.
///
- private void ReadInfoHeader()
+ [MemberNotNull(nameof(metadata))]
+ [MemberNotNull(nameof(bmpMetadata))]
+ private void ReadInfoHeader(BufferedReadStream stream)
{
Span buffer = stackalloc byte[BmpInfoHeader.MaxHeaderSize];
- long infoHeaderStart = this.stream.Position;
+ long infoHeaderStart = stream.Position;
// Resolution is stored in PPM.
this.metadata = new ImageMetadata
@@ -1239,7 +1240,7 @@ private void ReadInfoHeader()
};
// Read the header size.
- this.stream.Read(buffer, 0, BmpInfoHeader.HeaderSizeSize);
+ stream.Read(buffer, 0, BmpInfoHeader.HeaderSizeSize);
int headerSize = BinaryPrimitives.ReadInt32LittleEndian(buffer);
if (headerSize is < BmpInfoHeader.CoreSize or > BmpInfoHeader.MaxHeaderSize)
@@ -1248,7 +1249,7 @@ private void ReadInfoHeader()
}
// Read the rest of the header.
- this.stream.Read(buffer, BmpInfoHeader.HeaderSizeSize, headerSize - BmpInfoHeader.HeaderSizeSize);
+ stream.Read(buffer, BmpInfoHeader.HeaderSizeSize, headerSize - BmpInfoHeader.HeaderSizeSize);
BmpInfoHeaderType infoHeaderType = BmpInfoHeaderType.WinVersion2;
if (headerSize == BmpInfoHeader.CoreSize)
@@ -1274,7 +1275,7 @@ private void ReadInfoHeader()
if (this.infoHeader.Compression == BmpCompression.BitFields)
{
byte[] bitfieldsBuffer = new byte[12];
- this.stream.Read(bitfieldsBuffer, 0, 12);
+ stream.Read(bitfieldsBuffer, 0, 12);
Span data = bitfieldsBuffer.AsSpan();
this.infoHeader.RedMask = BinaryPrimitives.ReadInt32LittleEndian(data[..4]);
this.infoHeader.GreenMask = BinaryPrimitives.ReadInt32LittleEndian(data.Slice(4, 4));
@@ -1283,7 +1284,7 @@ private void ReadInfoHeader()
else if (this.infoHeader.Compression == BmpCompression.BI_ALPHABITFIELDS)
{
byte[] bitfieldsBuffer = new byte[16];
- this.stream.Read(bitfieldsBuffer, 0, 16);
+ stream.Read(bitfieldsBuffer, 0, 16);
Span data = bitfieldsBuffer.AsSpan();
this.infoHeader.RedMask = BinaryPrimitives.ReadInt32LittleEndian(data[..4]);
this.infoHeader.GreenMask = BinaryPrimitives.ReadInt32LittleEndian(data.Slice(4, 4));
@@ -1323,12 +1324,12 @@ private void ReadInfoHeader()
if (this.infoHeader.ProfileData != 0 && this.infoHeader.ProfileSize != 0)
{
// Read color profile.
- long streamPosition = this.stream.Position;
+ long streamPosition = stream.Position;
byte[] iccProfileData = new byte[this.infoHeader.ProfileSize];
- this.stream.Position = infoHeaderStart + this.infoHeader.ProfileData;
- this.stream.Read(iccProfileData);
+ stream.Position = infoHeaderStart + this.infoHeader.ProfileData;
+ stream.Read(iccProfileData);
this.metadata.IccProfile = new IccProfile(iccProfileData);
- this.stream.Position = streamPosition;
+ stream.Position = streamPosition;
}
}
else
@@ -1357,10 +1358,10 @@ private void ReadInfoHeader()
///
/// Reads the from the stream.
///
- private void ReadFileHeader()
+ private void ReadFileHeader(BufferedReadStream stream)
{
Span buffer = stackalloc byte[BmpFileHeader.Size];
- this.stream.Read(buffer, 0, BmpFileHeader.Size);
+ stream.Read(buffer, 0, BmpFileHeader.Size);
short fileTypeMarker = BinaryPrimitives.ReadInt16LittleEndian(buffer);
switch (fileTypeMarker)
@@ -1374,7 +1375,7 @@ private void ReadFileHeader()
// Because we only decode the first bitmap in the array, the array header will be ignored.
// The bitmap file header of the first image follows the array header.
- this.stream.Read(buffer, 0, BmpFileHeader.Size);
+ stream.Read(buffer, 0, BmpFileHeader.Size);
this.fileHeader = BmpFileHeader.Parse(buffer);
if (this.fileHeader.Type != BmpConstants.TypeMarkers.Bitmap)
{
@@ -1397,12 +1398,12 @@ private void ReadFileHeader()
/// The color palette.
/// Bytes per color palette entry. Usually 4 bytes, but in case of Windows 2.x bitmaps or OS/2 1.x bitmaps
/// the bytes per color palette entry's can be 3 bytes instead of 4.
+ [MemberNotNull(nameof(metadata))]
+ [MemberNotNull(nameof(bmpMetadata))]
private int ReadImageHeaders(BufferedReadStream stream, out bool inverted, out byte[] palette)
{
- this.stream = stream;
-
- this.ReadFileHeader();
- this.ReadInfoHeader();
+ this.ReadFileHeader(stream);
+ this.ReadInfoHeader(stream);
// see http://www.drdobbs.com/architecture-and-design/the-bmp-file-format-part-1/184409517
// If the height is negative, then this is a Windows bitmap whose origin
@@ -1450,13 +1451,13 @@ private int ReadImageHeaders(BufferedReadStream stream, out bool inverted, out b
colorMapSizeBytes = this.infoHeader.ClrUsed * bytesPerColorMapEntry;
}
- palette = null;
+ palette = Array.Empty();
if (colorMapSizeBytes > 0)
{
// Usually the color palette is 1024 byte (256 colors * 4), but the documentation does not mention a size limit.
// Make sure, that we will not read pass the bitmap offset (starting position of image data).
- if ((this.stream.Position + colorMapSizeBytes) > this.fileHeader.Offset)
+ if ((stream.Position + colorMapSizeBytes) > this.fileHeader.Offset)
{
BmpThrowHelper.ThrowInvalidImageContentException(
$"Reading the color map would read beyond the bitmap offset. Either the color map size of '{colorMapSizeBytes}' is invalid or the bitmap offset.");
@@ -1464,21 +1465,21 @@ private int ReadImageHeaders(BufferedReadStream stream, out bool inverted, out b
palette = new byte[colorMapSizeBytes];
- if (this.stream.Read(palette, 0, colorMapSizeBytes) == 0)
+ if (stream.Read(palette, 0, colorMapSizeBytes) == 0)
{
BmpThrowHelper.ThrowInvalidImageContentException("Could not read enough data for the palette!");
}
}
- int skipAmount = this.fileHeader.Offset - (int)this.stream.Position;
- if ((skipAmount + (int)this.stream.Position) > this.stream.Length)
+ int skipAmount = this.fileHeader.Offset - (int)stream.Position;
+ if ((skipAmount + (int)stream.Position) > stream.Length)
{
BmpThrowHelper.ThrowInvalidImageContentException("Invalid file header offset found. Offset is greater than the stream length.");
}
if (skipAmount > 0)
{
- this.stream.Skip(skipAmount);
+ stream.Skip(skipAmount);
}
return bytesPerColorMapEntry;
diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoder.cs b/src/ImageSharp/Formats/Bmp/BmpEncoder.cs
index a410a862b5..4b947660fd 100644
--- a/src/ImageSharp/Formats/Bmp/BmpEncoder.cs
+++ b/src/ImageSharp/Formats/Bmp/BmpEncoder.cs
@@ -29,7 +29,7 @@ public sealed class BmpEncoder : IImageEncoder, IBmpEncoderOptions
/// Gets or sets the quantizer for reducing the color count for 8-Bit images.
/// Defaults to Wu Quantizer.
///
- public IQuantizer Quantizer { get; set; }
+ public IQuantizer? Quantizer { get; set; }
///
public void Encode(Image image, Stream stream)
diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs
index 471e741826..bc97b37647 100644
--- a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs
+++ b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs
@@ -72,7 +72,7 @@ internal sealed class BmpEncoderCore : IImageEncoderInternals
///
/// The global configuration.
///
- private Configuration configuration;
+ private Configuration? configuration;
///
/// The color depth, in number of bits per pixel.
@@ -136,7 +136,7 @@ public void Encode(Image image, Stream stream, CancellationToken
_ => 0
};
- byte[] iccProfileData = null;
+ byte[]? iccProfileData = null;
int iccProfileSize = 0;
if (metadata.IccProfile != null)
{
@@ -176,7 +176,7 @@ public void Encode(Image image, Stream stream, CancellationToken
/// The metadata.
/// The icc profile data.
/// The bitmap information header.
- private BmpInfoHeader CreateBmpInfoHeader(int width, int height, int infoHeaderSize, short bpp, int bytesPerLine, ImageMetadata metadata, byte[] iccProfileData)
+ private BmpInfoHeader CreateBmpInfoHeader(int width, int height, int infoHeaderSize, short bpp, int bytesPerLine, ImageMetadata metadata, byte[]? iccProfileData)
{
int hResolution = 0;
int vResolution = 0;
@@ -228,7 +228,7 @@ private BmpInfoHeader CreateBmpInfoHeader(int width, int height, int infoHeaderS
infoHeader.Compression = BmpCompression.BitFields;
}
- if (this.infoHeaderType is BmpInfoHeaderType.WinVersion5 && metadata.IccProfile != null)
+ if (this.infoHeaderType is BmpInfoHeaderType.WinVersion5 && metadata.IccProfile != null && iccProfileData != null)
{
infoHeader.ProfileSize = iccProfileData.Length;
infoHeader.CsType = BmpColorSpace.PROFILE_EMBEDDED;
@@ -244,7 +244,7 @@ private BmpInfoHeader CreateBmpInfoHeader(int width, int height, int infoHeaderS
/// The stream to write to.
/// The color profile data.
/// The buffer.
- private static void WriteColorProfile(Stream stream, byte[] iccProfileData, Span buffer)
+ private static void WriteColorProfile(Stream stream, byte[]? iccProfileData, Span buffer)
{
if (iccProfileData != null)
{
@@ -314,7 +314,7 @@ private void WriteBitmapInfoHeader(Stream stream, BmpInfoHeader infoHeader, Span
private void WriteImage(Stream stream, ImageFrame image)
where TPixel : unmanaged, IPixel
{
- Buffer2D pixels = image.PixelBuffer;
+ Buffer2D pixels = image.PixelBuffer!;
switch (this.bitsPerPixel)
{
case BmpBitsPerPixel.Pixel32:
@@ -461,6 +461,8 @@ private void Write8BitPixelData(Stream stream, ImageFrame image)
private void Write8BitColor(Stream stream, ImageFrame image, Span colorPalette)
where TPixel : unmanaged, IPixel
{
+ ArgumentNullException.ThrowIfNull(this.configuration);
+
using IQuantizer frameQuantizer = this.quantizer.CreatePixelSpecificQuantizer(this.configuration);
using IndexedImageFrame quantized = frameQuantizer.BuildPaletteAndQuantizeFrame(image, image.Bounds());
@@ -503,7 +505,7 @@ private void Write8BitPixelData(Stream stream, ImageFrame image,
}
stream.Write(colorPalette);
- Buffer2D imageBuffer = image.PixelBuffer;
+ Buffer2D imageBuffer = image.PixelBuffer!;
for (int y = image.Height - 1; y >= 0; y--)
{
ReadOnlySpan inputPixelRow = imageBuffer.DangerousGetRowSpan(y);
@@ -526,6 +528,8 @@ private void Write8BitPixelData(Stream stream, ImageFrame image,
private void Write4BitPixelData(Stream stream, ImageFrame image)
where TPixel : unmanaged, IPixel
{
+ ArgumentNullException.ThrowIfNull(this.configuration);
+
using IQuantizer frameQuantizer = this.quantizer.CreatePixelSpecificQuantizer(this.configuration, new QuantizerOptions()
{
MaxColors = 16
@@ -570,6 +574,8 @@ private void Write4BitPixelData(Stream stream, ImageFrame image)
private void Write2BitPixelData(Stream stream, ImageFrame image)
where TPixel : unmanaged, IPixel
{
+ ArgumentNullException.ThrowIfNull(this.configuration);
+
using IQuantizer frameQuantizer = this.quantizer.CreatePixelSpecificQuantizer(this.configuration, new QuantizerOptions()
{
MaxColors = 4
@@ -623,6 +629,8 @@ private void Write2BitPixelData(Stream stream, ImageFrame image)
private void Write1BitPixelData(Stream stream, ImageFrame image)
where TPixel : unmanaged, IPixel
{
+ ArgumentNullException.ThrowIfNull(this.configuration);
+
using IQuantizer frameQuantizer = this.quantizer.CreatePixelSpecificQuantizer(this.configuration, new QuantizerOptions()
{
MaxColors = 2
diff --git a/src/ImageSharp/Formats/Bmp/BmpImageFormatDetector.cs b/src/ImageSharp/Formats/Bmp/BmpImageFormatDetector.cs
index a10f6b74a9..162c8ed399 100644
--- a/src/ImageSharp/Formats/Bmp/BmpImageFormatDetector.cs
+++ b/src/ImageSharp/Formats/Bmp/BmpImageFormatDetector.cs
@@ -14,7 +14,7 @@ public sealed class BmpImageFormatDetector : IImageFormatDetector
public int HeaderSize => 2;
///
- public IImageFormat DetectFormat(ReadOnlySpan header)
+ public IImageFormat? DetectFormat(ReadOnlySpan header)
{
return this.IsSupportedFileFormat(header) ? BmpFormat.Instance : null;
}
diff --git a/src/ImageSharp/Formats/Bmp/IBmpEncoderOptions.cs b/src/ImageSharp/Formats/Bmp/IBmpEncoderOptions.cs
index c2ce99ec71..6a07f7867e 100644
--- a/src/ImageSharp/Formats/Bmp/IBmpEncoderOptions.cs
+++ b/src/ImageSharp/Formats/Bmp/IBmpEncoderOptions.cs
@@ -26,5 +26,5 @@ internal interface IBmpEncoderOptions
///
/// Gets the quantizer for reducing the color count for 8-Bit, 4-Bit, and 1-Bit images.
///
- IQuantizer Quantizer { get; }
+ IQuantizer? Quantizer { get; }
}
diff --git a/src/ImageSharp/Formats/Gif/GifDecoder.cs b/src/ImageSharp/Formats/Gif/GifDecoder.cs
index cf8f4637ef..21d08e2e94 100644
--- a/src/ImageSharp/Formats/Gif/GifDecoder.cs
+++ b/src/ImageSharp/Formats/Gif/GifDecoder.cs
@@ -28,6 +28,8 @@ Image IImageDecoder.Decode(DecoderOptions options, Stream stream
GifDecoderCore decoder = new(options);
Image image = decoder.Decode(options.Configuration, stream, cancellationToken);
+ ArgumentNullException.ThrowIfNull(image);
+
ImageDecoderUtilities.Resize(options, image);
return image;
diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs
index ef29863d4f..1e0f98f8d2 100644
--- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs
+++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs
@@ -2,6 +2,7 @@
// Licensed under the Six Labors Split License.
using System.Buffers;
+using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
@@ -23,15 +24,10 @@ internal sealed class GifDecoderCore : IImageDecoderInternals
///
private readonly byte[] buffer = new byte[16];
- ///
- /// The currently loaded stream.
- ///
- private BufferedReadStream stream;
-
///
/// The global color table.
///
- private IMemoryOwner globalColorTable;
+ private IMemoryOwner? globalColorTable;
///
/// The area to restore.
@@ -76,12 +72,12 @@ internal sealed class GifDecoderCore : IImageDecoderInternals
///
/// The abstract metadata.
///
- private ImageMetadata metadata;
+ private ImageMetadata? metadata;
///
/// The gif specific metadata.
///
- private GifMetadata gifMetadata;
+ private GifMetadata? gifMetadata;
///
/// Initializes a new instance of the class.
@@ -100,15 +96,15 @@ public GifDecoderCore(DecoderOptions options)
public DecoderOptions Options { get; }
///
- public Size Dimensions => new(this.imageDescriptor.Width, this.imageDescriptor.Height);
+ public Size? Dimensions => new(this.imageDescriptor.Width, this.imageDescriptor.Height);
///
public Image Decode(BufferedReadStream stream, CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel
{
uint frameCount = 0;
- Image image = null;
- ImageFrame previousFrame = null;
+ Image? image = null;
+ ImageFrame? previousFrame = null;
try
{
this.ReadLogicalScreenDescriptorAndGlobalColorTable(stream);
@@ -124,23 +120,23 @@ public Image Decode(BufferedReadStream stream, CancellationToken
break;
}
- this.ReadFrame(ref image, ref previousFrame);
+ this.ReadFrame(ref image, ref previousFrame, stream);
}
else if (nextFlag == GifConstants.ExtensionIntroducer)
{
switch (stream.ReadByte())
{
case GifConstants.GraphicControlLabel:
- this.ReadGraphicalControlExtension();
+ this.ReadGraphicalControlExtension(stream);
break;
case GifConstants.CommentLabel:
- this.ReadComments();
+ this.ReadComments(stream);
break;
case GifConstants.ApplicationExtensionLabel:
- this.ReadApplicationExtension();
+ this.ReadApplicationExtension(stream);
break;
case GifConstants.PlainTextLabel:
- this.SkipBlock(); // Not supported by any known decoder.
+ this.SkipBlock(stream); // Not supported by any known decoder.
break;
}
}
@@ -161,7 +157,7 @@ public Image Decode(BufferedReadStream stream, CancellationToken
this.globalColorTable?.Dispose();
}
- return image;
+ return image!;
}
///
@@ -177,23 +173,23 @@ public IImageInfo Identify(BufferedReadStream stream, CancellationToken cancella
{
if (nextFlag == GifConstants.ImageLabel)
{
- this.ReadImageDescriptor();
+ this.ReadImageDescriptor(stream);
}
else if (nextFlag == GifConstants.ExtensionIntroducer)
{
switch (stream.ReadByte())
{
case GifConstants.GraphicControlLabel:
- this.SkipBlock(); // Skip graphic control extension block
+ this.SkipBlock(stream); // Skip graphic control extension block
break;
case GifConstants.CommentLabel:
- this.ReadComments();
+ this.ReadComments(stream);
break;
case GifConstants.ApplicationExtensionLabel:
- this.ReadApplicationExtension();
+ this.ReadApplicationExtension(stream);
break;
case GifConstants.PlainTextLabel:
- this.SkipBlock(); // Not supported by any known decoder.
+ this.SkipBlock(stream); // Not supported by any known decoder.
break;
}
}
@@ -224,9 +220,9 @@ public IImageInfo Identify(BufferedReadStream stream, CancellationToken cancella
///
/// Reads the graphic control extension.
///
- private void ReadGraphicalControlExtension()
+ private void ReadGraphicalControlExtension(BufferedReadStream stream)
{
- int bytesRead = this.stream.Read(this.buffer, 0, 6);
+ int bytesRead = stream.Read(this.buffer, 0, 6);
if (bytesRead != 6)
{
GifThrowHelper.ThrowInvalidImageContentException("Not enough data to read the graphic control extension");
@@ -238,9 +234,9 @@ private void ReadGraphicalControlExtension()
///
/// Reads the image descriptor.
///
- private void ReadImageDescriptor()
+ private void ReadImageDescriptor(BufferedReadStream stream)
{
- int bytesRead = this.stream.Read(this.buffer, 0, 9);
+ int bytesRead = stream.Read(this.buffer, 0, 9);
if (bytesRead != 9)
{
GifThrowHelper.ThrowInvalidImageContentException("Not enough data to read the image descriptor");
@@ -256,9 +252,9 @@ private void ReadImageDescriptor()
///
/// Reads the logical screen descriptor.
///
- private void ReadLogicalScreenDescriptor()
+ private void ReadLogicalScreenDescriptor(BufferedReadStream stream)
{
- int bytesRead = this.stream.Read(this.buffer, 0, 7);
+ int bytesRead = stream.Read(this.buffer, 0, 7);
if (bytesRead != 7)
{
GifThrowHelper.ThrowInvalidImageContentException("Not enough data to read the logical screen descriptor");
@@ -271,22 +267,24 @@ private void ReadLogicalScreenDescriptor()
/// Reads the application extension block parsing any animation or XMP information
/// if present.
///
- private void ReadApplicationExtension()
+ private void ReadApplicationExtension(BufferedReadStream stream)
{
- int appLength = this.stream.ReadByte();
+ int appLength = stream.ReadByte();
// If the length is 11 then it's a valid extension and most likely
// a NETSCAPE, XMP or ANIMEXTS extension. We want the loop count from this.
if (appLength == GifConstants.ApplicationBlockSize)
{
- this.stream.Read(this.buffer, 0, GifConstants.ApplicationBlockSize);
+ stream.Read(this.buffer, 0, GifConstants.ApplicationBlockSize);
bool isXmp = this.buffer.AsSpan().StartsWith(GifConstants.XmpApplicationIdentificationBytes);
if (isXmp && !this.skipMetadata)
{
- var extension = GifXmpApplicationExtension.Read(this.stream, this.memoryAllocator);
+ var extension = GifXmpApplicationExtension.Read(stream, this.memoryAllocator);
if (extension.Data.Length > 0)
{
+ ArgumentNullException.ThrowIfNull(this.metadata);
+
this.metadata.XmpProfile = new XmpProfile(extension.Data);
}
@@ -294,57 +292,60 @@ private void ReadApplicationExtension()
}
else
{
- int subBlockSize = this.stream.ReadByte();
+ int subBlockSize = stream.ReadByte();
// TODO: There's also a NETSCAPE buffer extension.
// http://www.vurdalakov.net/misc/gif/netscape-buffering-application-extension
if (subBlockSize == GifConstants.NetscapeLoopingSubBlockSize)
{
- this.stream.Read(this.buffer, 0, GifConstants.NetscapeLoopingSubBlockSize);
+ stream.Read(this.buffer, 0, GifConstants.NetscapeLoopingSubBlockSize);
+
+ ArgumentNullException.ThrowIfNull(this.gifMetadata);
+
this.gifMetadata.RepeatCount = GifNetscapeLoopingApplicationExtension.Parse(this.buffer.AsSpan(1)).RepeatCount;
- this.stream.Skip(1); // Skip the terminator.
+ stream.Skip(1); // Skip the terminator.
return;
}
// Could be something else not supported yet.
// Skip the subblock and terminator.
- this.SkipBlock(subBlockSize);
+ this.SkipBlock(stream, subBlockSize);
}
return;
}
- this.SkipBlock(appLength); // Not supported by any known decoder.
+ this.SkipBlock(stream, appLength); // Not supported by any known decoder.
}
///
/// Skips over a block or reads its terminator.
/// The length of the block to skip.
///
- private void SkipBlock(int blockSize = 0)
+ private void SkipBlock(BufferedReadStream stream, int blockSize = 0)
{
if (blockSize > 0)
{
- this.stream.Skip(blockSize);
+ stream.Skip(blockSize);
}
int flag;
- while ((flag = this.stream.ReadByte()) > 0)
+ while ((flag = stream.ReadByte()) > 0)
{
- this.stream.Skip(flag);
+ stream.Skip(flag);
}
}
///
/// Reads the gif comments.
///
- private void ReadComments()
+ private void ReadComments(BufferedReadStream stream)
{
int length;
var stringBuilder = new StringBuilder();
- while ((length = this.stream.ReadByte()) != 0)
+ while ((length = stream.ReadByte()) != 0)
{
if (length > GifConstants.MaxCommentSubBlockLength)
{
@@ -353,20 +354,22 @@ private void ReadComments()
if (this.skipMetadata)
{
- this.stream.Seek(length, SeekOrigin.Current);
+ stream.Seek(length, SeekOrigin.Current);
continue;
}
using IMemoryOwner commentsBuffer = this.memoryAllocator.Allocate(length);
Span commentsSpan = commentsBuffer.GetSpan();
- this.stream.Read(commentsSpan);
+ stream.Read(commentsSpan);
string commentPart = GifConstants.Encoding.GetString(commentsSpan);
stringBuilder.Append(commentPart);
}
if (stringBuilder.Length > 0)
{
+ ArgumentNullException.ThrowIfNull(this.gifMetadata);
+
this.gifMetadata.Comments.Add(stringBuilder.ToString());
}
}
@@ -377,13 +380,13 @@ private void ReadComments()
/// The pixel format.
/// The image to decode the information to.
/// The previous frame.
- private void ReadFrame(ref Image image, ref ImageFrame previousFrame)
+ private void ReadFrame(ref Image? image, ref ImageFrame? previousFrame, BufferedReadStream stream)
where TPixel : unmanaged, IPixel
{
- this.ReadImageDescriptor();
+ this.ReadImageDescriptor(stream);
- IMemoryOwner localColorTable = null;
- Buffer2D indices = null;
+ IMemoryOwner? localColorTable = null;
+ Buffer2D? indices = null;
try
{
// Determine the color table for this frame. If there is a local one, use it otherwise use the global color table.
@@ -391,11 +394,11 @@ private void ReadFrame(ref Image image, ref ImageFrame p
{
int length = this.imageDescriptor.LocalColorTableSize * 3;
localColorTable = this.configuration.MemoryAllocator.Allocate(length, AllocationOptions.Clean);
- this.stream.Read(localColorTable.GetSpan());
+ stream.Read(localColorTable.GetSpan());
}
indices = this.configuration.MemoryAllocator.Allocate2D(this.imageDescriptor.Width, this.imageDescriptor.Height, AllocationOptions.Clean);
- this.ReadFrameIndices(indices);
+ this.ReadFrameIndices(indices, stream);
Span rawColorTable = default;
if (localColorTable != null)
@@ -411,7 +414,7 @@ private void ReadFrame(ref Image image, ref ImageFrame p
this.ReadFrameColors(ref image, ref previousFrame, indices, colorTable, this.imageDescriptor);
// Skip any remaining blocks
- this.SkipBlock();
+ this.SkipBlock(stream);
}
finally
{
@@ -425,10 +428,10 @@ private void ReadFrame(ref Image image, ref ImageFrame p
///
/// The 2D pixel buffer to write to.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void ReadFrameIndices(Buffer2D indices)
+ private void ReadFrameIndices(Buffer2D indices, BufferedReadStream stream)
{
- int minCodeSize = this.stream.ReadByte();
- using var lzwDecoder = new LzwDecoder(this.configuration.MemoryAllocator, this.stream);
+ int minCodeSize = stream.ReadByte();
+ using var lzwDecoder = new LzwDecoder(this.configuration.MemoryAllocator, stream);
lzwDecoder.DecodePixels(minCodeSize, indices);
}
@@ -441,19 +444,21 @@ private void ReadFrameIndices(Buffer2D indices)
/// The indexed pixels.
/// The color table containing the available colors.
/// The
- private void ReadFrameColors(ref Image image, ref ImageFrame previousFrame, Buffer2D indices, ReadOnlySpan colorTable, in GifImageDescriptor descriptor)
+ private void ReadFrameColors(ref Image? image, ref ImageFrame? previousFrame, Buffer2D indices, ReadOnlySpan colorTable, in GifImageDescriptor descriptor)
where TPixel : unmanaged, IPixel
{
int imageWidth = this.logicalScreenDescriptor.Width;
int imageHeight = this.logicalScreenDescriptor.Height;
bool transFlag = this.graphicsControlExtension.TransparencyFlag;
- ImageFrame prevFrame = null;
- ImageFrame currentFrame = null;
+ ImageFrame? prevFrame = null;
+ ImageFrame? currentFrame = null;
ImageFrame imageFrame;
if (previousFrame is null)
{
+ ArgumentNullException.ThrowIfNull(this.metadata);
+
if (!transFlag)
{
image = new Image(this.configuration, imageWidth, imageHeight, Color.Black.ToPixel(), this.metadata);
@@ -475,6 +480,8 @@ private void ReadFrameColors(ref Image image, ref ImageFrame(ref Image image, ref ImageFrame(ImageFrame frame)
}
var interest = Rectangle.Intersect(frame.Bounds(), this.restoreArea.Value);
- Buffer2DRegion pixelRegion = frame.PixelBuffer.GetRegion(interest);
+ Buffer2DRegion pixelRegion = frame.PixelBuffer!.GetRegion(interest);
pixelRegion.Clear();
this.restoreArea = null;
@@ -631,13 +638,13 @@ private void SetFrameMetadata(ImageFrameMetadata meta)
/// Reads the logical screen descriptor and global color table blocks
///
/// The stream containing image data.
+ [MemberNotNull(nameof(metadata))]
+ [MemberNotNull(nameof(gifMetadata))]
private void ReadLogicalScreenDescriptorAndGlobalColorTable(BufferedReadStream stream)
{
- this.stream = stream;
-
// Skip the identifier
- this.stream.Skip(6);
- this.ReadLogicalScreenDescriptor();
+ stream.Skip(6);
+ this.ReadLogicalScreenDescriptor(stream);
var meta = new ImageMetadata();
diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs
index cfd4ba36a6..ebf9b67597 100644
--- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs
+++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs
@@ -120,7 +120,7 @@ public void Encode(Image image, Stream stream, CancellationToken
this.WriteComments(gifMetadata, stream);
// Write application extensions.
- XmpProfile xmpProfile = image.Metadata.XmpProfile ?? image.Frames.RootFrame.Metadata.XmpProfile;
+ XmpProfile? xmpProfile = image.Metadata.XmpProfile ?? image.Frames.RootFrame.Metadata.XmpProfile;
this.WriteApplicationExtensions(stream, image.Frames.Count, gifMetadata.RepeatCount, xmpProfile);
if (useGlobalTable)
@@ -174,11 +174,11 @@ private void EncodeGlobal(Image image, IndexedImageFrame
paletteFrameQuantizer.Dispose();
}
- private void EncodeLocal(Image image, IndexedImageFrame quantized, Stream stream)
+ private void EncodeLocal(Image image, IndexedImageFrame? quantized, Stream stream)
where TPixel : unmanaged, IPixel
{
- ImageFrame previousFrame = null;
- GifFrameMetadata previousMeta = null;
+ ImageFrame? previousFrame = null;
+ GifFrameMetadata? previousMeta = null;
for (int i = 0; i < image.Frames.Count; i++)
{
ImageFrame frame = image.Frames[i];
@@ -187,7 +187,7 @@ private void EncodeLocal(Image image, IndexedImageFrame
if (quantized is null)
{
// Allow each frame to be encoded at whatever color depth the frame designates if set.
- if (previousFrame != null && previousMeta.ColorTableLength != frameMetadata.ColorTableLength
+ if (previousFrame != null && previousMeta?.ColorTableLength != frameMetadata.ColorTableLength
&& frameMetadata.ColorTableLength > 0)
{
QuantizerOptions options = new()
@@ -324,7 +324,7 @@ private void WriteLogicalScreenDescriptor(
/// The frame count fo this image.
/// The animated image repeat count.
/// The XMP metadata profile. Null if profile is not to be written.
- private void WriteApplicationExtensions(Stream stream, int frameCount, ushort repeatCount, XmpProfile xmpProfile)
+ private void WriteApplicationExtensions(Stream stream, int frameCount, ushort repeatCount, XmpProfile? xmpProfile)
{
// Application Extension: Loop repeat count.
if (frameCount > 1 && repeatCount != 1)
@@ -336,7 +336,7 @@ private void WriteApplicationExtensions(Stream stream, int frameCount, ushort re
// Application Extension: XMP Profile.
if (xmpProfile != null)
{
- GifXmpApplicationExtension xmpExtension = new(xmpProfile.Data);
+ GifXmpApplicationExtension xmpExtension = new(xmpProfile.Data!);
this.WriteExtension(xmpExtension, stream);
}
}
@@ -425,7 +425,7 @@ private void WriteGraphicalControlExtension(GifFrameMetadata metadata, int trans
private void WriteExtension(TGifExtension extension, Stream stream)
where TGifExtension : struct, IGifExtension
{
- IMemoryOwner owner = null;
+ IMemoryOwner? owner = null;
Span extensionBuffer;
int extensionSize = extension.ContentLength;
diff --git a/src/ImageSharp/Formats/Gif/GifImageFormatDetector.cs b/src/ImageSharp/Formats/Gif/GifImageFormatDetector.cs
index 3f657610c9..db3d429046 100644
--- a/src/ImageSharp/Formats/Gif/GifImageFormatDetector.cs
+++ b/src/ImageSharp/Formats/Gif/GifImageFormatDetector.cs
@@ -12,7 +12,7 @@ public sealed class GifImageFormatDetector : IImageFormatDetector
public int HeaderSize => 6;
///
- public IImageFormat DetectFormat(ReadOnlySpan header)
+ public IImageFormat? DetectFormat(ReadOnlySpan header)
{
return this.IsSupportedFileFormat(header) ? GifFormat.Instance : null;
}
diff --git a/src/ImageSharp/Formats/IImageDecoderInternals.cs b/src/ImageSharp/Formats/IImageDecoderInternals.cs
index d8cb1c6627..3f9e63992f 100644
--- a/src/ImageSharp/Formats/IImageDecoderInternals.cs
+++ b/src/ImageSharp/Formats/IImageDecoderInternals.cs
@@ -19,7 +19,7 @@ internal interface IImageDecoderInternals
///
/// Gets the dimensions of the image being decoded.
///
- Size Dimensions { get; }
+ Size? Dimensions { get; }
///
/// Decodes the image from the specified stream.
diff --git a/src/ImageSharp/Formats/IImageFormatDetector.cs b/src/ImageSharp/Formats/IImageFormatDetector.cs
index 17f565d2b2..e1bdc41f8f 100644
--- a/src/ImageSharp/Formats/IImageFormatDetector.cs
+++ b/src/ImageSharp/Formats/IImageFormatDetector.cs
@@ -19,5 +19,5 @@ public interface IImageFormatDetector
///
/// The containing the file header.
/// returns the mime type of detected otherwise returns null
- IImageFormat DetectFormat(ReadOnlySpan header);
+ IImageFormat? DetectFormat(ReadOnlySpan header);
}
diff --git a/src/ImageSharp/Formats/ImageDecoderUtilities.cs b/src/ImageSharp/Formats/ImageDecoderUtilities.cs
index 42f15cf976..4b352a078d 100644
--- a/src/ImageSharp/Formats/ImageDecoderUtilities.cs
+++ b/src/ImageSharp/Formats/ImageDecoderUtilities.cs
@@ -25,7 +25,7 @@ public static void Resize(DecoderOptions options, Image image)
{
ResizeOptions resizeOptions = new()
{
- Size = options.TargetSize.Value,
+ Size = options.TargetSize!.Value,
Sampler = options.Sampler,
Mode = ResizeMode.Max
};
@@ -66,7 +66,7 @@ internal static IImageInfo Identify(
}
catch (InvalidMemoryOperationException ex)
{
- throw new InvalidImageContentException(decoder.Dimensions, ex);
+ throw new InvalidImageContentException(decoder.Dimensions!.Value, ex);
}
}
@@ -94,7 +94,7 @@ internal static Image Decode(
}
catch (InvalidMemoryOperationException ex)
{
- throw largeImageExceptionFactory(ex, decoder.Dimensions);
+ throw largeImageExceptionFactory(ex, decoder.Dimensions!.Value);
}
}
diff --git a/src/ImageSharp/Formats/ImageFormatManager.cs b/src/ImageSharp/Formats/ImageFormatManager.cs
index 9f22c62294..640bff30f2 100644
--- a/src/ImageSharp/Formats/ImageFormatManager.cs
+++ b/src/ImageSharp/Formats/ImageFormatManager.cs
@@ -92,7 +92,7 @@ public void AddImageFormat(IImageFormat format)
///
/// The extension to discover
/// The if found otherwise null
- public IImageFormat FindFormatByFileExtension(string extension)
+ public IImageFormat? FindFormatByFileExtension(string extension)
{
Guard.NotNullOrWhiteSpace(extension, nameof(extension));
@@ -109,7 +109,7 @@ public IImageFormat FindFormatByFileExtension(string extension)
///
/// The mime-type to discover
/// The if found; otherwise null
- public IImageFormat FindFormatByMimeType(string mimeType)
+ public IImageFormat? FindFormatByMimeType(string mimeType)
=> this.imageFormats.FirstOrDefault(x => x.MimeTypes.Contains(mimeType, StringComparer.OrdinalIgnoreCase));
///
@@ -159,11 +159,11 @@ public void AddImageFormatDetector(IImageFormatDetector detector)
///
/// The format to discover
/// The if found otherwise null
- public IImageDecoder FindDecoder(IImageFormat format)
+ public IImageDecoder? FindDecoder(IImageFormat format)
{
Guard.NotNull(format, nameof(format));
- return this.mimeTypeDecoders.TryGetValue(format, out IImageDecoder decoder)
+ return this.mimeTypeDecoders.TryGetValue(format, out IImageDecoder? decoder)
? decoder
: null;
}
@@ -173,11 +173,11 @@ public IImageDecoder FindDecoder(IImageFormat format)
///
/// The format to discover
/// The if found otherwise null
- public IImageEncoder FindEncoder(IImageFormat format)
+ public IImageEncoder? FindEncoder(IImageFormat format)
{
Guard.NotNull(format, nameof(format));
- return this.mimeTypeEncoders.TryGetValue(format, out IImageEncoder encoder)
+ return this.mimeTypeEncoders.TryGetValue(format, out IImageEncoder? encoder)
? encoder
: null;
}
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs
index 3023a01c9c..e25ddf42c9 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs
@@ -470,7 +470,7 @@ public bool Equals(Block8x8F other)
&& this.V7R == other.V7R;
///
- public override bool Equals(object obj) => this.Equals((Block8x8F)obj);
+ public override bool Equals(object? obj) => obj is not null && this.Equals((Block8x8F)obj);
///
public override int GetHashCode()
diff --git a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterBase.cs b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterBase.cs
index f0aa2c321d..639a36aedd 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterBase.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterBase.cs
@@ -71,7 +71,7 @@ protected JpegColorConverterBase(JpegColorSpace colorSpace, int precision)
/// Invalid colorspace.
public static JpegColorConverterBase GetConverter(JpegColorSpace colorSpace, int precision)
{
- JpegColorConverterBase converter = Array.Find(
+ JpegColorConverterBase? converter = Array.Find(
Converters,
c => c.ColorSpace == colorSpace
&& c.Precision == precision);
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/AdobeMarker.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/AdobeMarker.cs
index b3463b5169..c9ee55cd77 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/AdobeMarker.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/AdobeMarker.cs
@@ -89,7 +89,7 @@ public bool Equals(AdobeMarker other)
}
///
- public override bool Equals(object obj)
+ public override bool Equals(object? obj)
{
return obj is AdobeMarker other && this.Equals(other);
}
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ArithmeticDecodingComponent.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ArithmeticDecodingComponent.cs
index 869b9ae01b..76812a3baa 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ArithmeticDecodingComponent.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ArithmeticDecodingComponent.cs
@@ -20,10 +20,10 @@ public ArithmeticDecodingComponent(MemoryAllocator memoryAllocator, JpegFrame fr
///
/// Gets or sets the dc statistics.
///
- public ArithmeticStatistics DcStatistics { get; set; }
+ public ArithmeticStatistics? DcStatistics { get; set; }
///
/// Gets or sets the ac statistics.
///
- public ArithmeticStatistics AcStatistics { get; set; }
+ public ArithmeticStatistics? AcStatistics { get; set; }
}
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ArithmeticScanDecoder.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ArithmeticScanDecoder.cs
index a62efa8125..182b96b1db 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ArithmeticScanDecoder.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ArithmeticScanDecoder.cs
@@ -22,12 +22,12 @@ internal class ArithmeticScanDecoder : IJpegScanDecoder
///
/// instance containing decoding-related information.
///
- private JpegFrame frame;
+ private JpegFrame? frame;
///
/// Shortcut for .Components.
///
- private IJpegComponent[] components;
+ private IJpegComponent[]? components;
///
/// Number of component in the current scan.
@@ -44,13 +44,13 @@ internal class ArithmeticScanDecoder : IJpegScanDecoder
///
private int todo;
- private readonly SpectralConverter spectralConverter;
+ private readonly SpectralConverter? spectralConverter;
private JpegBitReader scanBuffer;
- private ArithmeticDecodingTable[] dcDecodingTables;
+ private ArithmeticDecodingTable?[]? dcDecodingTables;
- private ArithmeticDecodingTable[] acDecodingTables;
+ private ArithmeticDecodingTable?[]? acDecodingTables;
private readonly byte[] fixedBin = { 113, 0, 0, 0 };
@@ -185,7 +185,7 @@ internal class ArithmeticScanDecoder : IJpegScanDecoder
/// The input stream.
/// Spectral to pixel converter.
/// The token to monitor cancellation.
- public ArithmeticScanDecoder(BufferedReadStream stream, SpectralConverter converter, CancellationToken cancellationToken)
+ public ArithmeticScanDecoder(BufferedReadStream stream, SpectralConverter? converter, CancellationToken cancellationToken)
{
this.stream = stream;
this.spectralConverter = converter;
@@ -220,9 +220,14 @@ public int ResetInterval
public void InitDecodingTables(List arithmeticDecodingTables)
{
- for (int i = 0; i < this.components.Length; i++)
+ for (int i = 0; i < this.components?.Length; i++)
{
- ArithmeticDecodingComponent component = this.components[i] as ArithmeticDecodingComponent;
+ ArithmeticDecodingComponent? component = this.components[i] as ArithmeticDecodingComponent;
+
+ ArgumentNullException.ThrowIfNull(component);
+ ArgumentNullException.ThrowIfNull(this.dcDecodingTables);
+ ArgumentNullException.ThrowIfNull(this.acDecodingTables);
+
this.dcDecodingTables[i] = GetArithmeticTable(arithmeticDecodingTables, true, component.DcTableId);
component.DcStatistics = this.CreateOrGetStatisticsBin(true, component.DcTableId);
this.acDecodingTables[i] = GetArithmeticTable(arithmeticDecodingTables, false, component.AcTableId);
@@ -244,6 +249,7 @@ public void ParseEntropyCodedData(int scanComponentCount)
this.scanBuffer = new JpegBitReader(this.stream);
+ ArgumentNullException.ThrowIfNull(this.frame);
this.frame.AllocateComponents();
if (this.frame.Progressive)
@@ -267,13 +273,15 @@ public void InjectFrameData(JpegFrame frame, IRawJpegData jpegData)
this.frame = frame;
this.components = frame.Components;
+ ArgumentNullException.ThrowIfNull(this.components);
+
this.dcDecodingTables = new ArithmeticDecodingTable[this.components.Length];
this.acDecodingTables = new ArithmeticDecodingTable[this.components.Length];
- this.spectralConverter.InjectFrameData(frame, jpegData);
+ this.spectralConverter?.InjectFrameData(frame, jpegData);
}
- private static ArithmeticDecodingTable GetArithmeticTable(List arithmeticDecodingTables, bool isDcTable, int identifier)
+ private static ArithmeticDecodingTable? GetArithmeticTable(List arithmeticDecodingTables, bool isDcTable, int identifier)
{
int tableClass = isDcTable ? 0 : 1;
@@ -310,7 +318,7 @@ private ArithmeticStatistics CreateOrGetStatisticsBin(bool dc, int identifier, b
private void ParseBaselineData()
{
- for (int i = 0; i < this.components.Length; i++)
+ for (int i = 0; i < this.components?.Length; i++)
{
ArithmeticDecodingComponent component = (ArithmeticDecodingComponent)this.components[i];
component.DcPredictor = 0;
@@ -323,15 +331,19 @@ private void ParseBaselineData()
if (this.scanComponentCount != 1)
{
- this.spectralConverter.PrepareForDecoding();
+ this.spectralConverter?.PrepareForDecoding();
this.ParseBaselineDataInterleaved();
- this.spectralConverter.CommitConversion();
+ this.spectralConverter?.CommitConversion();
+ }
+ else if (this.frame is null)
+ {
+ ArgumentNullException.ThrowIfNull(this.frame);
}
else if (this.frame.ComponentCount == 1)
{
- this.spectralConverter.PrepareForDecoding();
+ this.spectralConverter?.PrepareForDecoding();
this.ParseBaselineDataSingleComponent();
- this.spectralConverter.CommitConversion();
+ this.spectralConverter?.CommitConversion();
}
else
{
@@ -343,7 +355,7 @@ private void ParseProgressiveData()
{
this.CheckProgressiveData();
- foreach (ArithmeticDecodingComponent component in this.components)
+ foreach (ArithmeticDecodingComponent component in this.components!)
{
if (this.SpectralStart == 0 && this.SuccessiveHigh == 0)
{
@@ -423,6 +435,7 @@ private void CheckProgressiveData()
private void ParseBaselineDataInterleaved()
{
int mcu = 0;
+ ArgumentNullException.ThrowIfNull(this.frame);
int mcusPerColumn = this.frame.McusPerColumn;
int mcusPerLine = this.frame.McusPerLine;
ref JpegBitReader reader = ref this.scanBuffer;
@@ -438,11 +451,16 @@ private void ParseBaselineDataInterleaved()
int mcuCol = mcu % mcusPerLine;
for (int k = 0; k < this.scanComponentCount; k++)
{
+ ArgumentNullException.ThrowIfNull(this.frame.ComponentOrder);
int order = this.frame.ComponentOrder[k];
- ArithmeticDecodingComponent component = this.components[order] as ArithmeticDecodingComponent;
+ ArithmeticDecodingComponent? component = this.components?[order] as ArithmeticDecodingComponent;
+
+ ArgumentNullException.ThrowIfNull(component);
+ ArgumentNullException.ThrowIfNull(this.dcDecodingTables);
+ ArgumentNullException.ThrowIfNull(this.acDecodingTables);
- ref ArithmeticDecodingTable dcDecodingTable = ref this.dcDecodingTables[component.DcTableId];
- ref ArithmeticDecodingTable acDecodingTable = ref this.acDecodingTables[component.AcTableId];
+ ref ArithmeticDecodingTable? dcDecodingTable = ref this.dcDecodingTables[component.DcTableId];
+ ref ArithmeticDecodingTable? acDecodingTable = ref this.acDecodingTables[component.AcTableId];
int h = component.HorizontalSamplingFactor;
int v = component.VerticalSamplingFactor;
@@ -452,7 +470,7 @@ private void ParseBaselineDataInterleaved()
int mcuColMulh = mcuCol * h;
for (int y = 0; y < v; y++)
{
- Span blockSpan = component.SpectralBlocks.DangerousGetRowSpan(y);
+ Span blockSpan = component.SpectralBlocks!.DangerousGetRowSpan(y);
ref Block8x8 blockRef = ref MemoryMarshal.GetReference(blockSpan);
for (int x = 0; x < h; x++)
@@ -461,7 +479,7 @@ private void ParseBaselineDataInterleaved()
{
// It is very likely that some spectral data was decoded before we've encountered 'end of scan'
// so we need to decode what's left and return (or maybe throw?)
- this.spectralConverter.ConvertStrideBaseline();
+ this.spectralConverter?.ConvertStrideBaseline();
return;
}
@@ -483,18 +501,24 @@ ref Unsafe.Add(ref blockRef, (nint)(uint)blockCol),
}
// Convert from spectral to actual pixels via given converter.
- this.spectralConverter.ConvertStrideBaseline();
+ this.spectralConverter?.ConvertStrideBaseline();
}
}
private void ParseBaselineDataSingleComponent()
{
- ArithmeticDecodingComponent component = this.frame.Components[0] as ArithmeticDecodingComponent;
+ ArgumentNullException.ThrowIfNull(this.frame);
+ ArithmeticDecodingComponent? component = this.frame.Components?[0] as ArithmeticDecodingComponent;
+
+ ArgumentNullException.ThrowIfNull(component);
+ ArgumentNullException.ThrowIfNull(this.dcDecodingTables);
+ ArgumentNullException.ThrowIfNull(this.acDecodingTables);
+
int mcuLines = this.frame.McusPerColumn;
int w = component.WidthInBlocks;
int h = component.SamplingFactors.Height;
- ref ArithmeticDecodingTable dcDecodingTable = ref this.dcDecodingTables[component.DcTableId];
- ref ArithmeticDecodingTable acDecodingTable = ref this.acDecodingTables[component.AcTableId];
+ ref ArithmeticDecodingTable? dcDecodingTable = ref this.dcDecodingTables[component.DcTableId];
+ ref ArithmeticDecodingTable? acDecodingTable = ref this.acDecodingTables[component.AcTableId];
ref JpegBitReader reader = ref this.scanBuffer;
@@ -505,7 +529,7 @@ private void ParseBaselineDataSingleComponent()
// Decode from binary to spectral.
for (int j = 0; j < h; j++)
{
- Span blockSpan = component.SpectralBlocks.DangerousGetRowSpan(j);
+ Span blockSpan = component.SpectralBlocks!.DangerousGetRowSpan(j);
ref Block8x8 blockRef = ref MemoryMarshal.GetReference(blockSpan);
for (int k = 0; k < w; k++)
@@ -514,7 +538,7 @@ private void ParseBaselineDataSingleComponent()
{
// It is very likely that some spectral data was decoded before we've encountered 'end of scan'
// so we need to decode what's left and return (or maybe throw?)
- this.spectralConverter.ConvertStrideBaseline();
+ this.spectralConverter?.ConvertStrideBaseline();
return;
}
@@ -529,25 +553,31 @@ ref Unsafe.Add(ref blockRef, (nint)(uint)k),
}
// Convert from spectral to actual pixels via given converter.
- this.spectralConverter.ConvertStrideBaseline();
+ this.spectralConverter?.ConvertStrideBaseline();
}
}
private void ParseBaselineDataNonInterleaved()
{
- ArithmeticDecodingComponent component = (ArithmeticDecodingComponent)this.components[this.frame.ComponentOrder[0]];
+ ArgumentNullException.ThrowIfNull(this.frame);
+ ArgumentNullException.ThrowIfNull(this.frame.ComponentOrder);
+ ArithmeticDecodingComponent? component = (ArithmeticDecodingComponent?)this.components?[this.frame.ComponentOrder[0]];
ref JpegBitReader reader = ref this.scanBuffer;
+ ArgumentNullException.ThrowIfNull(component);
+ ArgumentNullException.ThrowIfNull(this.dcDecodingTables);
+ ArgumentNullException.ThrowIfNull(this.acDecodingTables);
+
int w = component.WidthInBlocks;
int h = component.HeightInBlocks;
- ref ArithmeticDecodingTable dcDecodingTable = ref this.dcDecodingTables[component.DcTableId];
- ref ArithmeticDecodingTable acDecodingTable = ref this.acDecodingTables[component.AcTableId];
+ ref ArithmeticDecodingTable? dcDecodingTable = ref this.dcDecodingTables[component.DcTableId];
+ ref ArithmeticDecodingTable? acDecodingTable = ref this.acDecodingTables[component.AcTableId];
for (int j = 0; j < h; j++)
{
this.cancellationToken.ThrowIfCancellationRequested();
- Span blockSpan = component.SpectralBlocks.DangerousGetRowSpan(j);
+ Span blockSpan = component.SpectralBlocks!.DangerousGetRowSpan(j);
ref Block8x8 blockRef = ref MemoryMarshal.GetReference(blockSpan);
for (int i = 0; i < w; i++)
@@ -571,6 +601,7 @@ ref Unsafe.Add(ref blockRef, (nint)(uint)i),
private void ParseProgressiveDataInterleaved()
{
int mcu = 0;
+ ArgumentNullException.ThrowIfNull(this.frame);
int mcusPerColumn = this.frame.McusPerColumn;
int mcusPerLine = this.frame.McusPerLine;
ref JpegBitReader reader = ref this.scanBuffer;
@@ -583,9 +614,14 @@ private void ParseProgressiveDataInterleaved()
int mcuRow = Math.DivRem(mcu, mcusPerLine, out int mcuCol);
for (int k = 0; k < this.scanComponentCount; k++)
{
+ ArgumentNullException.ThrowIfNull(this.frame.ComponentOrder);
int order = this.frame.ComponentOrder[k];
- ArithmeticDecodingComponent component = this.components[order] as ArithmeticDecodingComponent;
- ref ArithmeticDecodingTable dcDecodingTable = ref this.dcDecodingTables[component.DcTableId];
+ ArithmeticDecodingComponent? component = this.components?[order] as ArithmeticDecodingComponent;
+
+ ArgumentNullException.ThrowIfNull(component);
+ ArgumentNullException.ThrowIfNull(this.dcDecodingTables);
+
+ ref ArithmeticDecodingTable? dcDecodingTable = ref this.dcDecodingTables[component.DcTableId];
int h = component.HorizontalSamplingFactor;
int v = component.VerticalSamplingFactor;
@@ -596,7 +632,7 @@ private void ParseProgressiveDataInterleaved()
for (int y = 0; y < v; y++)
{
int blockRow = (mcuRow * v) + y;
- Span blockSpan = component.SpectralBlocks.DangerousGetRowSpan(blockRow);
+ Span blockSpan = component.SpectralBlocks!.DangerousGetRowSpan(blockRow);
ref Block8x8 blockRef = ref MemoryMarshal.GetReference(blockSpan);
for (int x = 0; x < h; x++)
@@ -626,21 +662,26 @@ ref Unsafe.Add(ref blockRef, (nint)(uint)blockCol),
private void ParseProgressiveDataNonInterleaved()
{
- ArithmeticDecodingComponent component = this.components[this.frame.ComponentOrder[0]] as ArithmeticDecodingComponent;
+ ArgumentNullException.ThrowIfNull(this.frame);
+ ArgumentNullException.ThrowIfNull(this.frame.ComponentOrder);
+ ArithmeticDecodingComponent? component = this.components?[this.frame.ComponentOrder[0]] as ArithmeticDecodingComponent;
ref JpegBitReader reader = ref this.scanBuffer;
+ ArgumentNullException.ThrowIfNull(component);
+
int w = component.WidthInBlocks;
int h = component.HeightInBlocks;
if (this.SpectralStart == 0)
{
- ref ArithmeticDecodingTable dcDecodingTable = ref this.dcDecodingTables[component.DcTableId];
+ ArgumentNullException.ThrowIfNull(this.dcDecodingTables);
+ ref ArithmeticDecodingTable? dcDecodingTable = ref this.dcDecodingTables[component.DcTableId];
for (int j = 0; j < h; j++)
{
this.cancellationToken.ThrowIfCancellationRequested();
- Span blockSpan = component.SpectralBlocks.DangerousGetRowSpan(j);
+ Span blockSpan = component.SpectralBlocks!.DangerousGetRowSpan(j);
ref Block8x8 blockRef = ref MemoryMarshal.GetReference(blockSpan);
for (int i = 0; i < w; i++)
@@ -661,13 +702,14 @@ ref Unsafe.Add(ref blockRef, (nint)(uint)i),
}
else
{
- ref ArithmeticDecodingTable acDecodingTable = ref this.acDecodingTables[component.AcTableId];
+ ArgumentNullException.ThrowIfNull(this.acDecodingTables);
+ ref ArithmeticDecodingTable? acDecodingTable = ref this.acDecodingTables[component.AcTableId];
for (int j = 0; j < h; j++)
{
this.cancellationToken.ThrowIfCancellationRequested();
- Span blockSpan = component.SpectralBlocks.DangerousGetRowSpan(j);
+ Span blockSpan = component.SpectralBlocks!.DangerousGetRowSpan(j);
ref Block8x8 blockRef = ref MemoryMarshal.GetReference(blockSpan);
for (int i = 0; i < w; i++)
@@ -688,7 +730,7 @@ ref Unsafe.Add(ref blockRef, (nint)(uint)i),
}
}
- private void DecodeBlockProgressiveDc(ArithmeticDecodingComponent component, ref Block8x8 block, ref ArithmeticDecodingTable dcTable)
+ private void DecodeBlockProgressiveDc(ArithmeticDecodingComponent component, ref Block8x8 block, ref ArithmeticDecodingTable? dcTable)
{
if (dcTable == null)
{
@@ -704,7 +746,7 @@ private void DecodeBlockProgressiveDc(ArithmeticDecodingComponent component, ref
// Sections F.2.4.1 & F.1.4.4.1: Decoding of DC coefficients.
// Table F.4: Point to statistics bin S0 for DC coefficient coding.
- ref byte st = ref Unsafe.Add(ref component.DcStatistics.GetReference(), component.DcContext);
+ ref byte st = ref Unsafe.Add(ref component.DcStatistics!.GetReference(), component.DcContext);
// Figure F.19: Decode_DC_DIFF
if (this.DecodeBinaryDecision(ref reader, ref st) == 0)
@@ -735,7 +777,7 @@ private void DecodeBlockProgressiveDc(ArithmeticDecodingComponent component, ref
}
// Section F.1.4.4.1.2: Establish dc_context conditioning category.
- if (m < (int)((1L << dcTable.DcL) >> 1))
+ if (m < (int)((1L << dcTable!.DcL) >> 1))
{
component.DcContext = 0; // Zero diff category.
}
@@ -780,12 +822,12 @@ private void DecodeBlockProgressiveDc(ArithmeticDecodingComponent component, ref
}
}
- private void DecodeBlockProgressiveAc(ArithmeticDecodingComponent component, ref Block8x8 block, ref ArithmeticDecodingTable acTable)
+ private void DecodeBlockProgressiveAc(ArithmeticDecodingComponent component, ref Block8x8 block, ref ArithmeticDecodingTable? acTable)
{
ref JpegBitReader reader = ref this.scanBuffer;
ref short blockDataRef = ref Unsafe.As(ref block);
- ArithmeticStatistics acStatistics = component.AcStatistics;
+ ArithmeticStatistics? acStatistics = component.AcStatistics;
if (acStatistics == null || acTable == null)
{
JpegThrowHelper.ThrowInvalidImageContentException("AC table is missing");
@@ -802,7 +844,7 @@ private void DecodeBlockProgressiveAc(ArithmeticDecodingComponent component, ref
for (int k = start; k <= end; k++)
{
- ref byte st = ref acStatistics.GetReference(3 * (k - 1));
+ ref byte st = ref acStatistics!.GetReference(3 * (k - 1));
if (this.DecodeBinaryDecision(ref reader, ref st) != 0)
{
break;
@@ -830,7 +872,7 @@ private void DecodeBlockProgressiveAc(ArithmeticDecodingComponent component, ref
if (this.DecodeBinaryDecision(ref reader, ref st) != 0)
{
m <<= 1;
- st = ref acStatistics.GetReference(k <= acTable.AcKx ? 189 : 217);
+ st = ref acStatistics.GetReference(k <= acTable!.AcKx ? 189 : 217);
while (this.DecodeBinaryDecision(ref reader, ref st) != 0)
{
if ((m <<= 1) == 0x8000)
@@ -871,7 +913,7 @@ private void DecodeBlockProgressiveAc(ArithmeticDecodingComponent component, ref
}
}
- private void ReadBlockProgressiveAcRefined(ArithmeticStatistics acStatistics, ref short blockDataRef)
+ private void ReadBlockProgressiveAcRefined(ArithmeticStatistics? acStatistics, ref short blockDataRef)
{
ref JpegBitReader reader = ref this.scanBuffer;
int start = this.SpectralStart;
@@ -892,7 +934,7 @@ private void ReadBlockProgressiveAcRefined(ArithmeticStatistics acStatistics, re
for (int k = start; k <= end; k++)
{
- ref byte st = ref acStatistics.GetReference(3 * (k - 1));
+ ref byte st = ref acStatistics!.GetReference(3 * (k - 1));
if (k > kex)
{
if (this.DecodeBinaryDecision(ref reader, ref st) != 0)
@@ -935,8 +977,8 @@ private void ReadBlockProgressiveAcRefined(ArithmeticStatistics acStatistics, re
private void DecodeBlockBaseline(
ArithmeticDecodingComponent component,
ref Block8x8 destinationBlock,
- ref ArithmeticDecodingTable acTable,
- ref ArithmeticDecodingTable dcTable)
+ ref ArithmeticDecodingTable? acTable,
+ ref ArithmeticDecodingTable? dcTable)
{
if (acTable is null)
{
@@ -954,7 +996,7 @@ private void DecodeBlockBaseline(
// Sections F.2.4.1 & F.1.4.4.1: Decoding of DC coefficients.
// Table F.4: Point to statistics bin S0 for DC coefficient coding.
- ref byte st = ref Unsafe.Add(ref component.DcStatistics.GetReference(), component.DcContext);
+ ref byte st = ref Unsafe.Add(ref component.DcStatistics!.GetReference(), component.DcContext);
/* Figure F.19: Decode_DC_DIFF */
if (this.DecodeBinaryDecision(ref reader, ref st) == 0)
@@ -986,7 +1028,7 @@ private void DecodeBlockBaseline(
}
// Section F.1.4.4.1.2: Establish dc_context conditioning category.
- if (m < (int)((1L << dcTable.DcL) >> 1))
+ if (m < (int)((1L << dcTable!.DcL) >> 1))
{
component.DcContext = 0; // zero diff category
}
@@ -1023,11 +1065,11 @@ private void DecodeBlockBaseline(
destinationRef = (short)component.DcPredictor;
// Sections F.2.4.2 & F.1.4.4.2: Decoding of AC coefficients.
- ArithmeticStatistics acStatistics = component.AcStatistics;
+ ArithmeticStatistics? acStatistics = component.AcStatistics;
for (int k = 1; k <= 63; k++)
{
- st = ref acStatistics.GetReference(3 * (k - 1));
+ st = ref acStatistics!.GetReference(3 * (k - 1));
if (this.DecodeBinaryDecision(ref reader, ref st) != 0)
{
// EOB flag.
@@ -1056,7 +1098,7 @@ private void DecodeBlockBaseline(
if (this.DecodeBinaryDecision(ref reader, ref st) != 0)
{
m <<= 1;
- st = ref acStatistics.GetReference(k <= acTable.AcKx ? 189 : 217);
+ st = ref acStatistics.GetReference(k <= acTable!.AcKx ? 189 : 217);
while (this.DecodeBinaryDecision(ref reader, ref st) != 0)
{
if ((m <<= 1) == 0x8000)
@@ -1106,7 +1148,7 @@ private bool HandleRestart()
this.todo = this.restartInterval;
- foreach (ArithmeticDecodingComponent component in this.components)
+ foreach (ArithmeticDecodingComponent component in this.components!)
{
component.DcPredictor = 0;
component.DcContext = 0;
@@ -1136,9 +1178,12 @@ private bool HandleRestart()
[MethodImpl(InliningOptions.ShortMethod)]
private void Reset()
{
- for (int i = 0; i < this.components.Length; i++)
+ for (int i = 0; i < this.components?.Length; i++)
{
- ArithmeticDecodingComponent component = this.components[i] as ArithmeticDecodingComponent;
+ ArithmeticDecodingComponent? component = this.components[i] as ArithmeticDecodingComponent;
+
+ ArgumentNullException.ThrowIfNull(component);
+
component.DcPredictor = 0;
}
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ComponentProcessors/ComponentProcessor.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ComponentProcessors/ComponentProcessor.cs
index f0cc4d5e82..fdbbf5beb8 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ComponentProcessors/ComponentProcessor.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ComponentProcessors/ComponentProcessor.cs
@@ -44,7 +44,7 @@ public ComponentProcessor(MemoryAllocator memoryAllocator, JpegFrame frame, Size
///
public void ClearSpectralBuffers()
{
- Buffer2D spectralBlocks = this.Component.SpectralBlocks;
+ Buffer2D spectralBlocks = this.Component.SpectralBlocks!;
for (int i = 0; i < spectralBlocks.Height; i++)
{
spectralBlocks.DangerousGetRowSpan(i).Clear();
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ComponentProcessors/DirectComponentProcessor.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ComponentProcessors/DirectComponentProcessor.cs
index 79e25a67a9..bfa6b9a6a7 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ComponentProcessors/DirectComponentProcessor.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ComponentProcessors/DirectComponentProcessor.cs
@@ -15,13 +15,15 @@ internal sealed class DirectComponentProcessor : ComponentProcessor
public DirectComponentProcessor(MemoryAllocator memoryAllocator, JpegFrame frame, IRawJpegData rawJpeg, Size postProcessorBufferSize, IJpegComponent component)
: base(memoryAllocator, frame, postProcessorBufferSize, component, blockSize: 8)
{
+ ArgumentNullException.ThrowIfNull(rawJpeg.QuantizationTables);
+
this.dequantizationTable = rawJpeg.QuantizationTables[component.QuantizationTableIndex];
FloatingPointDCT.AdjustToIDCT(ref this.dequantizationTable);
}
public override void CopyBlocksToColorBuffer(int spectralStep)
{
- Buffer2D spectralBuffer = this.Component.SpectralBlocks;
+ Buffer2D spectralBuffer = this.Component.SpectralBlocks!;
float maximumValue = this.Frame.MaxColorChannelValue;
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ComponentProcessors/DownScalingComponentProcessor2.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ComponentProcessors/DownScalingComponentProcessor2.cs
index 51d8d03593..fc84abc31c 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ComponentProcessors/DownScalingComponentProcessor2.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ComponentProcessors/DownScalingComponentProcessor2.cs
@@ -16,13 +16,15 @@ internal sealed class DownScalingComponentProcessor2 : ComponentProcessor
public DownScalingComponentProcessor2(MemoryAllocator memoryAllocator, JpegFrame frame, IRawJpegData rawJpeg, Size postProcessorBufferSize, IJpegComponent component)
: base(memoryAllocator, frame, postProcessorBufferSize, component, 4)
{
+ ArgumentNullException.ThrowIfNull(rawJpeg.QuantizationTables);
+
this.dequantizationTable = rawJpeg.QuantizationTables[component.QuantizationTableIndex];
ScaledFloatingPointDCT.AdjustToIDCT(ref this.dequantizationTable);
}
public override void CopyBlocksToColorBuffer(int spectralStep)
{
- Buffer2D spectralBuffer = this.Component.SpectralBlocks;
+ Buffer2D? spectralBuffer = this.Component.SpectralBlocks;
float maximumValue = this.Frame.MaxColorChannelValue;
float normalizationValue = MathF.Ceiling(maximumValue / 2);
@@ -41,7 +43,7 @@ public override void CopyBlocksToColorBuffer(int spectralStep)
int yBuffer = y * this.BlockAreaSize.Height;
Span colorBufferRow = this.ColorBuffer.DangerousGetRowSpan(yBuffer);
- Span blockRow = spectralBuffer.DangerousGetRowSpan(yBlockStart + y);
+ Span blockRow = spectralBuffer!.DangerousGetRowSpan(yBlockStart + y);
for (int xBlock = 0; xBlock < spectralBuffer.Width; xBlock++)
{
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ComponentProcessors/DownScalingComponentProcessor4.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ComponentProcessors/DownScalingComponentProcessor4.cs
index b8a40f53b1..80e70e8bec 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ComponentProcessors/DownScalingComponentProcessor4.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ComponentProcessors/DownScalingComponentProcessor4.cs
@@ -16,13 +16,15 @@ internal sealed class DownScalingComponentProcessor4 : ComponentProcessor
public DownScalingComponentProcessor4(MemoryAllocator memoryAllocator, JpegFrame frame, IRawJpegData rawJpeg, Size postProcessorBufferSize, IJpegComponent component)
: base(memoryAllocator, frame, postProcessorBufferSize, component, 2)
{
+ ArgumentNullException.ThrowIfNull(rawJpeg.QuantizationTables);
+
this.dequantizationTable = rawJpeg.QuantizationTables[component.QuantizationTableIndex];
ScaledFloatingPointDCT.AdjustToIDCT(ref this.dequantizationTable);
}
public override void CopyBlocksToColorBuffer(int spectralStep)
{
- Buffer2D spectralBuffer = this.Component.SpectralBlocks;
+ Buffer2D? spectralBuffer = this.Component.SpectralBlocks;
float maximumValue = this.Frame.MaxColorChannelValue;
float normalizationValue = MathF.Ceiling(maximumValue / 2);
@@ -41,7 +43,7 @@ public override void CopyBlocksToColorBuffer(int spectralStep)
int yBuffer = y * this.BlockAreaSize.Height;
Span colorBufferRow = this.ColorBuffer.DangerousGetRowSpan(yBuffer);
- Span blockRow = spectralBuffer.DangerousGetRowSpan(yBlockStart + y);
+ Span blockRow = spectralBuffer!.DangerousGetRowSpan(yBlockStart + y);
for (int xBlock = 0; xBlock < spectralBuffer.Width; xBlock++)
{
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ComponentProcessors/DownScalingComponentProcessor8.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ComponentProcessors/DownScalingComponentProcessor8.cs
index 121b745465..7f313613e0 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ComponentProcessors/DownScalingComponentProcessor8.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ComponentProcessors/DownScalingComponentProcessor8.cs
@@ -15,11 +15,14 @@ internal sealed class DownScalingComponentProcessor8 : ComponentProcessor
public DownScalingComponentProcessor8(MemoryAllocator memoryAllocator, JpegFrame frame, IRawJpegData rawJpeg, Size postProcessorBufferSize, IJpegComponent component)
: base(memoryAllocator, frame, postProcessorBufferSize, component, 1)
- => this.dcDequantizatizer = 0.125f * rawJpeg.QuantizationTables[component.QuantizationTableIndex][0];
+ {
+ ArgumentNullException.ThrowIfNull(rawJpeg.QuantizationTables);
+ this.dcDequantizatizer = 0.125f * rawJpeg.QuantizationTables[component.QuantizationTableIndex][0];
+ }
public override void CopyBlocksToColorBuffer(int spectralStep)
{
- Buffer2D spectralBuffer = this.Component.SpectralBlocks;
+ Buffer2D? spectralBuffer = this.Component.SpectralBlocks;
float maximumValue = this.Frame.MaxColorChannelValue;
float normalizationValue = MathF.Ceiling(maximumValue / 2);
@@ -36,7 +39,7 @@ public override void CopyBlocksToColorBuffer(int spectralStep)
int yBuffer = y * this.BlockAreaSize.Height;
Span colorBufferRow = this.ColorBuffer.DangerousGetRowSpan(yBuffer);
- Span blockRow = spectralBuffer.DangerousGetRowSpan(yBlockStart + y);
+ Span blockRow = spectralBuffer!.DangerousGetRowSpan(yBlockStart + y);
for (int xBlock = 0; xBlock < spectralBuffer.Width; xBlock++)
{
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanDecoder.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanDecoder.cs
index 91abce4d74..07d897ca74 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanDecoder.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanDecoder.cs
@@ -1,6 +1,7 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
+using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.IO;
@@ -19,12 +20,12 @@ internal class HuffmanScanDecoder : IJpegScanDecoder
///
/// instance containing decoding-related information.
///
- private JpegFrame frame;
+ private JpegFrame? frame;
///
/// Shortcut for .Components.
///
- private IJpegComponent[] components;
+ private IJpegComponent[]? components;
///
/// Number of component in the current scan.
@@ -58,7 +59,7 @@ internal class HuffmanScanDecoder : IJpegScanDecoder
private JpegBitReader scanBuffer;
- private readonly SpectralConverter spectralConverter;
+ private readonly SpectralConverter? spectralConverter;
private readonly CancellationToken cancellationToken;
@@ -70,7 +71,7 @@ internal class HuffmanScanDecoder : IJpegScanDecoder
/// The token to monitor cancellation.
public HuffmanScanDecoder(
BufferedReadStream stream,
- SpectralConverter converter,
+ SpectralConverter? converter,
CancellationToken cancellationToken)
{
this.stream = stream;
@@ -116,6 +117,8 @@ public void ParseEntropyCodedData(int scanComponentCount)
this.scanBuffer = new JpegBitReader(this.stream);
+ ArgumentNullException.ThrowIfNull(this.frame);
+
this.frame.AllocateComponents();
if (!this.frame.Progressive)
@@ -134,27 +137,32 @@ public void ParseEntropyCodedData(int scanComponentCount)
}
///
+ [MemberNotNull(nameof(frame))]
public void InjectFrameData(JpegFrame frame, IRawJpegData jpegData)
{
this.frame = frame;
this.components = frame.Components;
- this.spectralConverter.InjectFrameData(frame, jpegData);
+ this.spectralConverter?.InjectFrameData(frame, jpegData);
}
private void ParseBaselineData()
{
if (this.scanComponentCount != 1)
{
- this.spectralConverter.PrepareForDecoding();
+ this.spectralConverter?.PrepareForDecoding();
this.ParseBaselineDataInterleaved();
- this.spectralConverter.CommitConversion();
+ this.spectralConverter?.CommitConversion();
+ }
+ else if (this.frame is null)
+ {
+ ArgumentNullException.ThrowIfNull(this.frame);
}
else if (this.frame.ComponentCount == 1)
{
- this.spectralConverter.PrepareForDecoding();
+ this.spectralConverter?.PrepareForDecoding();
this.ParseBaselineDataSingleComponent();
- this.spectralConverter.CommitConversion();
+ this.spectralConverter?.CommitConversion();
}
else
{
@@ -165,6 +173,8 @@ private void ParseBaselineData()
private void ParseBaselineDataInterleaved()
{
int mcu = 0;
+ ArgumentNullException.ThrowIfNull(this.frame);
+
int mcusPerColumn = this.frame.McusPerColumn;
int mcusPerLine = this.frame.McusPerLine;
ref JpegBitReader buffer = ref this.scanBuffer;
@@ -180,8 +190,11 @@ private void ParseBaselineDataInterleaved()
int mcuCol = mcu % mcusPerLine;
for (int k = 0; k < this.scanComponentCount; k++)
{
+ ArgumentNullException.ThrowIfNull(this.frame.ComponentOrder);
int order = this.frame.ComponentOrder[k];
- var component = this.components[order] as JpegComponent;
+ JpegComponent? component = this.components?[order] as JpegComponent;
+
+ ArgumentNullException.ThrowIfNull(component);
ref HuffmanTable dcHuffmanTable = ref this.dcHuffmanTables[component.DcTableId];
ref HuffmanTable acHuffmanTable = ref this.acHuffmanTables[component.AcTableId];
@@ -193,7 +206,7 @@ private void ParseBaselineDataInterleaved()
// by the basic H and V specified for the component
for (int y = 0; y < v; y++)
{
- Span blockSpan = component.SpectralBlocks.DangerousGetRowSpan(y);
+ Span blockSpan = component.SpectralBlocks!.DangerousGetRowSpan(y);
ref Block8x8 blockRef = ref MemoryMarshal.GetReference(blockSpan);
for (int x = 0; x < h; x++)
@@ -202,7 +215,7 @@ private void ParseBaselineDataInterleaved()
{
// It is very likely that some spectral data was decoded before we've encountered 'end of scan'
// so we need to decode what's left and return (or maybe throw?)
- this.spectralConverter.ConvertStrideBaseline();
+ this.spectralConverter?.ConvertStrideBaseline();
return;
}
@@ -224,15 +237,19 @@ ref Unsafe.Add(ref blockRef, blockCol),
}
// Convert from spectral to actual pixels via given converter
- this.spectralConverter.ConvertStrideBaseline();
+ this.spectralConverter?.ConvertStrideBaseline();
}
}
private void ParseBaselineDataNonInterleaved()
{
- var component = this.components[this.frame.ComponentOrder[0]] as JpegComponent;
+ ArgumentNullException.ThrowIfNull(this.frame);
+ ArgumentNullException.ThrowIfNull(this.frame.ComponentOrder);
+ JpegComponent? component = this.components?[this.frame.ComponentOrder[0]] as JpegComponent;
ref JpegBitReader buffer = ref this.scanBuffer;
+ ArgumentNullException.ThrowIfNull(component);
+
int w = component.WidthInBlocks;
int h = component.HeightInBlocks;
@@ -242,7 +259,7 @@ private void ParseBaselineDataNonInterleaved()
for (int j = 0; j < h; j++)
{
this.cancellationToken.ThrowIfCancellationRequested();
- Span blockSpan = component.SpectralBlocks.DangerousGetRowSpan(j);
+ Span blockSpan = component.SpectralBlocks!.DangerousGetRowSpan(j);
ref Block8x8 blockRef = ref MemoryMarshal.GetReference(blockSpan);
for (int i = 0; i < w; i++)
@@ -265,7 +282,12 @@ ref Unsafe.Add(ref blockRef, i),
private void ParseBaselineDataSingleComponent()
{
- JpegComponent component = this.frame.Components[0];
+ ArgumentNullException.ThrowIfNull(this.frame);
+
+ JpegComponent? component = this.frame.Components?[0];
+
+ ArgumentNullException.ThrowIfNull(component);
+
int mcuLines = this.frame.McusPerColumn;
int w = component.WidthInBlocks;
int h = component.SamplingFactors.Height;
@@ -281,7 +303,7 @@ private void ParseBaselineDataSingleComponent()
// decode from binary to spectral
for (int j = 0; j < h; j++)
{
- Span blockSpan = component.SpectralBlocks.DangerousGetRowSpan(j);
+ Span blockSpan = component.SpectralBlocks!.DangerousGetRowSpan(j);
ref Block8x8 blockRef = ref MemoryMarshal.GetReference(blockSpan);
for (int k = 0; k < w; k++)
@@ -290,7 +312,7 @@ private void ParseBaselineDataSingleComponent()
{
// It is very likely that some spectral data was decoded before we've encountered 'end of scan'
// so we need to decode what's left and return (or maybe throw?)
- this.spectralConverter.ConvertStrideBaseline();
+ this.spectralConverter?.ConvertStrideBaseline();
return;
}
@@ -305,7 +327,7 @@ ref Unsafe.Add(ref blockRef, k),
}
// Convert from spectral to actual pixels via given converter
- this.spectralConverter.ConvertStrideBaseline();
+ this.spectralConverter?.ConvertStrideBaseline();
}
}
@@ -377,6 +399,8 @@ private void ParseProgressiveDataInterleaved()
{
// Interleaved
int mcu = 0;
+ ArgumentNullException.ThrowIfNull(this.frame);
+
int mcusPerColumn = this.frame.McusPerColumn;
int mcusPerLine = this.frame.McusPerLine;
ref JpegBitReader buffer = ref this.scanBuffer;
@@ -390,8 +414,12 @@ private void ParseProgressiveDataInterleaved()
int mcuCol = mcu % mcusPerLine;
for (int k = 0; k < this.scanComponentCount; k++)
{
+ ArgumentNullException.ThrowIfNull(this.frame.ComponentOrder);
int order = this.frame.ComponentOrder[k];
- var component = this.components[order] as JpegComponent;
+ JpegComponent? component = this.components?[order] as JpegComponent;
+
+ ArgumentNullException.ThrowIfNull(component);
+
ref HuffmanTable dcHuffmanTable = ref this.dcHuffmanTables[component.DcTableId];
int h = component.HorizontalSamplingFactor;
@@ -402,7 +430,7 @@ private void ParseProgressiveDataInterleaved()
for (int y = 0; y < v; y++)
{
int blockRow = (mcuRow * v) + y;
- Span blockSpan = component.SpectralBlocks.DangerousGetRowSpan(blockRow);
+ Span blockSpan = component.SpectralBlocks!.DangerousGetRowSpan(blockRow);
ref Block8x8 blockRef = ref MemoryMarshal.GetReference(blockSpan);
for (int x = 0; x < h; x++)
@@ -432,9 +460,14 @@ ref Unsafe.Add(ref blockRef, blockCol),
private void ParseProgressiveDataNonInterleaved()
{
- var component = this.components[this.frame.ComponentOrder[0]] as JpegComponent;
+ ArgumentNullException.ThrowIfNull(this.frame);
+
+ ArgumentNullException.ThrowIfNull(this.frame.ComponentOrder);
+ JpegComponent? component = this.components?[this.frame.ComponentOrder[0]] as JpegComponent;
ref JpegBitReader buffer = ref this.scanBuffer;
+ ArgumentNullException.ThrowIfNull(component);
+
int w = component.WidthInBlocks;
int h = component.HeightInBlocks;
@@ -446,7 +479,7 @@ private void ParseProgressiveDataNonInterleaved()
{
this.cancellationToken.ThrowIfCancellationRequested();
- Span blockSpan = component.SpectralBlocks.DangerousGetRowSpan(j);
+ Span blockSpan = component.SpectralBlocks!.DangerousGetRowSpan(j);
ref Block8x8 blockRef = ref MemoryMarshal.GetReference(blockSpan);
for (int i = 0; i < w; i++)
@@ -473,7 +506,7 @@ ref Unsafe.Add(ref blockRef, i),
{
this.cancellationToken.ThrowIfCancellationRequested();
- Span blockSpan = component.SpectralBlocks.DangerousGetRowSpan(j);
+ Span blockSpan = component.SpectralBlocks!.DangerousGetRowSpan(j);
ref Block8x8 blockRef = ref MemoryMarshal.GetReference(blockSpan);
for (int i = 0; i < w; i++)
@@ -727,7 +760,7 @@ private void DecodeBlockProgressiveACRefined(ref short blockDataRef, ref Huffman
[MethodImpl(InliningOptions.ShortMethod)]
private void Reset()
{
- for (int i = 0; i < this.components.Length; i++)
+ for (int i = 0; i < this.components?.Length; i++)
{
this.components[i].DcPredictor = 0;
}
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/IJpegComponent.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/IJpegComponent.cs
index 168e351bdf..78a5410db5 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/IJpegComponent.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/IJpegComponent.cs
@@ -58,7 +58,7 @@ internal interface IJpegComponent
/// Gets the storing the "raw" frequency-domain decoded + unzigged blocks.
/// We need to apply IDCT and dequantization to transform them into color-space blocks.
///
- Buffer2D SpectralBlocks { get; }
+ Buffer2D? SpectralBlocks { get; }
///
/// Gets or sets DC coefficient predictor.
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/IRawJpegData.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/IRawJpegData.cs
index fcb98b41b3..7cb0a53881 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/IRawJpegData.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/IRawJpegData.cs
@@ -16,10 +16,10 @@ internal interface IRawJpegData : IDisposable
///
/// Gets the components.
///
- JpegComponent[] Components { get; }
+ JpegComponent[]? Components { get; }
///
/// Gets the quantization tables, in natural order.
///
- Block8x8F[] QuantizationTables { get; }
+ Block8x8F[]? QuantizationTables { get; }
}
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JFifMarker.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JFifMarker.cs
index 3d015f4d94..42dcf7200a 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JFifMarker.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JFifMarker.cs
@@ -109,7 +109,7 @@ public bool Equals(JFifMarker other)
&& this.YDensity == other.YDensity;
///
- public override bool Equals(object obj) => obj is JFifMarker other && this.Equals(other);
+ public override bool Equals(object? obj) => obj is JFifMarker other && this.Equals(other);
///
public override int GetHashCode()
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponent.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponent.cs
index 5741c9536f..334c9d7eb4 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponent.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponent.cs
@@ -47,7 +47,7 @@ public JpegComponent(MemoryAllocator memoryAllocator, JpegFrame frame, byte id,
public int VerticalSamplingFactor { get; }
///
- public Buffer2D SpectralBlocks { get; private set; }
+ public Buffer2D? SpectralBlocks { get; private set; }
///
public Size SubSamplingDivisors { get; private set; }
@@ -90,7 +90,6 @@ public JpegComponent(MemoryAllocator memoryAllocator, JpegFrame frame, byte id,
public void Dispose()
{
this.SpectralBlocks?.Dispose();
- this.SpectralBlocks = null;
}
///
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegFrame.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegFrame.cs
index 9937cc8e20..8154b0a5eb 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegFrame.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegFrame.cs
@@ -73,18 +73,18 @@ public JpegFrame(JpegFileMarker sofMarker, byte precision, int width, int height
///
/// Gets or sets the component id collection.
///
- public byte[] ComponentIds { get; set; }
+ public byte[]? ComponentIds { get; set; }
///
/// Gets or sets the order in which to process the components.
/// in interleaved mode.
///
- public byte[] ComponentOrder { get; set; }
+ public byte[]? ComponentOrder { get; set; }
///
/// Gets or sets the frame component collection.
///
- public JpegComponent[] Components { get; set; }
+ public JpegComponent[]? Components { get; set; }
///
/// Gets or sets the number of MCU's per line.
@@ -115,8 +115,6 @@ public void Dispose()
{
this.Components[i]?.Dispose();
}
-
- this.Components = null;
}
}
@@ -132,8 +130,8 @@ public void Init(int maxSubFactorH, int maxSubFactorV)
for (int i = 0; i < this.ComponentCount; i++)
{
- IJpegComponent component = this.Components[i];
- component.Init(maxSubFactorH, maxSubFactorV);
+ IJpegComponent? component = this.Components?[i];
+ component?.Init(maxSubFactorH, maxSubFactorV);
}
}
@@ -142,8 +140,8 @@ public void AllocateComponents()
bool fullScan = this.Progressive || !this.Interleaved;
for (int i = 0; i < this.ComponentCount; i++)
{
- IJpegComponent component = this.Components[i];
- component.AllocateSpectral(fullScan);
+ IJpegComponent? component = this.Components?[i];
+ component?.AllocateSpectral(fullScan);
}
}
}
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs
index 8240a74587..13b18c928c 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs
@@ -27,34 +27,34 @@ internal class SpectralConverter : SpectralConverter, IDisposable
///
private readonly Configuration configuration;
- private JpegFrame frame;
+ private JpegFrame? frame;
- private IRawJpegData jpegData;
+ private IRawJpegData? jpegData;
///
/// Jpeg component converters from decompressed spectral to color data.
///
- private ComponentProcessor[] componentProcessors;
+ private ComponentProcessor[]? componentProcessors;
///
/// Color converter from jpeg color space to target pixel color space.
///
- private JpegColorConverterBase colorConverter;
+ private JpegColorConverterBase? colorConverter;
///
/// Intermediate buffer of RGB components used in color conversion.
///
- private IMemoryOwner rgbBuffer;
+ private IMemoryOwner? rgbBuffer;
///
/// Proxy buffer used in packing from RGB to target TPixel pixels.
///
- private IMemoryOwner paddedProxyPixelRow;
+ private IMemoryOwner? paddedProxyPixelRow;
///
/// Resulting 2D pixel buffer.
///
- private Buffer2D pixelBuffer;
+ private Buffer2D? pixelBuffer;
///
/// How many pixel rows are processed in one 'stride'.
@@ -101,6 +101,8 @@ public Buffer2D GetPixelBuffer(CancellationToken cancellationToken)
{
this.PrepareForDecoding();
+ ArgumentNullException.ThrowIfNull(this.pixelBuffer);
+
int steps = (int)Math.Ceiling(this.pixelBuffer.Height / (float)this.pixelRowsPerStep);
for (int step = 0; step < steps; step++)
@@ -110,9 +112,9 @@ public Buffer2D GetPixelBuffer(CancellationToken cancellationToken)
}
}
- Buffer2D buffer = this.pixelBuffer;
+ Buffer2D? buffer = this.pixelBuffer;
this.pixelBuffer = null;
- return buffer;
+ return buffer!;
}
///
@@ -121,6 +123,9 @@ public Buffer2D GetPixelBuffer(CancellationToken cancellationToken)
/// Spectral stride index.
private void ConvertStride(int spectralStep)
{
+ ArgumentNullException.ThrowIfNull(this.pixelBuffer);
+ ArgumentNullException.ThrowIfNull(this.componentProcessors);
+
int maxY = Math.Min(this.pixelBuffer.Height, this.pixelRowCounter + this.pixelRowsPerStep);
for (int i = 0; i < this.componentProcessors.Length; i++)
@@ -136,9 +141,11 @@ private void ConvertStride(int spectralStep)
var values = new JpegColorConverterBase.ComponentValues(this.componentProcessors, y);
+ ArgumentNullException.ThrowIfNull(this.colorConverter);
this.colorConverter.ConvertToRgbInplace(values);
values = values.Slice(0, width); // slice away Jpeg padding
+ ArgumentNullException.ThrowIfNull(this.rgbBuffer);
Span r = this.rgbBuffer.Slice(0, width);
Span g = this.rgbBuffer.Slice(width, width);
Span b = this.rgbBuffer.Slice(width * 2, width);
@@ -156,6 +163,7 @@ private void ConvertStride(int spectralStep)
}
else
{
+ ArgumentNullException.ThrowIfNull(this.paddedProxyPixelRow);
Span proxyRow = this.paddedProxyPixelRow.GetSpan();
PixelOperations.Instance.PackFromRgbPlanes(r, g, b, proxyRow);
proxyRow[..width].CopyTo(this.pixelBuffer.DangerousGetRowSpan(yy));
@@ -180,6 +188,8 @@ public override void PrepareForDecoding()
MemoryAllocator allocator = this.configuration.MemoryAllocator;
// color converter from RGB to TPixel
+ ArgumentNullException.ThrowIfNull(this.frame);
+ ArgumentNullException.ThrowIfNull(this.jpegData);
JpegColorConverterBase converter = this.GetColorConverter(this.frame, this.jpegData);
this.colorConverter = converter;
@@ -187,6 +197,8 @@ public override void PrepareForDecoding()
Size pixelSize = CalculateResultingImageSize(this.frame.PixelSize, this.targetSize, out int blockPixelSize);
// iteration data
+ ArgumentNullException.ThrowIfNull(this.frame.Components);
+
int majorBlockWidth = this.frame.Components.Max((component) => component.SizeInBlocks.Width);
int majorVerticalSamplingFactor = this.frame.Components.Max((component) => component.SamplingFactors.Height);
@@ -217,6 +229,8 @@ public override void ConvertStrideBaseline()
// Note that zero passing eliminates extra virtual call
this.ConvertStride(spectralStep: 0);
+ ArgumentNullException.ThrowIfNull(this.componentProcessors);
+
foreach (ComponentProcessor cpp in this.componentProcessors)
{
cpp.ClearSpectralBuffers();
@@ -226,6 +240,9 @@ public override void ConvertStrideBaseline()
protected ComponentProcessor[] CreateComponentProcessors(JpegFrame frame, IRawJpegData jpegData, int blockPixelSize, Size processorBufferSize)
{
MemoryAllocator allocator = this.configuration.MemoryAllocator;
+
+ ArgumentNullException.ThrowIfNull(frame.Components);
+
var componentProcessors = new ComponentProcessor[frame.Components.Length];
for (int i = 0; i < componentProcessors.Length; i++)
{
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Encoder/Component.cs b/src/ImageSharp/Formats/Jpeg/Components/Encoder/Component.cs
index 3049ab2c40..20d34f77e3 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Encoder/Component.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Encoder/Component.cs
@@ -38,7 +38,7 @@ public Component(MemoryAllocator memoryAllocator, int horizontalFactor, int vert
///
public int VerticalSamplingFactor { get; }
- public Buffer2D SpectralBlocks { get; private set; }
+ public Buffer2D? SpectralBlocks { get; private set; }
public Size SubSamplingDivisors { get; private set; }
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Encoder/ComponentProcessor.cs b/src/ImageSharp/Formats/Jpeg/Components/Encoder/ComponentProcessor.cs
index 2bc1405509..fb693a48ac 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Encoder/ComponentProcessor.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Encoder/ComponentProcessor.cs
@@ -41,7 +41,7 @@ public ComponentProcessor(MemoryAllocator memoryAllocator, Component component,
public void CopyColorBufferToBlocks(int spectralStep)
{
- Buffer2D spectralBuffer = this.component.SpectralBlocks;
+ Buffer2D? spectralBuffer = this.component.SpectralBlocks;
int destAreaStride = this.ColorBuffer.Width;
int yBlockStart = spectralStep * this.component.SamplingFactors.Height;
@@ -60,7 +60,7 @@ public void CopyColorBufferToBlocks(int spectralStep)
{
int yBuffer = y * this.blockAreaSize.Height;
Span colorBufferRow = this.ColorBuffer.DangerousGetRowSpan(yBuffer);
- Span blockRow = spectralBuffer.DangerousGetRowSpan(yBlockStart + y);
+ Span blockRow = spectralBuffer!.DangerousGetRowSpan(yBlockStart + y);
for (int xBlock = 0; xBlock < spectralBuffer.Width; xBlock++)
{
// load 8x8 block from 8 pixel strides
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanScanEncoder.cs b/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanScanEncoder.cs
index 8edbc3c407..c6aaa15694 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanScanEncoder.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanScanEncoder.cs
@@ -177,7 +177,7 @@ public void EncodeScanBaselineSingleComponent(Component component, Spect
converter.ConvertStrideBaseline();
// Encode spectral to binary
- Span blockSpan = component.SpectralBlocks.DangerousGetRowSpan(y: 0);
+ Span blockSpan = component.SpectralBlocks!.DangerousGetRowSpan(y: 0);
ref Block8x8 blockRef = ref MemoryMarshal.GetReference(blockSpan);
for (nint k = 0; k < w; k++)
@@ -216,7 +216,7 @@ public void EncodeScanBaseline(Component component, CancellationToken cancellati
cancellationToken.ThrowIfCancellationRequested();
// Encode spectral to binary
- Span blockSpan = component.SpectralBlocks.DangerousGetRowSpan(y: i);
+ Span blockSpan = component.SpectralBlocks!.DangerousGetRowSpan(y: i);
ref Block8x8 blockRef = ref MemoryMarshal.GetReference(blockSpan);
for (nint k = 0; k < w; k++)
@@ -278,7 +278,7 @@ private void EncodeScanBaselineInterleaved(JpegFrame frame, SpectralConv
// by the basic H and V specified for the component
for (int y = 0; y < v; y++)
{
- Span blockSpan = component.SpectralBlocks.DangerousGetRowSpan(y);
+ Span blockSpan = component.SpectralBlocks!.DangerousGetRowSpan(y);
ref Block8x8 blockRef = ref MemoryMarshal.GetReference(blockSpan);
for (nint x = 0; x < h; x++)
@@ -329,9 +329,9 @@ private void EncodeThreeComponentBaselineInterleavedScanNoSubsampling(Jp
ref HuffmanLut c2dcHuffmanTable = ref this.dcHuffmanTables[c2.DcTableId];
ref HuffmanLut c2acHuffmanTable = ref this.acHuffmanTables[c2.AcTableId];
- ref Block8x8 c0BlockRef = ref MemoryMarshal.GetReference(c0.SpectralBlocks.DangerousGetRowSpan(y: 0));
- ref Block8x8 c1BlockRef = ref MemoryMarshal.GetReference(c1.SpectralBlocks.DangerousGetRowSpan(y: 0));
- ref Block8x8 c2BlockRef = ref MemoryMarshal.GetReference(c2.SpectralBlocks.DangerousGetRowSpan(y: 0));
+ ref Block8x8 c0BlockRef = ref MemoryMarshal.GetReference(c0.SpectralBlocks!.DangerousGetRowSpan(y: 0));
+ ref Block8x8 c1BlockRef = ref MemoryMarshal.GetReference(c1.SpectralBlocks!.DangerousGetRowSpan(y: 0));
+ ref Block8x8 c2BlockRef = ref MemoryMarshal.GetReference(c2.SpectralBlocks!.DangerousGetRowSpan(y: 0));
for (nint j = 0; j < mcusPerColumn; j++)
{
diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
index 11a9bc5578..eb6e0def6f 100644
--- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
+++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
@@ -3,6 +3,7 @@
using System.Buffers;
using System.Buffers.Binary;
+using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Common.Helpers;
@@ -49,7 +50,7 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
///
/// Contains exif data.
///
- private byte[] exifData;
+ private byte[]? exifData;
///
/// Whether the image has an ICC marker.
@@ -59,7 +60,7 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
///
/// Contains ICC data.
///
- private byte[] iccData;
+ private byte[]? iccData;
///
/// Whether the image has a IPTC data.
@@ -69,7 +70,7 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
///
/// Contains IPTC data.
///
- private byte[] iptcData;
+ private byte[]? iptcData;
///
/// Whether the image has a XMP data.
@@ -79,7 +80,7 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
///
/// Contains XMP data.
///
- private byte[] xmpData;
+ private byte[]? xmpData;
///
/// Whether the image has a APP14 adobe marker. This is needed to determine image encoded colorspace.
@@ -99,12 +100,12 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
///
/// Scan decoder.
///
- private IJpegScanDecoder scanDecoder;
+ private IJpegScanDecoder? scanDecoder;
///
/// The arithmetic decoding tables.
///
- private List arithmeticDecodingTables;
+ private List? arithmeticDecodingTables;
///
/// The restart interval.
@@ -142,17 +143,17 @@ public JpegDecoderCore(JpegDecoderOptions options)
public DecoderOptions Options { get; }
///
- public Size Dimensions => this.Frame.PixelSize;
+ public Size? Dimensions => this.Frame?.PixelSize;
///
/// Gets the frame
///
- public JpegFrame Frame { get; private set; }
+ public JpegFrame? Frame { get; private set; }
///
/// Gets the decoded by this decoder instance.
///
- public ImageMetadata Metadata { get; private set; }
+ public ImageMetadata? Metadata { get; private set; }
///
public JpegColorSpace ColorSpace { get; private set; }
@@ -160,13 +161,13 @@ public JpegDecoderCore(JpegDecoderOptions options)
///
/// Gets the components.
///
- public JpegComponent[] Components => this.Frame.Components;
+ public JpegComponent[]? Components => this.Frame?.Components;
///
- JpegComponent[] IRawJpegData.Components => this.Components;
+ JpegComponent[]? IRawJpegData.Components => this.Components;
///
- public Block8x8F[] QuantizationTables { get; private set; }
+ public Block8x8F[]? QuantizationTables { get; private set; }
///
/// Finds the next file marker within the byte stream.
@@ -217,6 +218,8 @@ public Image Decode(BufferedReadStream stream, CancellationToken
this.InitXmpProfile();
this.InitDerivedMetadataProperties();
+ ArgumentNullException.ThrowIfNull(this.Metadata);
+
return new Image(
this.configuration,
spectralConverter.GetPixelBuffer(cancellationToken),
@@ -233,7 +236,9 @@ public IImageInfo Identify(BufferedReadStream stream, CancellationToken cancella
this.InitXmpProfile();
this.InitDerivedMetadataProperties();
- Size pixelSize = this.Frame.PixelSize;
+ Size pixelSize = this.Frame!.PixelSize;
+ ArgumentNullException.ThrowIfNull(this.Metadata);
+
return new ImageInfo(new PixelTypeInfo(this.Frame.BitsPerPixel), pixelSize.Width, pixelSize.Height, this.Metadata);
}
@@ -320,7 +325,7 @@ public void LoadTables(byte[] tableBytes, IJpegScanDecoder scanDecoder)
/// The input stream.
/// The spectral converter to use.
/// The token to monitor cancellation.
- internal void ParseStream(BufferedReadStream stream, SpectralConverter spectralConverter, CancellationToken cancellationToken)
+ internal void ParseStream(BufferedReadStream stream, SpectralConverter? spectralConverter, CancellationToken cancellationToken)
{
bool metadataOnly = spectralConverter == null;
@@ -494,7 +499,7 @@ internal void ParseStream(BufferedReadStream stream, SpectralConverter spectralC
fileMarker = FindNextFileMarker(stream);
}
- this.Metadata.GetJpegMetadata().Interleaved = this.Frame.Interleaved;
+ this.Metadata.GetJpegMetadata().Interleaved = this.Frame?.Interleaved;
}
///
@@ -585,31 +590,31 @@ private JpegEncodingColor DeduceJpegColorType()
return JpegEncodingColor.Rgb;
case JpegColorSpace.YCbCr:
- if (this.Frame.Components[0].HorizontalSamplingFactor == 1 && this.Frame.Components[0].VerticalSamplingFactor == 1 &&
+ if (this.Frame?.Components?[0].HorizontalSamplingFactor == 1 && this.Frame.Components[0].VerticalSamplingFactor == 1 &&
this.Frame.Components[1].HorizontalSamplingFactor == 1 && this.Frame.Components[1].VerticalSamplingFactor == 1 &&
this.Frame.Components[2].HorizontalSamplingFactor == 1 && this.Frame.Components[2].VerticalSamplingFactor == 1)
{
return JpegEncodingColor.YCbCrRatio444;
}
- else if (this.Frame.Components[0].HorizontalSamplingFactor == 2 && this.Frame.Components[0].VerticalSamplingFactor == 1 &&
+ else if (this.Frame?.Components?[0].HorizontalSamplingFactor == 2 && this.Frame.Components[0].VerticalSamplingFactor == 1 &&
this.Frame.Components[1].HorizontalSamplingFactor == 1 && this.Frame.Components[1].VerticalSamplingFactor == 1 &&
this.Frame.Components[2].HorizontalSamplingFactor == 1 && this.Frame.Components[2].VerticalSamplingFactor == 1)
{
return JpegEncodingColor.YCbCrRatio422;
}
- else if (this.Frame.Components[0].HorizontalSamplingFactor == 2 && this.Frame.Components[0].VerticalSamplingFactor == 2 &&
+ else if (this.Frame?.Components?[0].HorizontalSamplingFactor == 2 && this.Frame.Components[0].VerticalSamplingFactor == 2 &&
this.Frame.Components[1].HorizontalSamplingFactor == 1 && this.Frame.Components[1].VerticalSamplingFactor == 1 &&
this.Frame.Components[2].HorizontalSamplingFactor == 1 && this.Frame.Components[2].VerticalSamplingFactor == 1)
{
return JpegEncodingColor.YCbCrRatio420;
}
- else if (this.Frame.Components[0].HorizontalSamplingFactor == 4 && this.Frame.Components[0].VerticalSamplingFactor == 1 &&
+ else if (this.Frame?.Components?[0].HorizontalSamplingFactor == 4 && this.Frame.Components[0].VerticalSamplingFactor == 1 &&
this.Frame.Components[1].HorizontalSamplingFactor == 1 && this.Frame.Components[1].VerticalSamplingFactor == 1 &&
this.Frame.Components[2].HorizontalSamplingFactor == 1 && this.Frame.Components[2].VerticalSamplingFactor == 1)
{
return JpegEncodingColor.YCbCrRatio411;
}
- else if (this.Frame.Components[0].HorizontalSamplingFactor == 4 && this.Frame.Components[0].VerticalSamplingFactor == 2 &&
+ else if (this.Frame?.Components?[0].HorizontalSamplingFactor == 4 && this.Frame.Components[0].VerticalSamplingFactor == 2 &&
this.Frame.Components[1].HorizontalSamplingFactor == 1 && this.Frame.Components[1].VerticalSamplingFactor == 1 &&
this.Frame.Components[2].HorizontalSamplingFactor == 1 && this.Frame.Components[2].VerticalSamplingFactor == 1)
{
@@ -636,6 +641,8 @@ private void InitExifProfile()
{
if (this.hasExif)
{
+ ArgumentNullException.ThrowIfNull(this.Metadata);
+
this.Metadata.ExifProfile = new ExifProfile(this.exifData);
}
}
@@ -650,6 +657,8 @@ private void InitIccProfile()
IccProfile profile = new(this.iccData);
if (profile.CheckIsValid())
{
+ ArgumentNullException.ThrowIfNull(this.Metadata);
+
this.Metadata.IccProfile = profile;
}
}
@@ -662,6 +671,8 @@ private void InitIptcProfile()
{
if (this.hasIptc)
{
+ ArgumentNullException.ThrowIfNull(this.Metadata);
+
this.Metadata.IptcProfile = new IptcProfile(this.iptcData);
}
}
@@ -673,6 +684,8 @@ private void InitXmpProfile()
{
if (this.hasXmp)
{
+ ArgumentNullException.ThrowIfNull(this.Metadata);
+
this.Metadata.XmpProfile = new XmpProfile(this.xmpData);
}
}
@@ -684,6 +697,8 @@ private void InitDerivedMetadataProperties()
{
if (this.jFif.XDensity > 0 && this.jFif.YDensity > 0)
{
+ ArgumentNullException.ThrowIfNull(this.Metadata);
+
this.Metadata.HorizontalResolution = this.jFif.XDensity;
this.Metadata.VerticalResolution = this.jFif.YDensity;
this.Metadata.ResolutionUnits = this.jFif.DensityUnits;
@@ -695,16 +710,20 @@ private void InitDerivedMetadataProperties()
if (horizontalValue > 0 && verticalValue > 0)
{
+ ArgumentNullException.ThrowIfNull(this.Metadata);
+
this.Metadata.HorizontalResolution = horizontalValue;
this.Metadata.VerticalResolution = verticalValue;
- this.Metadata.ResolutionUnits = UnitConverter.ExifProfileToResolutionUnit(this.Metadata.ExifProfile);
+ this.Metadata.ResolutionUnits = UnitConverter.ExifProfileToResolutionUnit(this.Metadata.ExifProfile!);
}
}
}
private double GetExifResolutionValue(ExifTag tag)
{
- IExifValue resolution = this.Metadata.ExifProfile.GetValue(tag);
+ ArgumentNullException.ThrowIfNull(this.Metadata);
+
+ IExifValue? resolution = this.Metadata.ExifProfile!.GetValue(tag);
return resolution is null ? 0 : resolution.Value.ToDouble();
}
@@ -951,6 +970,7 @@ private void ProcessApp13Marker(BufferedReadStream stream, int remaining)
///
/// The input stream.
/// The remaining bytes in the segment block.
+ [MemberNotNull(nameof(arithmeticDecodingTables))]
private void ProcessArithmeticTable(BufferedReadStream stream, int remaining)
{
this.arithmeticDecodingTables ??= new List(4);
@@ -1055,6 +1075,8 @@ private void ProcessApp14Marker(BufferedReadStream stream, int remaining)
///
private void ProcessDefineQuantizationTablesMarker(BufferedReadStream stream, int remaining)
{
+ ArgumentNullException.ThrowIfNull(this.Metadata);
+
JpegMetadata jpegMetadata = this.Metadata.GetFormatMetadata(JpegFormat.Instance);
while (remaining > 0)
@@ -1075,6 +1097,8 @@ private void ProcessDefineQuantizationTablesMarker(BufferedReadStream stream, in
remaining--;
// Decoding single 8x8 table
+ ArgumentNullException.ThrowIfNull(this.QuantizationTables);
+
ref Block8x8F table = ref this.QuantizationTables[tableIndex];
switch (tablePrecision)
{
@@ -1199,6 +1223,8 @@ private void ProcessStartOfFrameMarker(BufferedReadStream stream, int remaining,
}
this.Frame = new JpegFrame(frameMarker, precision, frameWidth, frameHeight, componentCount);
+ ArgumentNullException.ThrowIfNull(this.Metadata);
+
this.Metadata.GetJpegMetadata().Progressive = this.Frame.Progressive;
remaining -= length;
@@ -1280,7 +1306,7 @@ private void ProcessStartOfFrameMarker(BufferedReadStream stream, int remaining,
if (!metadataOnly)
{
this.Frame.Init(maxH, maxV);
- this.scanDecoder.InjectFrameData(this.Frame, this);
+ this.scanDecoder?.InjectFrameData(this.Frame, this);
}
}
@@ -1296,7 +1322,7 @@ private void ProcessDefineHuffmanTablesMarker(BufferedReadStream stream, int rem
const int codeValuesMaxByteSize = 256;
const int totalBufferSize = codeLengthsByteSize + codeValuesMaxByteSize + HuffmanTable.WorkspaceByteSize;
- HuffmanScanDecoder huffmanScanDecoder = this.scanDecoder as HuffmanScanDecoder;
+ HuffmanScanDecoder? huffmanScanDecoder = this.scanDecoder as HuffmanScanDecoder;
if (huffmanScanDecoder is null)
{
JpegThrowHelper.ThrowInvalidImageContentException("missing huffman table data");
@@ -1396,7 +1422,7 @@ private void ProcessStartOfScanMarker(BufferedReadStream stream, int remaining)
int selectorsCount = stream.ReadByte();
// Validate: 0 < count <= totalComponents
- if (selectorsCount == 0 || selectorsCount > this.Frame.ComponentCount)
+ if (selectorsCount == 0 || selectorsCount > this.Frame?.ComponentCount)
{
// TODO: extract as separate method?
JpegThrowHelper.ThrowInvalidImageContentException($"Invalid number of components in scan: {selectorsCount}.");
@@ -1411,7 +1437,7 @@ private void ProcessStartOfScanMarker(BufferedReadStream stream, int remaining)
// selectorsCount*2 bytes: component index + huffman tables indices
stream.Read(this.temp, 0, selectorsBytes);
-
+ ArgumentNullException.ThrowIfNull(this.Frame);
this.Frame.Interleaved = this.Frame.ComponentCount == selectorsCount;
for (int i = 0; i < selectorsBytes; i += 2)
{
@@ -1419,7 +1445,9 @@ private void ProcessStartOfScanMarker(BufferedReadStream stream, int remaining)
int componentSelectorId = this.temp[i];
int componentIndex = -1;
- for (int j = 0; j < this.Frame.ComponentIds.Length; j++)
+ ArgumentNullException.ThrowIfNull(this.Frame);
+ ArgumentNullException.ThrowIfNull(this.Frame.ComponentIds);
+ for (int j = 0; j < this.Frame?.ComponentIds.Length; j++)
{
byte id = this.Frame.ComponentIds[j];
if (componentSelectorId == id)
@@ -1436,9 +1464,13 @@ private void ProcessStartOfScanMarker(BufferedReadStream stream, int remaining)
JpegThrowHelper.ThrowInvalidImageContentException($"Unknown component id in scan: {componentSelectorId}.");
}
+ ArgumentNullException.ThrowIfNull(this.Frame);
+ ArgumentNullException.ThrowIfNull(this.Frame.ComponentOrder);
this.Frame.ComponentOrder[i / 2] = (byte)componentIndex;
- IJpegComponent component = this.Frame.Components[componentIndex];
+ IJpegComponent? component = this.Frame?.Components?[componentIndex];
+
+ ArgumentNullException.ThrowIfNull(component);
// 1 byte: Huffman table selectors.
// 4 bits - dc
@@ -1465,7 +1497,7 @@ private void ProcessStartOfScanMarker(BufferedReadStream stream, int remaining)
JpegThrowHelper.ThrowInvalidImageContentException("Not enough data to read progressive scan decoding data");
}
- this.scanDecoder.SpectralStart = this.temp[0];
+ this.scanDecoder!.SpectralStart = this.temp[0];
this.scanDecoder.SpectralEnd = this.temp[1];
@@ -1475,6 +1507,7 @@ private void ProcessStartOfScanMarker(BufferedReadStream stream, int remaining)
if (this.scanDecoder is ArithmeticScanDecoder arithmeticScanDecoder)
{
+ ArgumentNullException.ThrowIfNull(this.arithmeticDecodingTables);
arithmeticScanDecoder.InitDecodingTables(this.arithmeticDecodingTables);
}
diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs
index 83c2e27e91..8e9536a0ae 100644
--- a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs
+++ b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs
@@ -31,11 +31,6 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals
private readonly IJpegEncoderOptions options;
- ///
- /// The output stream. All attempted writes after the first error become no-ops.
- ///
- private Stream outputStream;
-
///
/// Initializes a new instance of the class.
///
@@ -65,8 +60,6 @@ public void Encode(Image image, Stream stream, CancellationToken
cancellationToken.ThrowIfCancellationRequested();
- this.outputStream = stream;
-
ImageMetadata metadata = image.Metadata;
JpegMetadata jpegMetadata = metadata.GetJpegMetadata();
JpegFrameConfig frameConfig = this.GetFrameConfig(jpegMetadata);
@@ -75,39 +68,39 @@ public void Encode(Image image, Stream stream, CancellationToken
using var frame = new JpegFrame(image, frameConfig, interleaved);
// Write the Start Of Image marker.
- this.WriteStartOfImage();
+ this.WriteStartOfImage(stream);
// Write APP0 marker
if (frameConfig.AdobeColorTransformMarkerFlag is null)
{
- this.WriteJfifApplicationHeader(metadata);
+ this.WriteJfifApplicationHeader(metadata, stream);
}
// Write APP14 marker with adobe color extension
else
{
- this.WriteApp14Marker(frameConfig.AdobeColorTransformMarkerFlag.Value);
+ this.WriteApp14Marker(frameConfig.AdobeColorTransformMarkerFlag.Value, stream);
}
// Write Exif, XMP, ICC and IPTC profiles
- this.WriteProfiles(metadata);
+ this.WriteProfiles(metadata, stream);
// Write the image dimensions.
- this.WriteStartOfFrame(image.Width, image.Height, frameConfig);
+ this.WriteStartOfFrame(image.Width, image.Height, frameConfig, stream);
// Write the Huffman tables.
var scanEncoder = new HuffmanScanEncoder(frame.BlocksPerMcu, stream);
- this.WriteDefineHuffmanTables(frameConfig.HuffmanTables, scanEncoder);
+ this.WriteDefineHuffmanTables(frameConfig.HuffmanTables, scanEncoder, stream);
// Write the quantization tables.
- this.WriteDefineQuantizationTables(frameConfig.QuantizationTables, this.options.Quality, jpegMetadata);
+ this.WriteDefineQuantizationTables(frameConfig.QuantizationTables, this.options.Quality, jpegMetadata, stream);
// Write scans with actual pixel data
using var spectralConverter = new SpectralConverter(frame, image, this.QuantizationTables);
- this.WriteHuffmanScans(frame, frameConfig, spectralConverter, scanEncoder, cancellationToken);
+ this.WriteHuffmanScans(frame, frameConfig, spectralConverter, scanEncoder, stream, cancellationToken);
// Write the End Of Image marker.
- this.WriteEndOfImageMarker();
+ this.WriteEndOfImageMarker(stream);
stream.Flush();
}
@@ -115,20 +108,20 @@ public void Encode(Image image, Stream stream, CancellationToken
///
/// Write the start of image marker.
///
- private void WriteStartOfImage()
+ private void WriteStartOfImage(Stream outputStream)
{
// Markers are always prefixed with 0xff.
this.buffer[0] = JpegConstants.Markers.XFF;
this.buffer[1] = JpegConstants.Markers.SOI;
- this.outputStream.Write(this.buffer, 0, 2);
+ outputStream.Write(this.buffer, 0, 2);
}
///
/// Writes the application header containing the JFIF identifier plus extra data.
///
/// The image metadata.
- private void WriteJfifApplicationHeader(ImageMetadata meta)
+ private void WriteJfifApplicationHeader(ImageMetadata meta, Stream outputStream)
{
// Write the JFIF headers
this.buffer[0] = JpegConstants.Markers.XFF;
@@ -166,13 +159,13 @@ private void WriteJfifApplicationHeader(ImageMetadata meta)
this.buffer[16] = 0x00; // Thumbnail width
this.buffer[17] = 0x00; // Thumbnail height
- this.outputStream.Write(this.buffer, 0, 18);
+ outputStream.Write(this.buffer, 0, 18);
}
///
/// Writes the Define Huffman Table marker and tables.
///
- private void WriteDefineHuffmanTables(JpegHuffmanTableConfig[] tableConfigs, HuffmanScanEncoder scanEncoder)
+ private void WriteDefineHuffmanTables(JpegHuffmanTableConfig[] tableConfigs, HuffmanScanEncoder scanEncoder, Stream outputStream)
{
if (tableConfigs is null)
{
@@ -186,15 +179,15 @@ private void WriteDefineHuffmanTables(JpegHuffmanTableConfig[] tableConfigs, Huf
markerlen += 1 + 16 + tableConfigs[i].Table.Values.Length;
}
- this.WriteMarkerHeader(JpegConstants.Markers.DHT, markerlen);
+ this.WriteMarkerHeader(JpegConstants.Markers.DHT, markerlen, outputStream);
for (int i = 0; i < tableConfigs.Length; i++)
{
JpegHuffmanTableConfig tableConfig = tableConfigs[i];
int header = (tableConfig.Class << 4) | tableConfig.DestinationIndex;
- this.outputStream.WriteByte((byte)header);
- this.outputStream.Write(tableConfig.Table.Count);
- this.outputStream.Write(tableConfig.Table.Values);
+ outputStream.WriteByte((byte)header);
+ outputStream.Write(tableConfig.Table.Count);
+ outputStream.Write(tableConfig.Table.Values);
scanEncoder.BuildHuffmanTable(tableConfig);
}
@@ -203,9 +196,9 @@ private void WriteDefineHuffmanTables(JpegHuffmanTableConfig[] tableConfigs, Huf
///
/// Writes the APP14 marker to indicate the image is in RGB color space.
///
- private void WriteApp14Marker(byte colorTransform)
+ private void WriteApp14Marker(byte colorTransform, Stream outputStream)
{
- this.WriteMarkerHeader(JpegConstants.Markers.APP14, 2 + Components.Decoder.AdobeMarker.Length);
+ this.WriteMarkerHeader(JpegConstants.Markers.APP14, 2 + Components.Decoder.AdobeMarker.Length, outputStream);
// Identifier: ASCII "Adobe".
this.buffer[0] = 0x41;
@@ -226,14 +219,14 @@ private void WriteApp14Marker(byte colorTransform)
// Color transform byte
this.buffer[11] = colorTransform;
- this.outputStream.Write(this.buffer.AsSpan(0, 12));
+ outputStream.Write(this.buffer.AsSpan(0, 12));
}
///
/// Writes the EXIF profile.
///
/// The exif profile.
- private void WriteExifProfile(ExifProfile exifProfile)
+ private void WriteExifProfile(ExifProfile? exifProfile, Stream outputStream)
{
if (exifProfile is null || exifProfile.Values.Count == 0)
{
@@ -243,7 +236,7 @@ private void WriteExifProfile(ExifProfile exifProfile)
const int maxBytesApp1 = 65533; // 64k - 2 padding bytes
const int maxBytesWithExifId = 65527; // Max - 6 bytes for EXIF header.
- byte[] data = exifProfile.ToByteArray();
+ byte[] data = exifProfile.ToByteArray()!;
if (data.Length == 0)
{
@@ -257,9 +250,9 @@ private void WriteExifProfile(ExifProfile exifProfile)
int app1Length = bytesToWrite + 2;
// Write the app marker, EXIF marker, and data
- this.WriteApp1Header(app1Length);
- this.outputStream.Write(Components.Decoder.ProfileResolver.ExifMarker);
- this.outputStream.Write(data, 0, bytesToWrite - exifMarkerLength);
+ this.WriteApp1Header(app1Length, outputStream);
+ outputStream.Write(Components.Decoder.ProfileResolver.ExifMarker);
+ outputStream.Write(data, 0, bytesToWrite - exifMarkerLength);
remaining -= bytesToWrite;
// If the exif data exceeds 64K, write it in multiple APP1 Markers
@@ -268,13 +261,13 @@ private void WriteExifProfile(ExifProfile exifProfile)
bytesToWrite = remaining > maxBytesWithExifId ? maxBytesWithExifId : remaining;
app1Length = bytesToWrite + 2 + exifMarkerLength;
- this.WriteApp1Header(app1Length);
+ this.WriteApp1Header(app1Length, outputStream);
// Write Exif00 marker
- this.outputStream.Write(Components.Decoder.ProfileResolver.ExifMarker);
+ outputStream.Write(Components.Decoder.ProfileResolver.ExifMarker);
// Write the exif data
- this.outputStream.Write(data, idx, bytesToWrite);
+ outputStream.Write(data, idx, bytesToWrite);
remaining -= bytesToWrite;
}
@@ -287,7 +280,7 @@ private void WriteExifProfile(ExifProfile exifProfile)
///
/// Thrown if the IPTC profile size exceeds the limit of 65533 bytes.
///
- private void WriteIptcProfile(IptcProfile iptcProfile)
+ private void WriteIptcProfile(IptcProfile? iptcProfile, Stream outputStream)
{
const int maxBytes = 65533;
if (iptcProfile is null || !iptcProfile.Values.Any())
@@ -296,8 +289,8 @@ private void WriteIptcProfile(IptcProfile iptcProfile)
}
iptcProfile.UpdateData();
- byte[] data = iptcProfile.Data;
- if (data.Length == 0)
+ byte[]? data = iptcProfile.Data;
+ if (data!.Length == 0)
{
return;
}
@@ -311,15 +304,15 @@ private void WriteIptcProfile(IptcProfile iptcProfile)
Components.Decoder.ProfileResolver.AdobeImageResourceBlockMarker.Length +
Components.Decoder.ProfileResolver.AdobeIptcMarker.Length +
2 + 4 + data.Length;
- this.WriteAppHeader(app13Length, JpegConstants.Markers.APP13);
- this.outputStream.Write(Components.Decoder.ProfileResolver.AdobePhotoshopApp13Marker);
- this.outputStream.Write(Components.Decoder.ProfileResolver.AdobeImageResourceBlockMarker);
- this.outputStream.Write(Components.Decoder.ProfileResolver.AdobeIptcMarker);
- this.outputStream.WriteByte(0); // a empty pascal string (padded to make size even)
- this.outputStream.WriteByte(0);
+ this.WriteAppHeader(app13Length, JpegConstants.Markers.APP13, outputStream);
+ outputStream.Write(Components.Decoder.ProfileResolver.AdobePhotoshopApp13Marker);
+ outputStream.Write(Components.Decoder.ProfileResolver.AdobeImageResourceBlockMarker);
+ outputStream.Write(Components.Decoder.ProfileResolver.AdobeIptcMarker);
+ outputStream.WriteByte(0); // a empty pascal string (padded to make size even)
+ outputStream.WriteByte(0);
BinaryPrimitives.WriteInt32BigEndian(this.buffer, data.Length);
- this.outputStream.Write(this.buffer, 0, 4);
- this.outputStream.Write(data, 0, data.Length);
+ outputStream.Write(this.buffer, 0, 4);
+ outputStream.Write(data, 0, data.Length);
}
///
@@ -329,7 +322,7 @@ private void WriteIptcProfile(IptcProfile iptcProfile)
///
/// Thrown if the XMP profile size exceeds the limit of 65533 bytes.
///
- private void WriteXmpProfile(XmpProfile xmpProfile)
+ private void WriteXmpProfile(XmpProfile? xmpProfile, Stream outputStream)
{
if (xmpProfile is null)
{
@@ -340,7 +333,7 @@ private void WriteXmpProfile(XmpProfile xmpProfile)
const int maxBytes = 65533;
const int maxData = maxBytes - xmpOverheadLength;
- byte[] data = xmpProfile.Data;
+ byte[]? data = xmpProfile.Data;
if (data is null || data.Length == 0)
{
@@ -362,9 +355,9 @@ private void WriteXmpProfile(XmpProfile xmpProfile)
dataLength -= length;
int app1Length = 2 + Components.Decoder.ProfileResolver.XmpMarker.Length + length;
- this.WriteApp1Header(app1Length);
- this.outputStream.Write(Components.Decoder.ProfileResolver.XmpMarker);
- this.outputStream.Write(data, offset, length);
+ this.WriteApp1Header(app1Length, outputStream);
+ outputStream.Write(Components.Decoder.ProfileResolver.XmpMarker);
+ outputStream.Write(data, offset, length);
offset += length;
}
@@ -374,22 +367,22 @@ private void WriteXmpProfile(XmpProfile xmpProfile)
/// Writes the App1 header.
///
/// The length of the data the app1 marker contains.
- private void WriteApp1Header(int app1Length)
- => this.WriteAppHeader(app1Length, JpegConstants.Markers.APP1);
+ private void WriteApp1Header(int app1Length, Stream outputStream)
+ => this.WriteAppHeader(app1Length, JpegConstants.Markers.APP1, outputStream);
///
/// Writes a AppX header.
///
/// The length of the data the app marker contains.
/// The app marker to write.
- private void WriteAppHeader(int length, byte appMarker)
+ private void WriteAppHeader(int length, byte appMarker, Stream outputStream)
{
this.buffer[0] = JpegConstants.Markers.XFF;
this.buffer[1] = appMarker;
this.buffer[2] = (byte)((length >> 8) & 0xFF);
this.buffer[3] = (byte)(length & 0xFF);
- this.outputStream.Write(this.buffer, 0, 4);
+ outputStream.Write(this.buffer, 0, 4);
}
///
@@ -399,7 +392,7 @@ private void WriteAppHeader(int length, byte appMarker)
///
/// Thrown if any of the ICC profiles size exceeds the limit.
///
- private void WriteIccProfile(IccProfile iccProfile)
+ private void WriteIccProfile(IccProfile? iccProfile, Stream outputStream)
{
if (iccProfile is null)
{
@@ -447,7 +440,7 @@ private void WriteIccProfile(IccProfile iccProfile)
this.buffer[2] = (byte)((markerLength >> 8) & 0xFF);
this.buffer[3] = (byte)(markerLength & 0xFF);
- this.outputStream.Write(this.buffer, 0, 4);
+ outputStream.Write(this.buffer, 0, 4);
this.buffer[0] = (byte)'I';
this.buffer[1] = (byte)'C';
@@ -464,8 +457,8 @@ private void WriteIccProfile(IccProfile iccProfile)
this.buffer[12] = (byte)current; // The position within the collection.
this.buffer[13] = (byte)count; // The total number of profiles.
- this.outputStream.Write(this.buffer, 0, iccOverheadLength);
- this.outputStream.Write(data, offset, length);
+ outputStream.Write(this.buffer, 0, iccOverheadLength);
+ outputStream.Write(data, offset, length);
current++;
offset += length;
@@ -476,7 +469,7 @@ private void WriteIccProfile(IccProfile iccProfile)
/// Writes the metadata profiles to the image.
///
/// The image metadata.
- private void WriteProfiles(ImageMetadata metadata)
+ private void WriteProfiles(ImageMetadata metadata, Stream outputStream)
{
if (metadata is null)
{
@@ -489,22 +482,22 @@ private void WriteProfiles(ImageMetadata metadata)
// - APP2 ICC
// - APP13 IPTC
metadata.SyncProfiles();
- this.WriteExifProfile(metadata.ExifProfile);
- this.WriteXmpProfile(metadata.XmpProfile);
- this.WriteIccProfile(metadata.IccProfile);
- this.WriteIptcProfile(metadata.IptcProfile);
+ this.WriteExifProfile(metadata.ExifProfile, outputStream);
+ this.WriteXmpProfile(metadata.XmpProfile, outputStream);
+ this.WriteIccProfile(metadata.IccProfile, outputStream);
+ this.WriteIptcProfile(metadata.IptcProfile, outputStream);
}
///
/// Writes the Start Of Frame (Baseline) marker.
///
- private void WriteStartOfFrame(int width, int height, JpegFrameConfig frame)
+ private void WriteStartOfFrame(int width, int height, JpegFrameConfig frame, Stream outputStream)
{
JpegComponentConfig[] components = frame.Components;
// Length (high byte, low byte), 8 + components * 3.
int markerlen = 8 + (3 * components.Length);
- this.WriteMarkerHeader(JpegConstants.Markers.SOF0, markerlen);
+ this.WriteMarkerHeader(JpegConstants.Markers.SOF0, markerlen, outputStream);
this.buffer[0] = 8; // Data Precision. 8 for now, 12 and 16 bit jpegs not supported
this.buffer[1] = (byte)(height >> 8);
this.buffer[2] = (byte)(height & 0xff); // (2 bytes, Hi-Lo), must be > 0 if DNL not supported
@@ -530,13 +523,13 @@ private void WriteStartOfFrame(int width, int height, JpegFrameConfig frame)
bufferSpan[0] = components[i].Id;
}
- this.outputStream.Write(this.buffer, 0, (3 * (components.Length - 1)) + 9);
+ outputStream.Write(this.buffer, 0, (3 * (components.Length - 1)) + 9);
}
///
/// Writes the StartOfScan marker.
///
- private void WriteStartOfScan(Span components)
+ private void WriteStartOfScan(Span components, Stream outputStream)
{
// Write the SOS (Start Of Scan) marker "\xff\xda" followed by 12 bytes:
// - the marker length "\x00\x0c",
@@ -572,37 +565,37 @@ private void WriteStartOfScan(Span components)
this.buffer[sosSize - 1] = 0x00; // Ss - Start of spectral selection.
this.buffer[sosSize] = 0x3f; // Se - End of spectral selection.
this.buffer[sosSize + 1] = 0x00; // Ah + Ah (Successive approximation bit position high + low)
- this.outputStream.Write(this.buffer, 0, sosSize + 2);
+ outputStream.Write(this.buffer, 0, sosSize + 2);
}
///
/// Writes the EndOfImage marker.
///
- private void WriteEndOfImageMarker()
+ private void WriteEndOfImageMarker(Stream outputStream)
{
this.buffer[0] = JpegConstants.Markers.XFF;
this.buffer[1] = JpegConstants.Markers.EOI;
- this.outputStream.Write(this.buffer, 0, 2);
+ outputStream.Write(this.buffer, 0, 2);
}
///
/// Writes scans for given config.
///
- private void WriteHuffmanScans(JpegFrame frame, JpegFrameConfig frameConfig, SpectralConverter spectralConverter, HuffmanScanEncoder encoder, CancellationToken cancellationToken)
+ private void WriteHuffmanScans(JpegFrame frame, JpegFrameConfig frameConfig, SpectralConverter spectralConverter, HuffmanScanEncoder encoder, Stream outputStream, CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel
{
if (frame.Components.Length == 1)
{
frame.AllocateComponents(fullScan: false);
- this.WriteStartOfScan(frameConfig.Components);
+ this.WriteStartOfScan(frameConfig.Components, outputStream);
encoder.EncodeScanBaselineSingleComponent(frame.Components[0], spectralConverter, cancellationToken);
}
else if (frame.Interleaved)
{
frame.AllocateComponents(fullScan: false);
- this.WriteStartOfScan(frameConfig.Components);
+ this.WriteStartOfScan(frameConfig.Components, outputStream);
encoder.EncodeScanBaselineInterleaved(frameConfig.EncodingColor, frame, spectralConverter, cancellationToken);
}
else
@@ -613,7 +606,7 @@ private void WriteHuffmanScans(JpegFrame frame, JpegFrameConfig frameCon
Span components = frameConfig.Components;
for (int i = 0; i < frame.Components.Length; i++)
{
- this.WriteStartOfScan(components.Slice(i, 1));
+ this.WriteStartOfScan(components.Slice(i, 1), outputStream);
encoder.EncodeScanBaseline(frame.Components[i], cancellationToken);
}
}
@@ -624,14 +617,14 @@ private void WriteHuffmanScans(JpegFrame frame, JpegFrameConfig frameCon
///
/// The marker to write.
/// The marker length.
- private void WriteMarkerHeader(byte marker, int length)
+ private void WriteMarkerHeader(byte marker, int length, Stream outputStream)
{
// Markers are always prefixed with 0xff.
this.buffer[0] = JpegConstants.Markers.XFF;
this.buffer[1] = marker;
this.buffer[2] = (byte)(length >> 8);
this.buffer[3] = (byte)(length & 0xff);
- this.outputStream.Write(this.buffer, 0, 4);
+ outputStream.Write(this.buffer, 0, 4);
}
///
@@ -648,13 +641,13 @@ private void WriteMarkerHeader(byte marker, int length)
/// Quantization tables configs.
/// Optional quality value from the options.
/// Jpeg metadata instance.
- private void WriteDefineQuantizationTables(JpegQuantizationTableConfig[] configs, int? optionsQuality, JpegMetadata metadata)
+ private void WriteDefineQuantizationTables(JpegQuantizationTableConfig[] configs, int? optionsQuality, JpegMetadata metadata, Stream outputStream)
{
int dataLen = configs.Length * (1 + Block8x8.Size);
// Marker + quantization table lengths.
int markerlen = 2 + dataLen;
- this.WriteMarkerHeader(JpegConstants.Markers.DQT, markerlen);
+ this.WriteMarkerHeader(JpegConstants.Markers.DQT, markerlen, outputStream);
byte[] buffer = new byte[dataLen];
int offset = 0;
@@ -684,7 +677,7 @@ private void WriteDefineQuantizationTables(JpegQuantizationTableConfig[] configs
}
// write filled buffer to the stream
- this.outputStream.Write(buffer);
+ outputStream.Write(buffer);
static int GetQualityForTable(int destIndex, int? encoderQuality, JpegMetadata metadata) => destIndex switch
{
@@ -697,7 +690,7 @@ private void WriteDefineQuantizationTables(JpegQuantizationTableConfig[] configs
private JpegFrameConfig GetFrameConfig(JpegMetadata metadata)
{
JpegEncodingColor color = this.options.ColorType ?? metadata.ColorType ?? JpegEncodingColor.YCbCrRatio420;
- JpegFrameConfig frameConfig = Array.Find(
+ JpegFrameConfig? frameConfig = Array.Find(
FrameConfigs,
cfg => cfg.EncodingColor == color);
diff --git a/src/ImageSharp/Formats/Jpeg/JpegImageFormatDetector.cs b/src/ImageSharp/Formats/Jpeg/JpegImageFormatDetector.cs
index f2cc631c53..3bf7346ff3 100644
--- a/src/ImageSharp/Formats/Jpeg/JpegImageFormatDetector.cs
+++ b/src/ImageSharp/Formats/Jpeg/JpegImageFormatDetector.cs
@@ -12,7 +12,7 @@ public sealed class JpegImageFormatDetector : IImageFormatDetector
public int HeaderSize => 11;
///
- public IImageFormat DetectFormat(ReadOnlySpan header)
+ public IImageFormat? DetectFormat(ReadOnlySpan header)
=> this.IsSupportedFileFormat(header) ? JpegFormat.Instance : null;
private bool IsSupportedFileFormat(ReadOnlySpan header)
diff --git a/src/ImageSharp/Formats/Pbm/BinaryEncoder.cs b/src/ImageSharp/Formats/Pbm/BinaryEncoder.cs
index b179c775cf..df6a8d7db6 100644
--- a/src/ImageSharp/Formats/Pbm/BinaryEncoder.cs
+++ b/src/ImageSharp/Formats/Pbm/BinaryEncoder.cs
@@ -60,7 +60,7 @@ private static void WriteGrayscale(Configuration configuration, Stream s
{
int width = image.Width;
int height = image.Height;
- Buffer2D pixelBuffer = image.PixelBuffer;
+ Buffer2D pixelBuffer = image.PixelBuffer!;
MemoryAllocator allocator = configuration.MemoryAllocator;
using IMemoryOwner row = allocator.Allocate(width);
Span rowSpan = row.GetSpan();
@@ -85,7 +85,7 @@ private static void WriteWideGrayscale(Configuration configuration, Stre
const int bytesPerPixel = 2;
int width = image.Width;
int height = image.Height;
- Buffer2D pixelBuffer = image.PixelBuffer;
+ Buffer2D pixelBuffer = image.PixelBuffer!;
MemoryAllocator allocator = configuration.MemoryAllocator;
using IMemoryOwner row = allocator.Allocate(width * bytesPerPixel);
Span rowSpan = row.GetSpan();
@@ -110,7 +110,7 @@ private static void WriteRgb(Configuration configuration, Stream stream,
const int bytesPerPixel = 3;
int width = image.Width;
int height = image.Height;
- Buffer2D pixelBuffer = image.PixelBuffer;
+ Buffer2D pixelBuffer = image.PixelBuffer!;
MemoryAllocator allocator = configuration.MemoryAllocator;
using IMemoryOwner row = allocator.Allocate(width * bytesPerPixel);
Span rowSpan = row.GetSpan();
@@ -135,7 +135,7 @@ private static void WriteWideRgb(Configuration configuration, Stream str
const int bytesPerPixel = 6;
int width = image.Width;
int height = image.Height;
- Buffer2D pixelBuffer = image.PixelBuffer;
+ Buffer2D pixelBuffer = image.PixelBuffer!;
MemoryAllocator allocator = configuration.MemoryAllocator;
using IMemoryOwner row = allocator.Allocate(width * bytesPerPixel);
Span rowSpan = row.GetSpan();
@@ -159,7 +159,7 @@ private static void WriteBlackAndWhite(Configuration configuration, Stre
{
int width = image.Width;
int height = image.Height;
- Buffer2D pixelBuffer = image.PixelBuffer;
+ Buffer2D pixelBuffer = image.PixelBuffer!;
MemoryAllocator allocator = configuration.MemoryAllocator;
using IMemoryOwner row = allocator.Allocate(width);
Span rowSpan = row.GetSpan();
diff --git a/src/ImageSharp/Formats/Pbm/PbmDecoder.cs b/src/ImageSharp/Formats/Pbm/PbmDecoder.cs
index 2caf8ecc1f..85d7b57958 100644
--- a/src/ImageSharp/Formats/Pbm/PbmDecoder.cs
+++ b/src/ImageSharp/Formats/Pbm/PbmDecoder.cs
@@ -44,6 +44,8 @@ Image IImageDecoder.Decode(DecoderOptions options, Stream stream
PbmDecoderCore decoder = new(options);
Image image = decoder.Decode(options.Configuration, stream, cancellationToken);
+ ArgumentNullException.ThrowIfNull(image);
+
ImageDecoderUtilities.Resize(options, image);
return image;
diff --git a/src/ImageSharp/Formats/Pbm/PbmDecoderCore.cs b/src/ImageSharp/Formats/Pbm/PbmDecoderCore.cs
index d5ea66482e..77cae0dd4f 100644
--- a/src/ImageSharp/Formats/Pbm/PbmDecoderCore.cs
+++ b/src/ImageSharp/Formats/Pbm/PbmDecoderCore.cs
@@ -1,6 +1,7 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
+using System.Diagnostics.CodeAnalysis;
using SixLabors.ImageSharp.IO;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata;
@@ -44,7 +45,7 @@ internal sealed class PbmDecoderCore : IImageDecoderInternals
///
/// The decoded by this decoder instance.
///
- private ImageMetadata metadata;
+ private ImageMetadata? metadata;
///
/// Initializes a new instance of the class.
@@ -60,7 +61,7 @@ public PbmDecoderCore(DecoderOptions options)
public DecoderOptions Options { get; }
///
- public Size Dimensions => this.pixelSize;
+ public Size? Dimensions => this.pixelSize;
///
public Image Decode(BufferedReadStream stream, CancellationToken cancellationToken)
@@ -95,6 +96,7 @@ public IImageInfo Identify(BufferedReadStream stream, CancellationToken cancella
/// Processes the ppm header.
///
/// The input stream.
+ [MemberNotNull(nameof(metadata))]
private void ProcessHeader(BufferedReadStream stream)
{
Span buffer = stackalloc byte[2];
diff --git a/src/ImageSharp/Formats/Pbm/PbmImageFormatDetector.cs b/src/ImageSharp/Formats/Pbm/PbmImageFormatDetector.cs
index c982042e02..021cff2670 100644
--- a/src/ImageSharp/Formats/Pbm/PbmImageFormatDetector.cs
+++ b/src/ImageSharp/Formats/Pbm/PbmImageFormatDetector.cs
@@ -16,7 +16,7 @@ public sealed class PbmImageFormatDetector : IImageFormatDetector
public int HeaderSize => 2;
///
- public IImageFormat DetectFormat(ReadOnlySpan header) => IsSupportedFileFormat(header) ? PbmFormat.Instance : null;
+ public IImageFormat? DetectFormat(ReadOnlySpan header) => IsSupportedFileFormat(header) ? PbmFormat.Instance : null;
private static bool IsSupportedFileFormat(ReadOnlySpan header)
{
diff --git a/src/ImageSharp/Formats/Pbm/PlainEncoder.cs b/src/ImageSharp/Formats/Pbm/PlainEncoder.cs
index 29260f54aa..a6190592a3 100644
--- a/src/ImageSharp/Formats/Pbm/PlainEncoder.cs
+++ b/src/ImageSharp/Formats/Pbm/PlainEncoder.cs
@@ -74,7 +74,7 @@ private static void WriteGrayscale(Configuration configuration, Stream s
{
int width = image.Width;
int height = image.Height;
- Buffer2D pixelBuffer = image.PixelBuffer;
+ Buffer2D pixelBuffer = image.PixelBuffer!;
MemoryAllocator allocator = configuration.MemoryAllocator;
using IMemoryOwner row = allocator.Allocate(width);
Span rowSpan = row.GetSpan();
@@ -107,7 +107,7 @@ private static void WriteWideGrayscale(Configuration configuration, Stre
{
int width = image.Width;
int height = image.Height;
- Buffer2D pixelBuffer = image.PixelBuffer;
+ Buffer2D pixelBuffer = image.PixelBuffer!;
MemoryAllocator allocator = configuration.MemoryAllocator;
using IMemoryOwner row = allocator.Allocate(width);
Span rowSpan = row.GetSpan();
@@ -140,7 +140,7 @@ private static void WriteRgb(Configuration configuration, Stream stream,
{
int width = image.Width;
int height = image.Height;
- Buffer2D pixelBuffer = image.PixelBuffer;
+ Buffer2D pixelBuffer = image.PixelBuffer!;
MemoryAllocator allocator = configuration.MemoryAllocator;
using IMemoryOwner row = allocator.Allocate(width);
Span rowSpan = row.GetSpan();
@@ -179,7 +179,7 @@ private static void WriteWideRgb(Configuration configuration, Stream str
{
int width = image.Width;
int height = image.Height;
- Buffer2D pixelBuffer = image.PixelBuffer;
+ Buffer2D pixelBuffer = image.PixelBuffer!;
MemoryAllocator allocator = configuration.MemoryAllocator;
using IMemoryOwner row = allocator.Allocate(width);
Span rowSpan = row.GetSpan();
@@ -218,7 +218,7 @@ private static void WriteBlackAndWhite(Configuration configuration, Stre
{
int width = image.Width;
int height = image.Height;
- Buffer2D pixelBuffer = image.PixelBuffer;
+ Buffer2D pixelBuffer = image.PixelBuffer!;
MemoryAllocator allocator = configuration.MemoryAllocator;
using IMemoryOwner row = allocator.Allocate(width);
Span rowSpan = row.GetSpan();
diff --git a/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs b/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs
index 27d86f9218..1bed8937bf 100644
--- a/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs
+++ b/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs
@@ -46,7 +46,7 @@ internal interface IPngEncoderOptions
///
/// Gets the quantizer for reducing the color count.
///
- IQuantizer Quantizer { get; }
+ IQuantizer? Quantizer { get; }
///
/// Gets the transparency threshold.
diff --git a/src/ImageSharp/Formats/Png/PngChunk.cs b/src/ImageSharp/Formats/Png/PngChunk.cs
index 945661aa57..8fda6454b6 100644
--- a/src/ImageSharp/Formats/Png/PngChunk.cs
+++ b/src/ImageSharp/Formats/Png/PngChunk.cs
@@ -10,7 +10,7 @@ namespace SixLabors.ImageSharp.Formats.Png;
///
internal readonly struct PngChunk
{
- public PngChunk(int length, PngChunkType type, IMemoryOwner data = null)
+ public PngChunk(int length, PngChunkType type, IMemoryOwner? data = null)
{
this.Length = length;
this.Type = type;
@@ -35,7 +35,7 @@ public PngChunk(int length, PngChunkType type, IMemoryOwner data = null)
/// Gets the data bytes appropriate to the chunk type, if any.
/// This field can be of zero length or null.
///
- public IMemoryOwner Data { get; }
+ public IMemoryOwner? Data { get; }
///
/// Gets a value indicating whether the given chunk is critical to decoding
diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs
index 2247cd6b7b..55515e994d 100644
--- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs
+++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs
@@ -3,6 +3,7 @@
using System.Buffers;
using System.Buffers.Binary;
+using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO.Compression;
using System.Runtime.CompilerServices;
@@ -52,11 +53,6 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
///
private readonly MemoryAllocator memoryAllocator;
- ///
- /// The stream to decode from.
- ///
- private BufferedReadStream currentStream;
-
///
/// The png header.
///
@@ -80,22 +76,22 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
///
/// The palette containing color information for indexed png's.
///
- private byte[] palette;
+ private byte[]? palette;
///
/// The palette containing alpha channel color information for indexed png's.
///
- private byte[] paletteAlpha;
+ private byte[]? paletteAlpha;
///
/// Previous scanline processed.
///
- private IMemoryOwner previousScanline;
+ private IMemoryOwner? previousScanline;
///
/// The current scanline that is being processed.
///
- private IMemoryOwner scanline;
+ private IMemoryOwner? scanline;
///
/// The index of the current scanline being processed.
@@ -142,7 +138,7 @@ internal PngDecoderCore(DecoderOptions options, bool colorMetadataOnly)
public DecoderOptions Options { get; }
///
- public Size Dimensions => new(this.header.Width, this.header.Height);
+ public Size? Dimensions => new(this.header.Width, this.header.Height);
///
public Image Decode(BufferedReadStream stream, CancellationToken cancellationToken)
@@ -150,25 +146,24 @@ public Image Decode(BufferedReadStream stream, CancellationToken
{
ImageMetadata metadata = new();
PngMetadata pngMetadata = metadata.GetPngMetadata();
- this.currentStream = stream;
- this.currentStream.Skip(8);
- Image image = null;
+ stream.Skip(8);
+ Image? image = null;
try
{
- while (this.TryReadChunk(out PngChunk chunk))
+ while (this.TryReadChunk(stream, out PngChunk chunk))
{
try
{
switch (chunk.Type)
{
case PngChunkType.Header:
- this.ReadHeaderChunk(pngMetadata, chunk.Data.GetSpan());
+ this.ReadHeaderChunk(pngMetadata, chunk.Data!.GetSpan());
break;
case PngChunkType.Physical:
- ReadPhysicalChunk(metadata, chunk.Data.GetSpan());
+ ReadPhysicalChunk(metadata, chunk.Data!.GetSpan());
break;
case PngChunkType.Gamma:
- ReadGammaChunk(pngMetadata, chunk.Data.GetSpan());
+ ReadGammaChunk(pngMetadata, chunk.Data!.GetSpan());
break;
case PngChunkType.Data:
if (image is null)
@@ -176,40 +171,40 @@ public Image Decode(BufferedReadStream stream, CancellationToken
this.InitializeImage(metadata, out image);
}
- this.ReadScanlines(chunk, image.Frames.RootFrame, pngMetadata);
+ this.ReadScanlines(stream, chunk, image.Frames.RootFrame, pngMetadata);
break;
case PngChunkType.Palette:
byte[] pal = new byte[chunk.Length];
- chunk.Data.GetSpan().CopyTo(pal);
+ chunk.Data!.GetSpan().CopyTo(pal);
this.palette = pal;
break;
case PngChunkType.Transparency:
byte[] alpha = new byte[chunk.Length];
- chunk.Data.GetSpan().CopyTo(alpha);
+ chunk.Data!.GetSpan().CopyTo(alpha);
this.paletteAlpha = alpha;
this.AssignTransparentMarkers(alpha, pngMetadata);
break;
case PngChunkType.Text:
- this.ReadTextChunk(metadata, pngMetadata, chunk.Data.GetSpan());
+ this.ReadTextChunk(metadata, pngMetadata, chunk.Data!.GetSpan());
break;
case PngChunkType.CompressedText:
- this.ReadCompressedTextChunk(metadata, pngMetadata, chunk.Data.GetSpan());
+ this.ReadCompressedTextChunk(metadata, pngMetadata, chunk.Data!.GetSpan());
break;
case PngChunkType.InternationalText:
- this.ReadInternationalTextChunk(metadata, chunk.Data.GetSpan());
+ this.ReadInternationalTextChunk(metadata, chunk.Data!.GetSpan());
break;
case PngChunkType.Exif:
if (!this.skipMetadata)
{
byte[] exifData = new byte[chunk.Length];
- chunk.Data.GetSpan().CopyTo(exifData);
+ chunk.Data!.GetSpan().CopyTo(exifData);
MergeOrSetExifProfile(metadata, new ExifProfile(exifData), replaceExistingKeys: true);
}
break;
case PngChunkType.EmbeddedColorProfile:
- this.ReadColorProfileChunk(metadata, chunk.Data.GetSpan());
+ this.ReadColorProfileChunk(metadata, chunk.Data!.GetSpan());
break;
case PngChunkType.End:
goto EOF;
@@ -250,36 +245,35 @@ public IImageInfo Identify(BufferedReadStream stream, CancellationToken cancella
{
ImageMetadata metadata = new();
PngMetadata pngMetadata = metadata.GetPngMetadata();
- this.currentStream = stream;
- this.currentStream.Skip(8);
+ stream.Skip(8);
try
{
- while (this.TryReadChunk(out PngChunk chunk))
+ while (this.TryReadChunk(stream, out PngChunk chunk))
{
try
{
switch (chunk.Type)
{
case PngChunkType.Header:
- this.ReadHeaderChunk(pngMetadata, chunk.Data.GetSpan());
+ this.ReadHeaderChunk(pngMetadata, chunk.Data!.GetSpan());
break;
case PngChunkType.Physical:
if (this.colorMetadataOnly)
{
- this.SkipChunkDataAndCrc(chunk);
+ this.SkipChunkDataAndCrc(stream, chunk);
break;
}
- ReadPhysicalChunk(metadata, chunk.Data.GetSpan());
+ ReadPhysicalChunk(metadata, chunk.Data!.GetSpan());
break;
case PngChunkType.Gamma:
if (this.colorMetadataOnly)
{
- this.SkipChunkDataAndCrc(chunk);
+ this.SkipChunkDataAndCrc(stream, chunk);
break;
}
- ReadGammaChunk(pngMetadata, chunk.Data.GetSpan());
+ ReadGammaChunk(pngMetadata, chunk.Data!.GetSpan());
break;
case PngChunkType.Data:
@@ -289,11 +283,11 @@ public IImageInfo Identify(BufferedReadStream stream, CancellationToken cancella
goto EOF;
}
- this.SkipChunkDataAndCrc(chunk);
+ this.SkipChunkDataAndCrc(stream, chunk);
break;
case PngChunkType.Transparency:
byte[] alpha = new byte[chunk.Length];
- chunk.Data.GetSpan().CopyTo(alpha);
+ chunk.Data!.GetSpan().CopyTo(alpha);
this.paletteAlpha = alpha;
this.AssignTransparentMarkers(alpha, pngMetadata);
@@ -306,41 +300,41 @@ public IImageInfo Identify(BufferedReadStream stream, CancellationToken cancella
case PngChunkType.Text:
if (this.colorMetadataOnly)
{
- this.SkipChunkDataAndCrc(chunk);
+ this.SkipChunkDataAndCrc(stream, chunk);
break;
}
- this.ReadTextChunk(metadata, pngMetadata, chunk.Data.GetSpan());
+ this.ReadTextChunk(metadata, pngMetadata, chunk.Data!.GetSpan());
break;
case PngChunkType.CompressedText:
if (this.colorMetadataOnly)
{
- this.SkipChunkDataAndCrc(chunk);
+ this.SkipChunkDataAndCrc(stream, chunk);
break;
}
- this.ReadCompressedTextChunk(metadata, pngMetadata, chunk.Data.GetSpan());
+ this.ReadCompressedTextChunk(metadata, pngMetadata, chunk.Data!.GetSpan());
break;
case PngChunkType.InternationalText:
if (this.colorMetadataOnly)
{
- this.SkipChunkDataAndCrc(chunk);
+ this.SkipChunkDataAndCrc(stream, chunk);
break;
}
- this.ReadInternationalTextChunk(metadata, chunk.Data.GetSpan());
+ this.ReadInternationalTextChunk(metadata, chunk.Data!.GetSpan());
break;
case PngChunkType.Exif:
if (this.colorMetadataOnly)
{
- this.SkipChunkDataAndCrc(chunk);
+ this.SkipChunkDataAndCrc(stream, chunk);
break;
}
if (!this.skipMetadata)
{
byte[] exifData = new byte[chunk.Length];
- chunk.Data.GetSpan().CopyTo(exifData);
+ chunk.Data!.GetSpan().CopyTo(exifData);
MergeOrSetExifProfile(metadata, new ExifProfile(exifData), replaceExistingKeys: true);
}
@@ -351,7 +345,7 @@ public IImageInfo Identify(BufferedReadStream stream, CancellationToken cancella
default:
if (this.colorMetadataOnly)
{
- this.SkipChunkDataAndCrc(chunk);
+ this.SkipChunkDataAndCrc(stream, chunk);
}
break;
@@ -397,7 +391,7 @@ private static byte ReadByteLittleEndian(ReadOnlySpan buffer, int offset)
/// The number of bits per value.
/// The new array.
/// The resulting array.
- private bool TryScaleUpTo8BitArray(ReadOnlySpan source, int bytesPerScanline, int bits, out IMemoryOwner buffer)
+ private bool TryScaleUpTo8BitArray(ReadOnlySpan source, int bytesPerScanline, int bits, out IMemoryOwner? buffer)
{
if (bits >= 8)
{
@@ -555,12 +549,14 @@ private int CalculateScanlineLength(int width)
/// The png chunk containing the compressed scanline data.
/// The pixel data.
/// The png metadata
- private void ReadScanlines(PngChunk chunk, ImageFrame image, PngMetadata pngMetadata)
+ private void ReadScanlines(BufferedReadStream stream, PngChunk chunk, ImageFrame image, PngMetadata pngMetadata)
where TPixel : unmanaged, IPixel
{
- using ZlibInflateStream deframeStream = new(this.currentStream, this.ReadNextDataChunk);
+ using ZlibInflateStream deframeStream = new(stream, () => this.ReadNextDataChunk(stream));
deframeStream.AllocateNewBytes(chunk.Length, true);
- DeflateStream dataStream = deframeStream.CompressedStream;
+ DeflateStream? dataStream = deframeStream.CompressedStream;
+
+ ArgumentNullException.ThrowIfNull(dataStream);
if (this.header.InterlaceMethod == PngInterlaceMode.Adam7)
{
@@ -584,6 +580,8 @@ private void DecodePixelData(DeflateStream compressedStream, ImageFrame<
{
while (this.currentRow < this.header.Height)
{
+ ArgumentNullException.ThrowIfNull(this.scanline);
+
Span scanlineSpan = this.scanline.GetSpan();
while (this.currentRowBytesRead < this.bytesPerScanline)
{
@@ -608,14 +606,17 @@ private void DecodePixelData(DeflateStream compressedStream, ImageFrame<
break;
case FilterType.Up:
+ ArgumentNullException.ThrowIfNull(this.previousScanline);
UpFilter.Decode(scanlineSpan, this.previousScanline.GetSpan());
break;
case FilterType.Average:
+ ArgumentNullException.ThrowIfNull(this.previousScanline);
AverageFilter.Decode(scanlineSpan, this.previousScanline.GetSpan(), this.bytesPerPixel);
break;
case FilterType.Paeth:
+ ArgumentNullException.ThrowIfNull(this.previousScanline);
PaethFilter.Decode(scanlineSpan, this.previousScanline.GetSpan(), this.bytesPerPixel);
break;
@@ -644,7 +645,7 @@ private void DecodeInterlacedPixelData(DeflateStream compressedStream, I
{
int pass = 0;
int width = this.header.Width;
- Buffer2D imageBuffer = image.PixelBuffer;
+ Buffer2D imageBuffer = image.PixelBuffer!;
while (true)
{
int numColumns = Adam7.ComputeColumns(width, pass);
@@ -663,6 +664,7 @@ private void DecodeInterlacedPixelData(DeflateStream compressedStream, I
{
while (this.currentRowBytesRead < bytesPerInterlaceScanline)
{
+ ArgumentNullException.ThrowIfNull(this.scanline);
int bytesRead = compressedStream.Read(this.scanline.GetSpan(), this.currentRowBytesRead, bytesPerInterlaceScanline - this.currentRowBytesRead);
if (bytesRead <= 0)
{
@@ -674,6 +676,9 @@ private void DecodeInterlacedPixelData(DeflateStream compressedStream, I
this.currentRowBytesRead = 0;
+ ArgumentNullException.ThrowIfNull(this.scanline);
+ ArgumentNullException.ThrowIfNull(this.previousScanline);
+
Span scanSpan = this.scanline.Slice(0, bytesPerInterlaceScanline);
Span prevSpan = this.previousScanline.Slice(0, bytesPerInterlaceScanline);
@@ -712,6 +717,7 @@ private void DecodeInterlacedPixelData(DeflateStream compressedStream, I
}
pass++;
+ ArgumentNullException.ThrowIfNull(this.previousScanline);
this.previousScanline.Clear();
if (pass < 7)
@@ -736,13 +742,13 @@ private void DecodeInterlacedPixelData(DeflateStream compressedStream, I
private void ProcessDefilteredScanline(ReadOnlySpan defilteredScanline, ImageFrame pixels, PngMetadata pngMetadata)
where TPixel : unmanaged, IPixel
{
- Span rowSpan = pixels.PixelBuffer.DangerousGetRowSpan(this.currentRow);
+ Span rowSpan = pixels.PixelBuffer!.DangerousGetRowSpan(this.currentRow);
// Trim the first marker byte from the buffer
ReadOnlySpan trimmed = defilteredScanline[1..];
// Convert 1, 2, and 4 bit pixel data into the 8 bit equivalent.
- IMemoryOwner buffer = null;
+ IMemoryOwner? buffer = null;
try
{
ReadOnlySpan scanlineSpan = this.TryScaleUpTo8BitArray(
@@ -750,7 +756,7 @@ private void ProcessDefilteredScanline(ReadOnlySpan defilteredScan
this.bytesPerScanline - 1,
this.header.BitDepth,
out buffer)
- ? buffer.GetSpan()
+ ? buffer!.GetSpan()
: trimmed;
switch (this.pngColorType)
@@ -834,7 +840,7 @@ private void ProcessInterlacedDefilteredScanline(ReadOnlySpan defi
ReadOnlySpan trimmed = defilteredScanline[1..];
// Convert 1, 2, and 4 bit pixel data into the 8 bit equivalent.
- IMemoryOwner buffer = null;
+ IMemoryOwner? buffer = null;
try
{
ReadOnlySpan scanlineSpan = this.TryScaleUpTo8BitArray(
@@ -842,7 +848,7 @@ private void ProcessInterlacedDefilteredScanline(ReadOnlySpan defi
this.bytesPerScanline,
this.header.BitDepth,
out buffer)
- ? buffer.GetSpan()
+ ? buffer!.GetSpan()
: trimmed;
switch (this.pngColorType)
@@ -1056,7 +1062,7 @@ private void ReadCompressedTextChunk(ImageMetadata baseMetadata, PngMetadata met
ReadOnlySpan compressedData = data[(zeroIndex + 2)..];
- if (this.TryUncompressTextData(compressedData, PngConstants.Encoding, out string uncompressed)
+ if (this.TryUncompressTextData(compressedData, PngConstants.Encoding, out string? uncompressed)
&& !TryReadTextChunkMetadata(baseMetadata, name, uncompressed))
{
metadata.TextData.Add(new PngTextData(name, uncompressed, string.Empty, string.Empty));
@@ -1072,7 +1078,7 @@ private void ReadCompressedTextChunk(ImageMetadata baseMetadata, PngMetadata met
/// True if metadata was successfully parsed from the text chunk. False if the
/// text chunk was not identified as metadata, and should be stored in the metadata
/// object unmodified.
- private static bool TryReadTextChunkMetadata(ImageMetadata baseMetadata, string chunkName, string chunkText)
+ private static bool TryReadTextChunkMetadata(ImageMetadata baseMetadata, string chunkName, string? chunkText)
{
if (chunkName.Equals("Raw profile type exif", StringComparison.OrdinalIgnoreCase) &&
TryReadLegacyExifTextChunk(baseMetadata, chunkText))
@@ -1094,7 +1100,7 @@ private static bool TryReadTextChunkMetadata(ImageMetadata baseMetadata, string
///
/// The to store the decoded exif tags into.
/// The contents of the "raw profile type exif" text chunk.
- private static bool TryReadLegacyExifTextChunk(ImageMetadata metadata, string data)
+ private static bool TryReadLegacyExifTextChunk(ImageMetadata metadata, string? data)
{
ReadOnlySpan dataSpan = data.AsSpan();
dataSpan = dataSpan.TrimStart();
@@ -1229,11 +1235,11 @@ private unsafe bool TryUncompressZlibData(ReadOnlySpan compressedData, out
return false;
}
- int bytesRead = inflateStream.CompressedStream.Read(destUncompressedData, 0, destUncompressedData.Length);
+ int bytesRead = inflateStream.CompressedStream!.Read(destUncompressedData, 0, destUncompressedData.Length);
while (bytesRead != 0)
{
memoryStreamOutput.Write(destUncompressedData[..bytesRead]);
- bytesRead = inflateStream.CompressedStream.Read(destUncompressedData, 0, destUncompressedData.Length);
+ bytesRead = inflateStream.CompressedStream!.Read(destUncompressedData, 0, destUncompressedData.Length);
}
uncompressedBytesArray = memoryStreamOutput.ToArray();
@@ -1349,7 +1355,7 @@ private void ReadInternationalTextChunk(ImageMetadata metadata, ReadOnlySpan compressedData = data[dataStartIdx..];
- if (this.TryUncompressTextData(compressedData, PngConstants.TranslatedEncoding, out string uncompressed))
+ if (this.TryUncompressTextData(compressedData, PngConstants.TranslatedEncoding, out string? uncompressed))
{
pngMetadata.TextData.Add(new PngTextData(keyword, uncompressed, language, translatedKeyword));
}
@@ -1372,7 +1378,7 @@ private void ReadInternationalTextChunk(ImageMetadata metadata, ReadOnlySpanThe string encoding to use.
/// The uncompressed value.
/// The .
- private bool TryUncompressTextData(ReadOnlySpan compressedData, Encoding encoding, out string value)
+ private bool TryUncompressTextData(ReadOnlySpan compressedData, Encoding encoding, [NotNullWhen(true)]out string? value)
{
if (this.TryUncompressZlibData(compressedData, out byte[] uncompressedData))
{
@@ -1388,16 +1394,16 @@ private bool TryUncompressTextData(ReadOnlySpan compressedData, Encoding e
/// Reads the next data chunk.
///
/// Count of bytes in the next data chunk, or 0 if there are no more data chunks left.
- private int ReadNextDataChunk()
+ private int ReadNextDataChunk(BufferedReadStream stream)
{
if (this.nextChunk != null)
{
return 0;
}
- this.currentStream.Read(this.buffer, 0, 4);
+ stream.Read(this.buffer, 0, 4);
- if (this.TryReadChunk(out PngChunk chunk))
+ if (this.TryReadChunk(stream, out PngChunk chunk))
{
if (chunk.Type == PngChunkType.Data)
{
@@ -1418,7 +1424,7 @@ private int ReadNextDataChunk()
///
/// The .
///
- private bool TryReadChunk(out PngChunk chunk)
+ private bool TryReadChunk(BufferedReadStream stream, out PngChunk chunk)
{
if (this.nextChunk != null)
{
@@ -1429,7 +1435,7 @@ private bool TryReadChunk(out PngChunk chunk)
return true;
}
- if (!this.TryReadChunkLength(out int length))
+ if (!this.TryReadChunkLength(stream, out int length))
{
chunk = default;
@@ -1437,10 +1443,10 @@ private bool TryReadChunk(out PngChunk chunk)
return false;
}
- while (length < 0 || length > (this.currentStream.Length - this.currentStream.Position))
+ while (length < 0 || length > (stream.Length - stream.Position))
{
// Not a valid chunk so try again until we reach a known chunk.
- if (!this.TryReadChunkLength(out length))
+ if (!this.TryReadChunkLength(stream, out length))
{
chunk = default;
@@ -1448,7 +1454,7 @@ private bool TryReadChunk(out PngChunk chunk)
}
}
- PngChunkType type = this.ReadChunkType();
+ PngChunkType type = this.ReadChunkType(stream);
// If we're reading color metadata only we're only interested in the IHDR and tRNS chunks.
// We can skip all other chunk data in the stream for better performance.
@@ -1459,19 +1465,19 @@ private bool TryReadChunk(out PngChunk chunk)
return true;
}
- long pos = this.currentStream.Position;
+ long pos = stream.Position;
chunk = new PngChunk(
length: length,
type: type,
- data: this.ReadChunkData(length));
+ data: this.ReadChunkData(stream, length));
- this.ValidateChunk(chunk);
+ this.ValidateChunk(stream, chunk);
// Restore the stream position for IDAT chunks, because it will be decoded later and
// was only read to verifying the CRC is correct.
if (type == PngChunkType.Data)
{
- this.currentStream.Position = pos;
+ stream.Position = pos;
}
return true;
@@ -1481,9 +1487,9 @@ private bool TryReadChunk(out PngChunk chunk)
/// Validates the png chunk.
///
/// The .
- private void ValidateChunk(in PngChunk chunk)
+ private void ValidateChunk(BufferedReadStream stream, in PngChunk chunk)
{
- uint inputCrc = this.ReadChunkCrc();
+ uint inputCrc = this.ReadChunkCrc(stream);
if (chunk.IsCritical)
{
@@ -1491,7 +1497,7 @@ private void ValidateChunk(in PngChunk chunk)
BinaryPrimitives.WriteUInt32BigEndian(chunkType, (uint)chunk.Type);
uint validCrc = Crc32.Calculate(chunkType);
- validCrc = Crc32.Calculate(validCrc, chunk.Data.GetSpan());
+ validCrc = Crc32.Calculate(validCrc, chunk.Data!.GetSpan());
if (validCrc != inputCrc)
{
@@ -1508,10 +1514,10 @@ private void ValidateChunk(in PngChunk chunk)
/// Reads the cycle redundancy chunk from the data.
///
[MethodImpl(InliningOptions.ShortMethod)]
- private uint ReadChunkCrc()
+ private uint ReadChunkCrc(BufferedReadStream stream)
{
uint crc = 0;
- if (this.currentStream.Read(this.buffer, 0, 4) == 4)
+ if (stream.Read(this.buffer, 0, 4) == 4)
{
crc = BinaryPrimitives.ReadUInt32BigEndian(this.buffer);
}
@@ -1524,10 +1530,10 @@ private uint ReadChunkCrc()
///
/// The image format chunk.
[MethodImpl(InliningOptions.ShortMethod)]
- private void SkipChunkDataAndCrc(in PngChunk chunk)
+ private void SkipChunkDataAndCrc(BufferedReadStream stream, in PngChunk chunk)
{
- this.currentStream.Skip(chunk.Length);
- this.currentStream.Skip(4);
+ stream.Skip(chunk.Length);
+ stream.Skip(4);
}
///
@@ -1535,12 +1541,12 @@ private void SkipChunkDataAndCrc(in PngChunk chunk)
///
/// The length of the chunk data to read.
[MethodImpl(InliningOptions.ShortMethod)]
- private IMemoryOwner ReadChunkData(int length)
+ private IMemoryOwner ReadChunkData(BufferedReadStream stream, int length)
{
// We rent the buffer here to return it afterwards in Decode()
IMemoryOwner buffer = this.configuration.MemoryAllocator.Allocate(length, AllocationOptions.Clean);
- this.currentStream.Read(buffer.GetSpan(), 0, length);
+ stream.Read(buffer.GetSpan(), 0, length);
return buffer;
}
@@ -1552,9 +1558,9 @@ private IMemoryOwner ReadChunkData(int length)
/// Thrown if the input stream is not valid.
///
[MethodImpl(InliningOptions.ShortMethod)]
- private PngChunkType ReadChunkType()
+ private PngChunkType ReadChunkType(BufferedReadStream stream)
{
- if (this.currentStream.Read(this.buffer, 0, 4) == 4)
+ if (stream.Read(this.buffer, 0, 4) == 4)
{
return (PngChunkType)BinaryPrimitives.ReadUInt32BigEndian(this.buffer);
}
@@ -1573,9 +1579,9 @@ private PngChunkType ReadChunkType()
/// Whether the length was read.
///
[MethodImpl(InliningOptions.ShortMethod)]
- private bool TryReadChunkLength(out int result)
+ private bool TryReadChunkLength(BufferedReadStream stream, out int result)
{
- if (this.currentStream.Read(this.buffer, 0, 4) == 4)
+ if (stream.Read(this.buffer, 0, 4) == 4)
{
result = BinaryPrimitives.ReadInt32BigEndian(this.buffer);
diff --git a/src/ImageSharp/Formats/Png/PngEncoder.cs b/src/ImageSharp/Formats/Png/PngEncoder.cs
index d769bcbc8d..7856366677 100644
--- a/src/ImageSharp/Formats/Png/PngEncoder.cs
+++ b/src/ImageSharp/Formats/Png/PngEncoder.cs
@@ -31,7 +31,7 @@ public sealed class PngEncoder : IImageEncoder, IPngEncoderOptions
public float? Gamma { get; set; }
///
- public IQuantizer Quantizer { get; set; }
+ public IQuantizer? Quantizer { get; set; }
///
public byte Threshold { get; set; } = byte.MaxValue;
diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs
index c45da6a825..9854c4c5a4 100644
--- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs
+++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs
@@ -3,6 +3,7 @@
using System.Buffers;
using System.Buffers.Binary;
+using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Common.Helpers;
@@ -78,12 +79,12 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable
///
/// The raw data of previous scanline.
///
- private IMemoryOwner previousScanline;
+ private IMemoryOwner? previousScanline;
///
/// The raw data of current scanline.
///
- private IMemoryOwner currentScanline;
+ private IMemoryOwner? currentScanline;
///
/// The color profile name.
@@ -123,7 +124,7 @@ public void Encode(Image image, Stream stream, CancellationToken
PngMetadata pngMetadata = metadata.GetFormatMetadata(PngFormat.Instance);
PngEncoderOptionsHelpers.AdjustOptions(this.options, pngMetadata, out this.use16Bit, out this.bytesPerPixel);
- Image clonedImage = null;
+ Image? clonedImage = null;
bool clearTransparency = this.options.TransparentColorMode == PngTransparentColorMode.Clear;
if (clearTransparency)
{
@@ -131,7 +132,7 @@ public void Encode(Image image, Stream stream, CancellationToken
ClearTransparentPixels(clonedImage);
}
- IndexedImageFrame quantized = this.CreateQuantizedImage(image, clonedImage);
+ IndexedImageFrame? quantized = this.CreateQuantizedImage(image, clonedImage!);
stream.Write(PngConstants.HeaderBytes);
@@ -144,7 +145,7 @@ public void Encode(Image image, Stream stream, CancellationToken
this.WriteExifChunk(stream, metadata);
this.WriteXmpChunk(stream, metadata);
this.WriteTextChunks(stream, pngMetadata);
- this.WriteDataChunks(clearTransparency ? clonedImage : image, quantized, stream);
+ this.WriteDataChunks(clearTransparency ? clonedImage! : image, quantized, stream);
this.WriteEndChunk(stream);
stream.Flush();
@@ -158,8 +159,6 @@ public void Dispose()
{
this.previousScanline?.Dispose();
this.currentScanline?.Dispose();
- this.previousScanline = null;
- this.currentScanline = null;
}
///
@@ -195,10 +194,10 @@ private static void ClearTransparentPixels(Image image)
/// The image to quantize.
/// Cloned image with transparent pixels are changed to black.
/// The quantized image.
- private IndexedImageFrame CreateQuantizedImage(Image image, Image clonedImage)
+ private IndexedImageFrame? CreateQuantizedImage(Image image, Image clonedImage)
where TPixel : unmanaged, IPixel
{
- IndexedImageFrame quantized;
+ IndexedImageFrame? quantized;
if (this.options.TransparentColorMode == PngTransparentColorMode.Clear)
{
quantized = PngEncoderOptionsHelpers.CreateQuantizedFrame(this.options, clonedImage);
@@ -220,6 +219,8 @@ private void CollectGrayscaleBytes(ReadOnlySpan rowSpan)
where TPixel : unmanaged, IPixel
{
ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan);
+ ArgumentNullException.ThrowIfNull(this.currentScanline);
+
Span rawScanlineSpan = this.currentScanline.GetSpan();
ref byte rawScanlineSpanRef = ref MemoryMarshal.GetReference(rawScanlineSpan);
@@ -302,6 +303,7 @@ private void CollectGrayscaleBytes(ReadOnlySpan rowSpan)
private void CollectTPixelBytes(ReadOnlySpan rowSpan)
where TPixel : unmanaged, IPixel
{
+ ArgumentNullException.ThrowIfNull(this.currentScanline);
Span rawScanlineSpan = this.currentScanline.GetSpan();
switch (this.bytesPerPixel)
@@ -379,20 +381,22 @@ private void CollectTPixelBytes(ReadOnlySpan rowSpan)
/// The row span.
/// The quantized pixels. Can be null.
/// The row.
- private void CollectPixelBytes(ReadOnlySpan rowSpan, IndexedImageFrame quantized, int row)
+ private void CollectPixelBytes(ReadOnlySpan rowSpan, IndexedImageFrame? quantized, int row)
where TPixel : unmanaged, IPixel
{
switch (this.options.ColorType)
{
case PngColorType.Palette:
+ ArgumentNullException.ThrowIfNull(this.currentScanline);
+
if (this.bitDepth < 8)
{
- PngEncoderHelpers.ScaleDownFrom8BitArray(quantized.DangerousGetRowSpan(row), this.currentScanline.GetSpan(), this.bitDepth);
+ PngEncoderHelpers.ScaleDownFrom8BitArray(quantized!.DangerousGetRowSpan(row), this.currentScanline.GetSpan(), this.bitDepth);
}
else
{
- quantized.DangerousGetRowSpan(row).CopyTo(this.currentScanline.GetSpan());
+ quantized?.DangerousGetRowSpan(row).CopyTo(this.currentScanline.GetSpan());
}
break;
@@ -413,6 +417,9 @@ private void CollectPixelBytes(ReadOnlySpan rowSpan, IndexedImag
/// Used for attempting optimized filtering.
private void FilterPixelBytes(ref Span filter, ref Span attempt)
{
+ ArgumentNullException.ThrowIfNull(this.previousScanline);
+ ArgumentNullException.ThrowIfNull(this.currentScanline);
+
switch (this.options.FilterMethod)
{
case PngFilterMethod.None:
@@ -453,7 +460,7 @@ private void CollectAndFilterPixelRow(
ReadOnlySpan rowSpan,
ref Span filter,
ref Span attempt,
- IndexedImageFrame quantized,
+ IndexedImageFrame? quantized,
int row)
where TPixel : unmanaged, IPixel
{
@@ -472,6 +479,8 @@ private void EncodeAdam7IndexedPixelRow(
ref Span filter,
ref Span attempt)
{
+ ArgumentNullException.ThrowIfNull(this.currentScanline);
+
// CollectPixelBytes
if (this.bitDepth < 8)
{
@@ -493,6 +502,9 @@ private void EncodeAdam7IndexedPixelRow(
/// Used for attempting optimized filtering.
private void ApplyOptimalFilteredScanline(ref Span filter, ref Span attempt)
{
+ ArgumentNullException.ThrowIfNull(this.previousScanline);
+ ArgumentNullException.ThrowIfNull(this.currentScanline);
+
// Palette images don't compress well with adaptive filtering.
// Nor do images comprising a single row.
if (this.options.ColorType == PngColorType.Palette || this.height == 1 || this.bitDepth < 8)
@@ -543,10 +555,10 @@ private void WriteHeaderChunk(Stream stream)
width: this.width,
height: this.height,
bitDepth: this.bitDepth,
- colorType: this.options.ColorType.Value,
+ colorType: this.options.ColorType!.Value,
compressionMethod: 0, // None
filterMethod: 0,
- interlaceMethod: this.options.InterlaceMethod.Value);
+ interlaceMethod: this.options.InterlaceMethod!.Value);
header.WriteTo(this.chunkDataBuffer);
@@ -560,7 +572,7 @@ private void WriteHeaderChunk(Stream stream)
/// The pixel format.
/// The containing image data.
/// The quantized frame.
- private void WritePaletteChunk(Stream stream, IndexedImageFrame quantized)
+ private void WritePaletteChunk(Stream stream, IndexedImageFrame? quantized)
where TPixel : unmanaged, IPixel
{
if (quantized is null)
@@ -668,9 +680,9 @@ private void WriteXmpChunk(Stream stream, ImageMetadata meta)
return;
}
- byte[] xmpData = meta.XmpProfile.Data;
+ byte[]? xmpData = meta.XmpProfile.Data;
- if (xmpData.Length == 0)
+ if (xmpData!.Length == 0)
{
return;
}
@@ -916,7 +928,7 @@ private void WriteTransparencyChunk(Stream stream, PngMetadata pngMetadata)
/// The image.
/// The quantized pixel data. Can be null.
/// The stream.
- private void WriteDataChunks(Image pixels, IndexedImageFrame quantized, Stream stream)
+ private void WriteDataChunks(Image pixels, IndexedImageFrame? quantized, Stream stream)
where TPixel : unmanaged, IPixel
{
byte[] buffer;
@@ -973,6 +985,8 @@ private void WriteDataChunks(Image pixels, IndexedImageFrame
/// The bytes per scanline.
+ [MemberNotNull(nameof(currentScanline))]
+ [MemberNotNull(nameof(previousScanline))]
private void AllocateScanlineBuffers(int bytesPerScanline)
{
// Clean up from any potential previous runs.
@@ -989,7 +1003,7 @@ private void AllocateScanlineBuffers(int bytesPerScanline)
/// The pixels.
/// The quantized pixels span.
/// The deflate stream.
- private void EncodePixels(Image pixels, IndexedImageFrame quantized, ZlibDeflateStream deflateStream)
+ private void EncodePixels(Image pixels, IndexedImageFrame? quantized, ZlibDeflateStream deflateStream)
where TPixel : unmanaged, IPixel
{
int bytesPerScanline = this.CalculateScanlineLength(this.width);
@@ -1023,7 +1037,7 @@ private void EncodeAdam7Pixels(Image image, ZlibDeflateStream de
{
int width = image.Width;
int height = image.Height;
- Buffer2D pixelBuffer = image.Frames.RootFrame.PixelBuffer;
+ Buffer2D pixelBuffer = image.Frames.RootFrame.PixelBuffer!;
for (int pass = 0; pass < 7; pass++)
{
int startRow = Adam7.FirstRow[pass];
@@ -1188,8 +1202,11 @@ private int CalculateScanlineLength(int width)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void SwapScanlineBuffers()
{
- ref IMemoryOwner prev = ref this.previousScanline;
- ref IMemoryOwner current = ref this.currentScanline;
+ ArgumentNullException.ThrowIfNull(this.previousScanline);
+ ArgumentNullException.ThrowIfNull(this.currentScanline);
+
+ ref IMemoryOwner? prev = ref this.previousScanline;
+ ref IMemoryOwner? current = ref this.currentScanline;
RuntimeUtility.Swap(ref prev, ref current);
}
}
diff --git a/src/ImageSharp/Formats/Png/PngEncoderOptions.cs b/src/ImageSharp/Formats/Png/PngEncoderOptions.cs
index 7fe27b78d7..c58fc65767 100644
--- a/src/ImageSharp/Formats/Png/PngEncoderOptions.cs
+++ b/src/ImageSharp/Formats/Png/PngEncoderOptions.cs
@@ -49,7 +49,7 @@ public PngEncoderOptions(IPngEncoderOptions source)
public float? Gamma { get; set; }
///
- public IQuantizer Quantizer { get; set; }
+ public IQuantizer? Quantizer { get; set; }
///
public byte Threshold { get; }
diff --git a/src/ImageSharp/Formats/Png/PngEncoderOptionsHelpers.cs b/src/ImageSharp/Formats/Png/PngEncoderOptionsHelpers.cs
index e1ee61c378..65b9dedae2 100644
--- a/src/ImageSharp/Formats/Png/PngEncoderOptionsHelpers.cs
+++ b/src/ImageSharp/Formats/Png/PngEncoderOptionsHelpers.cs
@@ -72,7 +72,7 @@ public static void AdjustOptions(
/// The type of the pixel.
/// The options.
/// The image.
- public static IndexedImageFrame CreateQuantizedFrame(
+ public static IndexedImageFrame? CreateQuantizedFrame(
PngEncoderOptions options,
Image image)
where TPixel : unmanaged, IPixel
@@ -85,7 +85,7 @@ public static IndexedImageFrame CreateQuantizedFrame(
// Use the metadata to determine what quantization depth to use if no quantizer has been set.
if (options.Quantizer is null)
{
- byte bits = (byte)options.BitDepth;
+ byte bits = (byte)options.BitDepth!;
var maxColors = ColorNumerics.GetColorCountForBitDepth(bits);
options.Quantizer = new WuQuantizer(new QuantizerOptions { MaxColors = maxColors });
}
@@ -106,14 +106,14 @@ public static IndexedImageFrame CreateQuantizedFrame(
/// The quantized frame.
public static byte CalculateBitDepth(
PngEncoderOptions options,
- IndexedImageFrame quantizedFrame)
+ IndexedImageFrame? quantizedFrame)
where TPixel : unmanaged, IPixel
{
byte bitDepth;
if (options.ColorType == PngColorType.Palette)
{
- byte quantizedBits = (byte)Numerics.Clamp(ColorNumerics.GetBitsNeededForColorDepth(quantizedFrame.Palette.Length), 1, 8);
- byte bits = Math.Max((byte)options.BitDepth, quantizedBits);
+ byte quantizedBits = (byte)Numerics.Clamp(ColorNumerics.GetBitsNeededForColorDepth(quantizedFrame!.Palette.Length), 1, 8);
+ byte bits = Math.Max((byte)options.BitDepth!, quantizedBits);
// Png only supports in four pixel depths: 1, 2, 4, and 8 bits when using the PLTE chunk
// We check again for the bit depth as the bit depth of the color palette from a given quantizer might not
@@ -131,10 +131,10 @@ public static byte CalculateBitDepth(
}
else
{
- bitDepth = (byte)options.BitDepth;
+ bitDepth = (byte)options.BitDepth!;
}
- if (Array.IndexOf(PngConstants.ColorTypes[options.ColorType.Value], bitDepth) == -1)
+ if (Array.IndexOf(PngConstants.ColorTypes[options.ColorType!.Value], bitDepth) == -1)
{
throw new NotSupportedException("Bit depth is not supported or not valid.");
}
diff --git a/src/ImageSharp/Formats/Png/PngHeader.cs b/src/ImageSharp/Formats/Png/PngHeader.cs
index cee1017f12..559432a99d 100644
--- a/src/ImageSharp/Formats/Png/PngHeader.cs
+++ b/src/ImageSharp/Formats/Png/PngHeader.cs
@@ -87,7 +87,7 @@ public PngHeader(
///
public void Validate()
{
- if (!PngConstants.ColorTypes.TryGetValue(this.ColorType, out byte[] supportedBitDepths))
+ if (!PngConstants.ColorTypes.TryGetValue(this.ColorType, out byte[]? supportedBitDepths))
{
throw new NotSupportedException($"Invalid or unsupported color type. Was '{this.ColorType}'.");
}
diff --git a/src/ImageSharp/Formats/Png/PngImageFormatDetector.cs b/src/ImageSharp/Formats/Png/PngImageFormatDetector.cs
index 907898e17f..2e20668248 100644
--- a/src/ImageSharp/Formats/Png/PngImageFormatDetector.cs
+++ b/src/ImageSharp/Formats/Png/PngImageFormatDetector.cs
@@ -14,7 +14,7 @@ public sealed class PngImageFormatDetector : IImageFormatDetector
public int HeaderSize => 8;
///
- public IImageFormat DetectFormat(ReadOnlySpan header)
+ public IImageFormat? DetectFormat(ReadOnlySpan header)
{
return this.IsSupportedFileFormat(header) ? PngFormat.Instance : null;
}
diff --git a/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs
index cf77788bc0..af09f4d1af 100644
--- a/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs
+++ b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs
@@ -236,7 +236,7 @@ public static void ProcessPaletteScanline(
ReadOnlySpan scanlineSpan,
Span rowSpan,
ReadOnlySpan palette,
- byte[] paletteAlpha)
+ byte[]? paletteAlpha)
where TPixel : unmanaged, IPixel
{
if (palette.IsEmpty)
@@ -287,7 +287,7 @@ public static void ProcessInterlacedPaletteScanline(
int pixelOffset,
int increment,
ReadOnlySpan palette,
- byte[] paletteAlpha)
+ byte[]? paletteAlpha)
where TPixel : unmanaged, IPixel
{
TPixel pixel = default;
diff --git a/src/ImageSharp/Formats/Png/PngTextData.cs b/src/ImageSharp/Formats/Png/PngTextData.cs
index af2ba4b1db..8ef4f1821d 100644
--- a/src/ImageSharp/Formats/Png/PngTextData.cs
+++ b/src/ImageSharp/Formats/Png/PngTextData.cs
@@ -98,7 +98,7 @@ public PngTextData(string keyword, string value, string languageTag, string tran
/// true if and this instance are the same type and represent the
/// same value; otherwise, false.
///
- public override bool Equals(object obj)
+ public override bool Equals(object? obj)
=> obj is PngTextData other && this.Equals(other);
///
diff --git a/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs b/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs
index efb61610c2..1bc6a16b02 100644
--- a/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs
+++ b/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs
@@ -2,6 +2,7 @@
// Licensed under the Six Labors Split License.
using System.Buffers;
+using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.IO;
using SixLabors.ImageSharp.Memory;
@@ -28,12 +29,12 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
///
/// The metadata.
///
- private ImageMetadata metadata;
+ private ImageMetadata? metadata;
///
/// The tga specific metadata.
///
- private TgaMetadata tgaMetadata;
+ private TgaMetadata? tgaMetadata;
///
/// The file header containing general information about the image.
@@ -45,11 +46,6 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
///
private readonly MemoryAllocator memoryAllocator;
- ///
- /// The stream to decode from.
- ///
- private BufferedReadStream currentStream;
-
///
/// Indicates whether there is a alpha channel present.
///
@@ -70,7 +66,7 @@ public TgaDecoderCore(DecoderOptions options)
public DecoderOptions Options { get; }
///
- public Size Dimensions => new(this.fileHeader.Width, this.fileHeader.Height);
+ public Size? Dimensions => new(this.fileHeader.Width, this.fileHeader.Height);
///
public Image Decode(BufferedReadStream stream, CancellationToken cancellationToken)
@@ -79,7 +75,7 @@ public Image Decode(BufferedReadStream stream, CancellationToken
try
{
TgaImageOrigin origin = this.ReadFileHeader(stream);
- this.currentStream.Skip(this.fileHeader.IdLength);
+ stream.Skip(this.fileHeader.IdLength);
// Parse the color map, if present.
if (this.fileHeader.ColorMapType is not 0 and not 1)
@@ -112,7 +108,7 @@ public Image Decode(BufferedReadStream stream, CancellationToken
using (IMemoryOwner palette = this.memoryAllocator.Allocate(colorMapSizeInBytes, AllocationOptions.Clean))
{
Span paletteSpan = palette.GetSpan();
- int bytesRead = this.currentStream.Read(paletteSpan, this.fileHeader.CMapStart, colorMapSizeInBytes);
+ int bytesRead = stream.Read(paletteSpan, this.fileHeader.CMapStart, colorMapSizeInBytes);
if (bytesRead != colorMapSizeInBytes)
{
TgaThrowHelper.ThrowInvalidImageContentException("Not enough data to read the color map");
@@ -121,6 +117,7 @@ public Image Decode(BufferedReadStream stream, CancellationToken
if (this.fileHeader.ImageType == TgaImageType.RleColorMapped)
{
this.ReadPalettedRle(
+ stream,
this.fileHeader.Width,
this.fileHeader.Height,
pixels,
@@ -131,6 +128,7 @@ public Image Decode(BufferedReadStream stream, CancellationToken
else
{
this.ReadPaletted(
+ stream,
this.fileHeader.Width,
this.fileHeader.Height,
pixels,
@@ -147,7 +145,7 @@ public Image Decode(BufferedReadStream stream, CancellationToken
if (this.fileHeader.CMapLength > 0)
{
int colorMapPixelSizeInBytes = this.fileHeader.CMapDepth / 8;
- this.currentStream.Skip(this.fileHeader.CMapLength * colorMapPixelSizeInBytes);
+ stream.Skip(this.fileHeader.CMapLength * colorMapPixelSizeInBytes);
}
switch (this.fileHeader.PixelDepth)
@@ -155,11 +153,11 @@ public Image Decode(BufferedReadStream stream, CancellationToken
case 8:
if (this.fileHeader.ImageType.IsRunLengthEncoded())
{
- this.ReadRle(this.fileHeader.Width, this.fileHeader.Height, pixels, 1, origin);
+ this.ReadRle(stream, this.fileHeader.Width, this.fileHeader.Height, this.tgaMetadata.AlphaChannelBits, pixels, 1, origin);
}
else
{
- this.ReadMonoChrome(this.fileHeader.Width, this.fileHeader.Height, pixels, origin);
+ this.ReadMonoChrome(stream, this.fileHeader.Width, this.fileHeader.Height, pixels, origin);
}
break;
@@ -168,11 +166,11 @@ public Image Decode(BufferedReadStream stream, CancellationToken
case 16:
if (this.fileHeader.ImageType.IsRunLengthEncoded())
{
- this.ReadRle(this.fileHeader.Width, this.fileHeader.Height, pixels, 2, origin);
+ this.ReadRle(stream, this.fileHeader.Width, this.fileHeader.Height, this.tgaMetadata.AlphaChannelBits, pixels, 2, origin);
}
else
{
- this.ReadBgra16(this.fileHeader.Width, this.fileHeader.Height, pixels, origin);
+ this.ReadBgra16(this.fileHeader.Width, this.fileHeader.Height, stream, pixels, origin);
}
break;
@@ -180,11 +178,11 @@ public Image Decode(BufferedReadStream stream, CancellationToken
case 24:
if (this.fileHeader.ImageType.IsRunLengthEncoded())
{
- this.ReadRle(this.fileHeader.Width, this.fileHeader.Height, pixels, 3, origin);
+ this.ReadRle(stream, this.fileHeader.Width, this.fileHeader.Height, this.tgaMetadata.AlphaChannelBits, pixels, 3, origin);
}
else
{
- this.ReadBgr24(this.fileHeader.Width, this.fileHeader.Height, pixels, origin);
+ this.ReadBgr24(stream, this.fileHeader.Width, this.fileHeader.Height, pixels, origin);
}
break;
@@ -192,11 +190,11 @@ public Image Decode(BufferedReadStream stream, CancellationToken
case 32:
if (this.fileHeader.ImageType.IsRunLengthEncoded())
{
- this.ReadRle(this.fileHeader.Width, this.fileHeader.Height, pixels, 4, origin);
+ this.ReadRle(stream, this.fileHeader.Width, this.fileHeader.Height, this.tgaMetadata.AlphaChannelBits, pixels, 4, origin);
}
else
{
- this.ReadBgra32(this.fileHeader.Width, this.fileHeader.Height, pixels, origin);
+ this.ReadBgra32(stream, this.fileHeader.Width, this.fileHeader.Height, this.tgaMetadata.AlphaChannelBits, pixels, origin);
}
break;
@@ -224,7 +222,7 @@ public Image Decode(BufferedReadStream stream, CancellationToken
/// The color palette.
/// Color map size of one entry in bytes.
/// The image origin.
- private void ReadPaletted(int width, int height, Buffer2D pixels, Span palette, int colorMapPixelSizeInBytes, TgaImageOrigin origin)
+ private void ReadPaletted(BufferedReadStream stream, int width, int height, Buffer2D pixels, Span palette, int colorMapPixelSizeInBytes, TgaImageOrigin origin)
where TPixel : unmanaged, IPixel
{
TPixel color = default;
@@ -242,14 +240,14 @@ private void ReadPaletted(int width, int height, Buffer2D pixels
{
for (int x = width - 1; x >= 0; x--)
{
- this.ReadPalettedBgra16Pixel(palette, colorMapPixelSizeInBytes, x, color, pixelRow);
+ this.ReadPalettedBgra16Pixel(stream, palette, colorMapPixelSizeInBytes, x, color, pixelRow);
}
}
else
{
for (int x = 0; x < width; x++)
{
- this.ReadPalettedBgra16Pixel(palette, colorMapPixelSizeInBytes, x, color, pixelRow);
+ this.ReadPalettedBgra16Pixel(stream, palette, colorMapPixelSizeInBytes, x, color, pixelRow);
}
}
@@ -260,14 +258,14 @@ private void ReadPaletted(int width, int height, Buffer2D pixels
{
for (int x = width - 1; x >= 0; x--)
{
- this.ReadPalettedBgr24Pixel(palette, colorMapPixelSizeInBytes, x, color, pixelRow);
+ this.ReadPalettedBgr24Pixel(stream, palette, colorMapPixelSizeInBytes, x, color, pixelRow);
}
}
else
{
for (int x = 0; x < width; x++)
{
- this.ReadPalettedBgr24Pixel(palette, colorMapPixelSizeInBytes, x, color, pixelRow);
+ this.ReadPalettedBgr24Pixel(stream, palette, colorMapPixelSizeInBytes, x, color, pixelRow);
}
}
@@ -278,14 +276,14 @@ private void ReadPaletted