Browse Source

remove nullable disable from format gif

pull/2346/head
Stefan Nikolei 3 years ago
parent
commit
94fd43f71f
  1. 139
      src/ImageSharp/Formats/Gif/GifDecoderCore.cs
  2. 24
      src/ImageSharp/Formats/Gif/GifEncoderCore.cs
  3. 2
      src/ImageSharp/Image.Decode.cs
  4. 4
      src/ImageSharp/Image.cs
  5. 4
      src/ImageSharp/ImageInfo.cs
  6. 4
      src/ImageSharp/Image{TPixel}.cs

139
src/ImageSharp/Formats/Gif/GifDecoderCore.cs

@ -1,8 +1,8 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
#nullable disable
using System.Buffers; using System.Buffers;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text; using System.Text;
@ -24,15 +24,10 @@ internal sealed class GifDecoderCore : IImageDecoderInternals
/// </summary> /// </summary>
private readonly byte[] buffer = new byte[16]; private readonly byte[] buffer = new byte[16];
/// <summary>
/// The currently loaded stream.
/// </summary>
private BufferedReadStream stream;
/// <summary> /// <summary>
/// The global color table. /// The global color table.
/// </summary> /// </summary>
private IMemoryOwner<byte> globalColorTable; private IMemoryOwner<byte>? globalColorTable;
/// <summary> /// <summary>
/// The area to restore. /// The area to restore.
@ -77,12 +72,12 @@ internal sealed class GifDecoderCore : IImageDecoderInternals
/// <summary> /// <summary>
/// The abstract metadata. /// The abstract metadata.
/// </summary> /// </summary>
private ImageMetadata metadata; private ImageMetadata? metadata;
/// <summary> /// <summary>
/// The gif specific metadata. /// The gif specific metadata.
/// </summary> /// </summary>
private GifMetadata gifMetadata; private GifMetadata? gifMetadata;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="GifDecoderCore"/> class. /// Initializes a new instance of the <see cref="GifDecoderCore"/> class.
@ -108,8 +103,8 @@ internal sealed class GifDecoderCore : IImageDecoderInternals
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
uint frameCount = 0; uint frameCount = 0;
Image<TPixel> image = null; Image<TPixel>? image = null;
ImageFrame<TPixel> previousFrame = null; ImageFrame<TPixel>? previousFrame = null;
try try
{ {
this.ReadLogicalScreenDescriptorAndGlobalColorTable(stream); this.ReadLogicalScreenDescriptorAndGlobalColorTable(stream);
@ -125,7 +120,7 @@ internal sealed class GifDecoderCore : IImageDecoderInternals
break; break;
} }
this.ReadFrame(ref image, ref previousFrame); this.ReadFrame(stream, ref image, ref previousFrame);
// Reset per-frame state. // Reset per-frame state.
this.imageDescriptor = default; this.imageDescriptor = default;
@ -136,16 +131,16 @@ internal sealed class GifDecoderCore : IImageDecoderInternals
switch (stream.ReadByte()) switch (stream.ReadByte())
{ {
case GifConstants.GraphicControlLabel: case GifConstants.GraphicControlLabel:
this.ReadGraphicalControlExtension(); this.ReadGraphicalControlExtension(stream);
break; break;
case GifConstants.CommentLabel: case GifConstants.CommentLabel:
this.ReadComments(); this.ReadComments(stream);
break; break;
case GifConstants.ApplicationExtensionLabel: case GifConstants.ApplicationExtensionLabel:
this.ReadApplicationExtension(); this.ReadApplicationExtension(stream);
break; break;
case GifConstants.PlainTextLabel: case GifConstants.PlainTextLabel:
this.SkipBlock(); // Not supported by any known decoder. this.SkipBlock(stream); // Not supported by any known decoder.
break; break;
} }
} }
@ -187,23 +182,23 @@ internal sealed class GifDecoderCore : IImageDecoderInternals
{ {
if (nextFlag == GifConstants.ImageLabel) if (nextFlag == GifConstants.ImageLabel)
{ {
this.ReadImageDescriptor(); this.ReadImageDescriptor(stream);
} }
else if (nextFlag == GifConstants.ExtensionIntroducer) else if (nextFlag == GifConstants.ExtensionIntroducer)
{ {
switch (stream.ReadByte()) switch (stream.ReadByte())
{ {
case GifConstants.GraphicControlLabel: case GifConstants.GraphicControlLabel:
this.SkipBlock(); // Skip graphic control extension block this.SkipBlock(stream); // Skip graphic control extension block
break; break;
case GifConstants.CommentLabel: case GifConstants.CommentLabel:
this.ReadComments(); this.ReadComments(stream);
break; break;
case GifConstants.ApplicationExtensionLabel: case GifConstants.ApplicationExtensionLabel:
this.ReadApplicationExtension(); this.ReadApplicationExtension(stream);
break; break;
case GifConstants.PlainTextLabel: case GifConstants.PlainTextLabel:
this.SkipBlock(); // Not supported by any known decoder. this.SkipBlock(stream); // Not supported by any known decoder.
break; break;
} }
} }
@ -239,9 +234,10 @@ internal sealed class GifDecoderCore : IImageDecoderInternals
/// <summary> /// <summary>
/// Reads the graphic control extension. /// Reads the graphic control extension.
/// </summary> /// </summary>
private void ReadGraphicalControlExtension() /// <param name="stream">The <see cref="BufferedReadStream"/> containing image data.</param>
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) if (bytesRead != 6)
{ {
GifThrowHelper.ThrowInvalidImageContentException("Not enough data to read the graphic control extension"); GifThrowHelper.ThrowInvalidImageContentException("Not enough data to read the graphic control extension");
@ -253,9 +249,10 @@ internal sealed class GifDecoderCore : IImageDecoderInternals
/// <summary> /// <summary>
/// Reads the image descriptor. /// Reads the image descriptor.
/// </summary> /// </summary>
private void ReadImageDescriptor() /// <param name="stream">The <see cref="BufferedReadStream"/> containing image data.</param>
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) if (bytesRead != 9)
{ {
GifThrowHelper.ThrowInvalidImageContentException("Not enough data to read the image descriptor"); GifThrowHelper.ThrowInvalidImageContentException("Not enough data to read the image descriptor");
@ -271,9 +268,10 @@ internal sealed class GifDecoderCore : IImageDecoderInternals
/// <summary> /// <summary>
/// Reads the logical screen descriptor. /// Reads the logical screen descriptor.
/// </summary> /// </summary>
private void ReadLogicalScreenDescriptor() /// <param name="stream">The <see cref="BufferedReadStream"/> containing image data.</param>
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) if (bytesRead != 7)
{ {
GifThrowHelper.ThrowInvalidImageContentException("Not enough data to read the logical screen descriptor"); 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 /// Reads the application extension block parsing any animation or XMP information
/// if present. /// if present.
/// </summary> /// </summary>
private void ReadApplicationExtension() /// <param name="stream">The <see cref="BufferedReadStream"/> containing image data.</param>
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 // 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. // 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) 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); bool isXmp = this.buffer.AsSpan().StartsWith(GifConstants.XmpApplicationIdentificationBytes);
if (isXmp && !this.skipMetadata) if (isXmp && !this.skipMetadata)
{ {
GifXmpApplicationExtension extension = GifXmpApplicationExtension.Read(this.stream, this.memoryAllocator); GifXmpApplicationExtension extension = GifXmpApplicationExtension.Read(stream, this.memoryAllocator);
if (extension.Data.Length > 0) if (extension.Data.Length > 0)
{ {
this.metadata.XmpProfile = new XmpProfile(extension.Data); this.metadata!.XmpProfile = new XmpProfile(extension.Data);
} }
else else
{ {
// Reset the stream position and continue. // Reset the stream position and continue.
this.stream.Position = position; stream.Position = position;
this.SkipBlock(appLength); this.SkipBlock(stream, appLength);
} }
return; return;
} }
int subBlockSize = this.stream.ReadByte(); int subBlockSize = stream.ReadByte();
// TODO: There's also a NETSCAPE buffer extension. // TODO: There's also a NETSCAPE buffer extension.
// http://www.vurdalakov.net/misc/gif/netscape-buffering-application-extension // http://www.vurdalakov.net/misc/gif/netscape-buffering-application-extension
if (subBlockSize == GifConstants.NetscapeLoopingSubBlockSize) if (subBlockSize == GifConstants.NetscapeLoopingSubBlockSize)
{ {
this.stream.Read(this.buffer, 0, GifConstants.NetscapeLoopingSubBlockSize); stream.Read(this.buffer, 0, GifConstants.NetscapeLoopingSubBlockSize);
this.gifMetadata.RepeatCount = GifNetscapeLoopingApplicationExtension.Parse(this.buffer.AsSpan(1)).RepeatCount; this.gifMetadata!.RepeatCount = GifNetscapeLoopingApplicationExtension.Parse(this.buffer.AsSpan(1)).RepeatCount;
this.stream.Skip(1); // Skip the terminator. stream.Skip(1); // Skip the terminator.
return; return;
} }
// Could be something else not supported yet. // Could be something else not supported yet.
// Skip the subblock and terminator. // Skip the subblock and terminator.
this.SkipBlock(subBlockSize); this.SkipBlock(stream, subBlockSize);
return; return;
} }
this.SkipBlock(appLength); // Not supported by any known decoder. this.SkipBlock(stream, appLength); // Not supported by any known decoder.
} }
/// <summary> /// <summary>
/// Skips over a block or reads its terminator. /// Skips over a block or reads its terminator.
/// <param name="blockSize">The length of the block to skip.</param> /// <param name="blockSize">The length of the block to skip.</param>
/// <param name="stream">The <see cref="BufferedReadStream"/> containing image data.</param>
/// </summary> /// </summary>
private void SkipBlock(int blockSize = 0) private void SkipBlock(BufferedReadStream stream, int blockSize = 0)
{ {
if (blockSize > 0) if (blockSize > 0)
{ {
this.stream.Skip(blockSize); stream.Skip(blockSize);
} }
int flag; int flag;
while ((flag = this.stream.ReadByte()) > 0) while ((flag = stream.ReadByte()) > 0)
{ {
this.stream.Skip(flag); stream.Skip(flag);
} }
} }
/// <summary> /// <summary>
/// Reads the gif comments. /// Reads the gif comments.
/// </summary> /// </summary>
private void ReadComments() /// <param name="stream">The <see cref="BufferedReadStream"/> containing image data.</param>
private void ReadComments(BufferedReadStream stream)
{ {
int length; int length;
var stringBuilder = new StringBuilder(); var stringBuilder = new StringBuilder();
while ((length = this.stream.ReadByte()) != 0) while ((length = stream.ReadByte()) != 0)
{ {
if (length > GifConstants.MaxCommentSubBlockLength) if (length > GifConstants.MaxCommentSubBlockLength)
{ {
@ -372,21 +373,21 @@ internal sealed class GifDecoderCore : IImageDecoderInternals
if (this.skipMetadata) if (this.skipMetadata)
{ {
this.stream.Seek(length, SeekOrigin.Current); stream.Seek(length, SeekOrigin.Current);
continue; continue;
} }
using IMemoryOwner<byte> commentsBuffer = this.memoryAllocator.Allocate<byte>(length); using IMemoryOwner<byte> commentsBuffer = this.memoryAllocator.Allocate<byte>(length);
Span<byte> commentsSpan = commentsBuffer.GetSpan(); Span<byte> commentsSpan = commentsBuffer.GetSpan();
this.stream.Read(commentsSpan); stream.Read(commentsSpan);
string commentPart = GifConstants.Encoding.GetString(commentsSpan); string commentPart = GifConstants.Encoding.GetString(commentsSpan);
stringBuilder.Append(commentPart); stringBuilder.Append(commentPart);
} }
if (stringBuilder.Length > 0) 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. /// Reads an individual gif frame.
/// </summary> /// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="stream">The <see cref="BufferedReadStream"/> containing image data.</param>
/// <param name="image">The image to decode the information to.</param> /// <param name="image">The image to decode the information to.</param>
/// <param name="previousFrame">The previous frame.</param> /// <param name="previousFrame">The previous frame.</param>
private void ReadFrame<TPixel>(ref Image<TPixel> image, ref ImageFrame<TPixel> previousFrame) private void ReadFrame<TPixel>(BufferedReadStream stream, ref Image<TPixel>? image, ref ImageFrame<TPixel>? previousFrame)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
this.ReadImageDescriptor(); this.ReadImageDescriptor(stream);
IMemoryOwner<byte> localColorTable = null; IMemoryOwner<byte>? localColorTable = null;
Buffer2D<byte> indices = null; Buffer2D<byte>? indices = null;
try try
{ {
// Determine the color table for this frame. If there is a local one, use it otherwise use the global color table. // 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; int length = this.imageDescriptor.LocalColorTableSize * 3;
localColorTable = this.configuration.MemoryAllocator.Allocate<byte>(length, AllocationOptions.Clean); localColorTable = this.configuration.MemoryAllocator.Allocate<byte>(length, AllocationOptions.Clean);
this.stream.Read(localColorTable.GetSpan()); stream.Read(localColorTable.GetSpan());
} }
indices = this.configuration.MemoryAllocator.Allocate2D<byte>(this.imageDescriptor.Width, this.imageDescriptor.Height, AllocationOptions.Clean); indices = this.configuration.MemoryAllocator.Allocate2D<byte>(this.imageDescriptor.Width, this.imageDescriptor.Height, AllocationOptions.Clean);
this.ReadFrameIndices(indices); this.ReadFrameIndices(stream, indices);
Span<byte> rawColorTable = default; Span<byte> rawColorTable = default;
if (localColorTable != null) if (localColorTable != null)
@ -430,7 +432,7 @@ internal sealed class GifDecoderCore : IImageDecoderInternals
this.ReadFrameColors(ref image, ref previousFrame, indices, colorTable, this.imageDescriptor); this.ReadFrameColors(ref image, ref previousFrame, indices, colorTable, this.imageDescriptor);
// Skip any remaining blocks // Skip any remaining blocks
this.SkipBlock(); this.SkipBlock(stream);
} }
finally finally
{ {
@ -442,12 +444,13 @@ internal sealed class GifDecoderCore : IImageDecoderInternals
/// <summary> /// <summary>
/// Reads the frame indices marking the color to use for each pixel. /// Reads the frame indices marking the color to use for each pixel.
/// </summary> /// </summary>
/// <param name="stream">The <see cref="BufferedReadStream"/> containing image data.</param>
/// <param name="indices">The 2D pixel buffer to write to.</param> /// <param name="indices">The 2D pixel buffer to write to.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ReadFrameIndices(Buffer2D<byte> indices) private void ReadFrameIndices(BufferedReadStream stream, Buffer2D<byte> indices)
{ {
int minCodeSize = this.stream.ReadByte(); int minCodeSize = stream.ReadByte();
using var lzwDecoder = new LzwDecoder(this.configuration.MemoryAllocator, this.stream); using LzwDecoder lzwDecoder = new LzwDecoder(this.configuration.MemoryAllocator, stream);
lzwDecoder.DecodePixels(minCodeSize, indices); lzwDecoder.DecodePixels(minCodeSize, indices);
} }
@ -460,15 +463,15 @@ internal sealed class GifDecoderCore : IImageDecoderInternals
/// <param name="indices">The indexed pixels.</param> /// <param name="indices">The indexed pixels.</param>
/// <param name="colorTable">The color table containing the available colors.</param> /// <param name="colorTable">The color table containing the available colors.</param>
/// <param name="descriptor">The <see cref="GifImageDescriptor"/></param> /// <param name="descriptor">The <see cref="GifImageDescriptor"/></param>
private void ReadFrameColors<TPixel>(ref Image<TPixel> image, ref ImageFrame<TPixel> previousFrame, Buffer2D<byte> indices, ReadOnlySpan<Rgb24> colorTable, in GifImageDescriptor descriptor) private void ReadFrameColors<TPixel>(ref Image<TPixel>? image, ref ImageFrame<TPixel>? previousFrame, Buffer2D<byte> indices, ReadOnlySpan<Rgb24> colorTable, in GifImageDescriptor descriptor)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
int imageWidth = this.logicalScreenDescriptor.Width; int imageWidth = this.logicalScreenDescriptor.Width;
int imageHeight = this.logicalScreenDescriptor.Height; int imageHeight = this.logicalScreenDescriptor.Height;
bool transFlag = this.graphicsControlExtension.TransparencyFlag; bool transFlag = this.graphicsControlExtension.TransparencyFlag;
ImageFrame<TPixel> prevFrame = null; ImageFrame<TPixel>? prevFrame = null;
ImageFrame<TPixel> currentFrame = null; ImageFrame<TPixel>? currentFrame = null;
ImageFrame<TPixel> imageFrame; ImageFrame<TPixel> imageFrame;
if (previousFrame is null) if (previousFrame is null)
@ -494,7 +497,7 @@ internal sealed class GifDecoderCore : IImageDecoderInternals
prevFrame = previousFrame; prevFrame = previousFrame;
} }
currentFrame = image.Frames.CreateFrame(); currentFrame = image!.Frames.CreateFrame();
this.SetFrameMetadata(currentFrame.Metadata, false); this.SetFrameMetadata(currentFrame.Metadata, false);
@ -661,13 +664,13 @@ internal sealed class GifDecoderCore : IImageDecoderInternals
/// Reads the logical screen descriptor and global color table blocks /// Reads the logical screen descriptor and global color table blocks
/// </summary> /// </summary>
/// <param name="stream">The stream containing image data. </param> /// <param name="stream">The stream containing image data. </param>
[MemberNotNull(nameof(metadata))]
[MemberNotNull(nameof(gifMetadata))]
private void ReadLogicalScreenDescriptorAndGlobalColorTable(BufferedReadStream stream) private void ReadLogicalScreenDescriptorAndGlobalColorTable(BufferedReadStream stream)
{ {
this.stream = stream;
// Skip the identifier // Skip the identifier
this.stream.Skip(6); stream.Skip(6);
this.ReadLogicalScreenDescriptor(); this.ReadLogicalScreenDescriptor(stream);
ImageMetadata meta = new(); ImageMetadata meta = new();

24
src/ImageSharp/Formats/Gif/GifEncoderCore.cs

@ -1,8 +1,8 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
#nullable disable
using System.Buffers; using System.Buffers;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Advanced;
@ -93,7 +93,7 @@ internal sealed class GifEncoderCore : IImageEncoderInternals
bool useGlobalTable = this.colorTableMode == GifColorTableMode.Global; bool useGlobalTable = this.colorTableMode == GifColorTableMode.Global;
// Quantize the image returning a palette. // Quantize the image returning a palette.
IndexedImageFrame<TPixel> quantized; IndexedImageFrame<TPixel>? quantized;
using (IQuantizer<TPixel> frameQuantizer = this.quantizer.CreatePixelSpecificQuantizer<TPixel>(this.configuration)) using (IQuantizer<TPixel> frameQuantizer = this.quantizer.CreatePixelSpecificQuantizer<TPixel>(this.configuration))
{ {
if (useGlobalTable) if (useGlobalTable)
@ -129,7 +129,7 @@ internal sealed class GifEncoderCore : IImageEncoderInternals
this.WriteComments(gifMetadata, stream); this.WriteComments(gifMetadata, stream);
// Write application extensions. // 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); this.WriteApplicationExtensions(stream, image.Frames.Count, gifMetadata.RepeatCount, xmpProfile);
} }
@ -141,7 +141,7 @@ internal sealed class GifEncoderCore : IImageEncoderInternals
private void EncodeFrames<TPixel>( private void EncodeFrames<TPixel>(
Stream stream, Stream stream,
Image<TPixel> image, Image<TPixel> image,
IndexedImageFrame<TPixel> quantized, IndexedImageFrame<TPixel>? quantized,
ReadOnlyMemory<TPixel> palette) ReadOnlyMemory<TPixel> palette)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
@ -152,8 +152,8 @@ internal sealed class GifEncoderCore : IImageEncoderInternals
// Gather the metadata for this frame. // Gather the metadata for this frame.
ImageFrame<TPixel> frame = image.Frames[i]; ImageFrame<TPixel> frame = image.Frames[i];
ImageFrameMetadata metadata = frame.Metadata; ImageFrameMetadata metadata = frame.Metadata;
bool hasMetadata = metadata.TryGetGifMetadata(out GifFrameMetadata frameMetadata); bool hasMetadata = metadata.TryGetGifMetadata(out GifFrameMetadata? frameMetadata);
bool useLocal = this.colorTableMode == GifColorTableMode.Local || (hasMetadata && frameMetadata.ColorTableMode == GifColorTableMode.Local); bool useLocal = this.colorTableMode == GifColorTableMode.Local || (hasMetadata && frameMetadata!.ColorTableMode == GifColorTableMode.Local);
if (!useLocal && !hasPaletteQuantizer && i > 0) if (!useLocal && !hasPaletteQuantizer && i > 0)
{ {
@ -164,7 +164,7 @@ internal sealed class GifEncoderCore : IImageEncoderInternals
paletteQuantizer = new(this.configuration, this.quantizer.Options, palette); 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. // Clean up for the next run.
quantized.Dispose(); quantized.Dispose();
@ -182,7 +182,7 @@ internal sealed class GifEncoderCore : IImageEncoderInternals
ImageFrame<TPixel> frame, ImageFrame<TPixel> frame,
int frameIndex, int frameIndex,
bool useLocal, bool useLocal,
GifFrameMetadata metadata, GifFrameMetadata? metadata,
ref IndexedImageFrame<TPixel> quantized, ref IndexedImageFrame<TPixel> quantized,
ref PaletteQuantizer<TPixel> paletteQuantizer) ref PaletteQuantizer<TPixel> paletteQuantizer)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
@ -193,7 +193,7 @@ internal sealed class GifEncoderCore : IImageEncoderInternals
if (useLocal) if (useLocal)
{ {
// Reassign using the current frame and details. // Reassign using the current frame and details.
QuantizerOptions options = null; QuantizerOptions? options = null;
int colorTableLength = metadata?.ColorTableLength ?? 0; int colorTableLength = metadata?.ColorTableLength ?? 0;
if (colorTableLength > 0) if (colorTableLength > 0)
{ {
@ -338,7 +338,7 @@ internal sealed class GifEncoderCore : IImageEncoderInternals
/// <param name="frameCount">The frame count fo this image.</param> /// <param name="frameCount">The frame count fo this image.</param>
/// <param name="repeatCount">The animated image repeat count.</param> /// <param name="repeatCount">The animated image repeat count.</param>
/// <param name="xmpProfile">The XMP metadata profile. Null if profile is not to be written.</param> /// <param name="xmpProfile">The XMP metadata profile. Null if profile is not to be written.</param>
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. // Application Extension: Loop repeat count.
if (frameCount > 1 && repeatCount != 1) if (frameCount > 1 && repeatCount != 1)
@ -350,7 +350,7 @@ internal sealed class GifEncoderCore : IImageEncoderInternals
// Application Extension: XMP Profile. // Application Extension: XMP Profile.
if (xmpProfile != null) if (xmpProfile != null)
{ {
GifXmpApplicationExtension xmpExtension = new(xmpProfile.Data); GifXmpApplicationExtension xmpExtension = new(xmpProfile.Data!);
this.WriteExtension(xmpExtension, stream); this.WriteExtension(xmpExtension, stream);
} }
} }
@ -439,7 +439,7 @@ internal sealed class GifEncoderCore : IImageEncoderInternals
private void WriteExtension<TGifExtension>(TGifExtension extension, Stream stream) private void WriteExtension<TGifExtension>(TGifExtension extension, Stream stream)
where TGifExtension : struct, IGifExtension where TGifExtension : struct, IGifExtension
{ {
IMemoryOwner<byte> owner = null; IMemoryOwner<byte>? owner = null;
Span<byte> extensionBuffer; Span<byte> extensionBuffer;
int extensionSize = extension.ContentLength; int extensionSize = extension.ContentLength;

2
src/ImageSharp/Image.Decode.cs

@ -91,7 +91,7 @@ public abstract partial class Image
ImageFormatManager.ThrowInvalidDecoder(configuration.ImageFormatsManager); ImageFormatManager.ThrowInvalidDecoder(configuration.ImageFormatsManager);
} }
return format!; return format;
} }
/// <summary> /// <summary>

4
src/ImageSharp/Image.cs

@ -28,7 +28,7 @@ public abstract partial class Image : ImageInfo, IDisposable, IConfigurationProv
/// <param name="pixelType">The pixel type information.</param> /// <param name="pixelType">The pixel type information.</param>
/// <param name="metadata">The image metadata.</param> /// <param name="metadata">The image metadata.</param>
/// <param name="size">The size in px units.</param> /// <param name="size">The size in px units.</param>
protected Image(Configuration configuration, PixelTypeInfo pixelType, ImageMetadata metadata, Size size) protected Image(Configuration configuration, PixelTypeInfo pixelType, ImageMetadata? metadata, Size size)
: base(pixelType, size, metadata) : base(pixelType, size, metadata)
=> this.configuration = configuration ?? Configuration.Default; => this.configuration = configuration ?? Configuration.Default;
@ -43,7 +43,7 @@ public abstract partial class Image : ImageInfo, IDisposable, IConfigurationProv
internal Image( internal Image(
Configuration configuration, Configuration configuration,
PixelTypeInfo pixelType, PixelTypeInfo pixelType,
ImageMetadata metadata, ImageMetadata? metadata,
int width, int width,
int height) int height)
: this(configuration, pixelType, metadata, new Size(width, height)) : this(configuration, pixelType, metadata, new Size(width, height))

4
src/ImageSharp/ImageInfo.cs

@ -18,7 +18,7 @@ public class ImageInfo
/// <param name="width">The width of the image in px units.</param> /// <param name="width">The width of the image in px units.</param>
/// <param name="height">The height of the image in px units.</param> /// <param name="height">The height of the image in px units.</param>
/// <param name="metadata">The image metadata.</param> /// <param name="metadata">The image metadata.</param>
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) : this(pixelType, new(width, height), metadata)
{ {
} }
@ -29,7 +29,7 @@ public class ImageInfo
/// <param name="pixelType">The pixel type information.</param> /// <param name="pixelType">The pixel type information.</param>
/// <param name="size">The size of the image in px units.</param> /// <param name="size">The size of the image in px units.</param>
/// <param name="metadata">The image metadata.</param> /// <param name="metadata">The image metadata.</param>
public ImageInfo(PixelTypeInfo pixelType, Size size, ImageMetadata metadata) public ImageInfo(PixelTypeInfo pixelType, Size size, ImageMetadata? metadata)
{ {
this.PixelType = pixelType; this.PixelType = pixelType;
this.Metadata = metadata ?? new ImageMetadata(); this.Metadata = metadata ?? new ImageMetadata();

4
src/ImageSharp/Image{TPixel}.cs

@ -77,7 +77,7 @@ public sealed class Image<TPixel> : Image
/// <param name="width">The width of the image in pixels.</param> /// <param name="width">The width of the image in pixels.</param>
/// <param name="height">The height of the image in pixels.</param> /// <param name="height">The height of the image in pixels.</param>
/// <param name="metadata">The images metadata.</param> /// <param name="metadata">The images metadata.</param>
internal Image(Configuration configuration, int width, int height, ImageMetadata metadata) internal Image(Configuration configuration, int width, int height, ImageMetadata? metadata)
: base(configuration, PixelTypeInfo.Create<TPixel>(), metadata, width, height) : base(configuration, PixelTypeInfo.Create<TPixel>(), metadata, width, height)
=> this.frames = new ImageFrameCollection<TPixel>(this, width, height, default(TPixel)); => this.frames = new ImageFrameCollection<TPixel>(this, width, height, default(TPixel));
@ -128,7 +128,7 @@ public sealed class Image<TPixel> : Image
int width, int width,
int height, int height,
TPixel backgroundColor, TPixel backgroundColor,
ImageMetadata metadata) ImageMetadata? metadata)
: base(configuration, PixelTypeInfo.Create<TPixel>(), metadata, width, height) : base(configuration, PixelTypeInfo.Create<TPixel>(), metadata, width, height)
=> this.frames = new ImageFrameCollection<TPixel>(this, width, height, backgroundColor); => this.frames = new ImageFrameCollection<TPixel>(this, width, height, backgroundColor);

Loading…
Cancel
Save