diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs
index 8c5915800..0ccbe3db5 100644
--- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs
+++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs
@@ -1,8 +1,8 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
using System.Buffers;
+using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
@@ -24,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.
@@ -77,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.
@@ -108,8 +103,8 @@ internal sealed class GifDecoderCore : IImageDecoderInternals
where TPixel : unmanaged, IPixel
{
uint frameCount = 0;
- Image image = null;
- ImageFrame previousFrame = null;
+ Image? image = null;
+ ImageFrame? previousFrame = null;
try
{
this.ReadLogicalScreenDescriptorAndGlobalColorTable(stream);
@@ -125,7 +120,7 @@ internal sealed class GifDecoderCore : IImageDecoderInternals
break;
}
- this.ReadFrame(ref image, ref previousFrame);
+ this.ReadFrame(stream, ref image, ref previousFrame);
// Reset per-frame state.
this.imageDescriptor = default;
@@ -136,16 +131,16 @@ internal sealed class GifDecoderCore : IImageDecoderInternals
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;
}
}
@@ -187,23 +182,23 @@ internal sealed class GifDecoderCore : IImageDecoderInternals
{
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;
}
}
@@ -239,9 +234,10 @@ internal sealed class GifDecoderCore : IImageDecoderInternals
///
/// Reads the graphic control extension.
///
- private void ReadGraphicalControlExtension()
+ /// The containing image data.
+ 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");
@@ -253,9 +249,10 @@ internal sealed class GifDecoderCore : IImageDecoderInternals
///
/// Reads the image descriptor.
///
- private void ReadImageDescriptor()
+ /// The containing image data.
+ 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");
@@ -271,9 +268,10 @@ internal sealed class GifDecoderCore : IImageDecoderInternals
///
/// Reads the logical screen descriptor.
///
- private void ReadLogicalScreenDescriptor()
+ /// The containing image data.
+ 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");
@@ -286,84 +284,87 @@ internal sealed class GifDecoderCore : IImageDecoderInternals
/// Reads the application extension block parsing any animation or XMP information
/// if present.
///
- private void ReadApplicationExtension()
+ /// The containing image data.
+ 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.
- long position = this.stream.Position;
+ long position = stream.Position;
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)
{
- GifXmpApplicationExtension extension = GifXmpApplicationExtension.Read(this.stream, this.memoryAllocator);
+ GifXmpApplicationExtension extension = GifXmpApplicationExtension.Read(stream, this.memoryAllocator);
if (extension.Data.Length > 0)
{
- this.metadata.XmpProfile = new XmpProfile(extension.Data);
+ this.metadata!.XmpProfile = new XmpProfile(extension.Data);
}
else
{
// Reset the stream position and continue.
- this.stream.Position = position;
- this.SkipBlock(appLength);
+ stream.Position = position;
+ this.SkipBlock(stream, appLength);
}
return;
}
- 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);
- this.gifMetadata.RepeatCount = GifNetscapeLoopingApplicationExtension.Parse(this.buffer.AsSpan(1)).RepeatCount;
- this.stream.Skip(1); // Skip the terminator.
+ stream.Read(this.buffer, 0, GifConstants.NetscapeLoopingSubBlockSize);
+ this.gifMetadata!.RepeatCount = GifNetscapeLoopingApplicationExtension.Parse(this.buffer.AsSpan(1)).RepeatCount;
+ 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.
+ /// The containing image data.
///
- 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()
+ /// The containing image data.
+ 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)
{
@@ -372,21 +373,21 @@ internal sealed class GifDecoderCore : IImageDecoderInternals
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)
{
- this.gifMetadata.Comments.Add(stringBuilder.ToString());
+ this.gifMetadata!.Comments.Add(stringBuilder.ToString());
}
}
@@ -394,15 +395,16 @@ internal sealed class GifDecoderCore : IImageDecoderInternals
/// Reads an individual gif frame.
///
/// The pixel format.
+ /// The containing image data.
/// The image to decode the information to.
/// The previous frame.
- private void ReadFrame(ref Image image, ref ImageFrame previousFrame)
+ private void ReadFrame(BufferedReadStream stream, ref Image? image, ref ImageFrame? previousFrame)
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.
@@ -410,11 +412,11 @@ internal sealed class GifDecoderCore : IImageDecoderInternals
{
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(stream, indices);
Span rawColorTable = default;
if (localColorTable != null)
@@ -430,7 +432,7 @@ internal sealed class GifDecoderCore : IImageDecoderInternals
this.ReadFrameColors(ref image, ref previousFrame, indices, colorTable, this.imageDescriptor);
// Skip any remaining blocks
- this.SkipBlock();
+ this.SkipBlock(stream);
}
finally
{
@@ -442,12 +444,13 @@ internal sealed class GifDecoderCore : IImageDecoderInternals
///
/// Reads the frame indices marking the color to use for each pixel.
///
+ /// The containing image data.
/// The 2D pixel buffer to write to.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void ReadFrameIndices(Buffer2D indices)
+ private void ReadFrameIndices(BufferedReadStream stream, Buffer2D indices)
{
- int minCodeSize = this.stream.ReadByte();
- using var lzwDecoder = new LzwDecoder(this.configuration.MemoryAllocator, this.stream);
+ int minCodeSize = stream.ReadByte();
+ using LzwDecoder lzwDecoder = new LzwDecoder(this.configuration.MemoryAllocator, stream);
lzwDecoder.DecodePixels(minCodeSize, indices);
}
@@ -460,15 +463,15 @@ internal sealed class GifDecoderCore : IImageDecoderInternals
/// 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)
@@ -494,7 +497,7 @@ internal sealed class GifDecoderCore : IImageDecoderInternals
prevFrame = previousFrame;
}
- currentFrame = image.Frames.CreateFrame();
+ currentFrame = image!.Frames.CreateFrame();
this.SetFrameMetadata(currentFrame.Metadata, false);
@@ -661,13 +664,13 @@ internal sealed class GifDecoderCore : IImageDecoderInternals
/// 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);
ImageMetadata meta = new();
diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs
index eaa685293..0e59a0f05 100644
--- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs
+++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs
@@ -1,8 +1,8 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-#nullable disable
using System.Buffers;
+using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Advanced;
@@ -93,7 +93,7 @@ internal sealed class GifEncoderCore : IImageEncoderInternals
bool useGlobalTable = this.colorTableMode == GifColorTableMode.Global;
// Quantize the image returning a palette.
- IndexedImageFrame quantized;
+ IndexedImageFrame? quantized;
using (IQuantizer frameQuantizer = this.quantizer.CreatePixelSpecificQuantizer(this.configuration))
{
if (useGlobalTable)
@@ -129,7 +129,7 @@ internal sealed class GifEncoderCore : IImageEncoderInternals
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);
}
@@ -141,7 +141,7 @@ internal sealed class GifEncoderCore : IImageEncoderInternals
private void EncodeFrames(
Stream stream,
Image image,
- IndexedImageFrame quantized,
+ IndexedImageFrame? quantized,
ReadOnlyMemory palette)
where TPixel : unmanaged, IPixel
{
@@ -152,8 +152,8 @@ internal sealed class GifEncoderCore : IImageEncoderInternals
// Gather the metadata for this frame.
ImageFrame frame = image.Frames[i];
ImageFrameMetadata metadata = frame.Metadata;
- bool hasMetadata = metadata.TryGetGifMetadata(out GifFrameMetadata frameMetadata);
- bool useLocal = this.colorTableMode == GifColorTableMode.Local || (hasMetadata && frameMetadata.ColorTableMode == GifColorTableMode.Local);
+ bool hasMetadata = metadata.TryGetGifMetadata(out GifFrameMetadata? frameMetadata);
+ bool useLocal = this.colorTableMode == GifColorTableMode.Local || (hasMetadata && frameMetadata!.ColorTableMode == GifColorTableMode.Local);
if (!useLocal && !hasPaletteQuantizer && i > 0)
{
@@ -164,7 +164,7 @@ internal sealed class GifEncoderCore : IImageEncoderInternals
paletteQuantizer = new(this.configuration, this.quantizer.Options, palette);
}
- this.EncodeFrame(stream, frame, i, useLocal, frameMetadata, ref quantized, ref paletteQuantizer);
+ this.EncodeFrame(stream, frame, i, useLocal, frameMetadata, ref quantized!, ref paletteQuantizer);
// Clean up for the next run.
quantized.Dispose();
@@ -182,7 +182,7 @@ internal sealed class GifEncoderCore : IImageEncoderInternals
ImageFrame frame,
int frameIndex,
bool useLocal,
- GifFrameMetadata metadata,
+ GifFrameMetadata? metadata,
ref IndexedImageFrame quantized,
ref PaletteQuantizer paletteQuantizer)
where TPixel : unmanaged, IPixel
@@ -193,7 +193,7 @@ internal sealed class GifEncoderCore : IImageEncoderInternals
if (useLocal)
{
// Reassign using the current frame and details.
- QuantizerOptions options = null;
+ QuantizerOptions? options = null;
int colorTableLength = metadata?.ColorTableLength ?? 0;
if (colorTableLength > 0)
{
@@ -338,7 +338,7 @@ internal sealed class GifEncoderCore : IImageEncoderInternals
/// 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)
@@ -350,7 +350,7 @@ internal sealed class GifEncoderCore : IImageEncoderInternals
// Application Extension: XMP Profile.
if (xmpProfile != null)
{
- GifXmpApplicationExtension xmpExtension = new(xmpProfile.Data);
+ GifXmpApplicationExtension xmpExtension = new(xmpProfile.Data!);
this.WriteExtension(xmpExtension, stream);
}
}
@@ -439,7 +439,7 @@ internal sealed class GifEncoderCore : IImageEncoderInternals
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/Image.Decode.cs b/src/ImageSharp/Image.Decode.cs
index ae38144c0..887cb23ca 100644
--- a/src/ImageSharp/Image.Decode.cs
+++ b/src/ImageSharp/Image.Decode.cs
@@ -91,7 +91,7 @@ public abstract partial class Image
ImageFormatManager.ThrowInvalidDecoder(configuration.ImageFormatsManager);
}
- return format!;
+ return format;
}
///
diff --git a/src/ImageSharp/Image.cs b/src/ImageSharp/Image.cs
index 65b2d68b0..af1b1916f 100644
--- a/src/ImageSharp/Image.cs
+++ b/src/ImageSharp/Image.cs
@@ -28,7 +28,7 @@ public abstract partial class Image : ImageInfo, IDisposable, IConfigurationProv
/// The pixel type information.
/// The image metadata.
/// The size in px units.
- protected Image(Configuration configuration, PixelTypeInfo pixelType, ImageMetadata metadata, Size size)
+ protected Image(Configuration configuration, PixelTypeInfo pixelType, ImageMetadata? metadata, Size size)
: base(pixelType, size, metadata)
=> this.configuration = configuration ?? Configuration.Default;
@@ -43,7 +43,7 @@ public abstract partial class Image : ImageInfo, IDisposable, IConfigurationProv
internal Image(
Configuration configuration,
PixelTypeInfo pixelType,
- ImageMetadata metadata,
+ ImageMetadata? metadata,
int width,
int height)
: this(configuration, pixelType, metadata, new Size(width, height))
diff --git a/src/ImageSharp/ImageInfo.cs b/src/ImageSharp/ImageInfo.cs
index 9a6452ab8..fdc15a812 100644
--- a/src/ImageSharp/ImageInfo.cs
+++ b/src/ImageSharp/ImageInfo.cs
@@ -18,7 +18,7 @@ public class ImageInfo
/// The width of the image in px units.
/// The height of the image in px units.
/// The image metadata.
- public ImageInfo(PixelTypeInfo pixelType, int width, int height, ImageMetadata metadata)
+ public ImageInfo(PixelTypeInfo pixelType, int width, int height, ImageMetadata? metadata)
: this(pixelType, new(width, height), metadata)
{
}
@@ -29,7 +29,7 @@ public class ImageInfo
/// The pixel type information.
/// The size of the image in px units.
/// The image metadata.
- public ImageInfo(PixelTypeInfo pixelType, Size size, ImageMetadata metadata)
+ public ImageInfo(PixelTypeInfo pixelType, Size size, ImageMetadata? metadata)
{
this.PixelType = pixelType;
this.Metadata = metadata ?? new ImageMetadata();
diff --git a/src/ImageSharp/Image{TPixel}.cs b/src/ImageSharp/Image{TPixel}.cs
index 9e3cc065c..ed0db9b85 100644
--- a/src/ImageSharp/Image{TPixel}.cs
+++ b/src/ImageSharp/Image{TPixel}.cs
@@ -77,7 +77,7 @@ public sealed class Image : Image
/// The width of the image in pixels.
/// The height of the image in pixels.
/// The images metadata.
- internal Image(Configuration configuration, int width, int height, ImageMetadata metadata)
+ internal Image(Configuration configuration, int width, int height, ImageMetadata? metadata)
: base(configuration, PixelTypeInfo.Create(), metadata, width, height)
=> this.frames = new ImageFrameCollection(this, width, height, default(TPixel));
@@ -128,7 +128,7 @@ public sealed class Image : Image
int width,
int height,
TPixel backgroundColor,
- ImageMetadata metadata)
+ ImageMetadata? metadata)
: base(configuration, PixelTypeInfo.Create(), metadata, width, height)
=> this.frames = new ImageFrameCollection(this, width, height, backgroundColor);