Skip to content

Commit fff41c9

Browse files
Merge pull request #2346 from stefannikolei/sn/nullable/format_gif
remove nullable disable from format gif
2 parents c80bda4 + c6e5839 commit fff41c9

File tree

6 files changed

+91
-90
lines changed

6 files changed

+91
-90
lines changed

src/ImageSharp/Formats/Gif/GifDecoderCore.cs

Lines changed: 73 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
// Copyright (c) Six Labors.
22
// Licensed under the Six Labors Split License.
3-
#nullable disable
43

54
using System.Buffers;
5+
using System.Diagnostics.CodeAnalysis;
66
using System.Runtime.CompilerServices;
77
using System.Runtime.InteropServices;
88
using System.Text;
@@ -24,15 +24,10 @@ internal sealed class GifDecoderCore : IImageDecoderInternals
2424
/// </summary>
2525
private readonly byte[] buffer = new byte[16];
2626

27-
/// <summary>
28-
/// The currently loaded stream.
29-
/// </summary>
30-
private BufferedReadStream stream;
31-
3227
/// <summary>
3328
/// The global color table.
3429
/// </summary>
35-
private IMemoryOwner<byte> globalColorTable;
30+
private IMemoryOwner<byte>? globalColorTable;
3631

3732
/// <summary>
3833
/// The area to restore.
@@ -77,12 +72,12 @@ internal sealed class GifDecoderCore : IImageDecoderInternals
7772
/// <summary>
7873
/// The abstract metadata.
7974
/// </summary>
80-
private ImageMetadata metadata;
75+
private ImageMetadata? metadata;
8176

8277
/// <summary>
8378
/// The gif specific metadata.
8479
/// </summary>
85-
private GifMetadata gifMetadata;
80+
private GifMetadata? gifMetadata;
8681

8782
/// <summary>
8883
/// Initializes a new instance of the <see cref="GifDecoderCore"/> class.
@@ -108,8 +103,8 @@ public Image<TPixel> Decode<TPixel>(BufferedReadStream stream, CancellationToken
108103
where TPixel : unmanaged, IPixel<TPixel>
109104
{
110105
uint frameCount = 0;
111-
Image<TPixel> image = null;
112-
ImageFrame<TPixel> previousFrame = null;
106+
Image<TPixel>? image = null;
107+
ImageFrame<TPixel>? previousFrame = null;
113108
try
114109
{
115110
this.ReadLogicalScreenDescriptorAndGlobalColorTable(stream);
@@ -125,7 +120,7 @@ public Image<TPixel> Decode<TPixel>(BufferedReadStream stream, CancellationToken
125120
break;
126121
}
127122

128-
this.ReadFrame(ref image, ref previousFrame);
123+
this.ReadFrame(stream, ref image, ref previousFrame);
129124

130125
// Reset per-frame state.
131126
this.imageDescriptor = default;
@@ -136,16 +131,16 @@ public Image<TPixel> Decode<TPixel>(BufferedReadStream stream, CancellationToken
136131
switch (stream.ReadByte())
137132
{
138133
case GifConstants.GraphicControlLabel:
139-
this.ReadGraphicalControlExtension();
134+
this.ReadGraphicalControlExtension(stream);
140135
break;
141136
case GifConstants.CommentLabel:
142-
this.ReadComments();
137+
this.ReadComments(stream);
143138
break;
144139
case GifConstants.ApplicationExtensionLabel:
145-
this.ReadApplicationExtension();
140+
this.ReadApplicationExtension(stream);
146141
break;
147142
case GifConstants.PlainTextLabel:
148-
this.SkipBlock(); // Not supported by any known decoder.
143+
SkipBlock(stream); // Not supported by any known decoder.
149144
break;
150145
}
151146
}
@@ -187,23 +182,23 @@ public ImageInfo Identify(BufferedReadStream stream, CancellationToken cancellat
187182
{
188183
if (nextFlag == GifConstants.ImageLabel)
189184
{
190-
this.ReadImageDescriptor();
185+
this.ReadImageDescriptor(stream);
191186
}
192187
else if (nextFlag == GifConstants.ExtensionIntroducer)
193188
{
194189
switch (stream.ReadByte())
195190
{
196191
case GifConstants.GraphicControlLabel:
197-
this.SkipBlock(); // Skip graphic control extension block
192+
SkipBlock(stream); // Skip graphic control extension block
198193
break;
199194
case GifConstants.CommentLabel:
200-
this.ReadComments();
195+
this.ReadComments(stream);
201196
break;
202197
case GifConstants.ApplicationExtensionLabel:
203-
this.ReadApplicationExtension();
198+
this.ReadApplicationExtension(stream);
204199
break;
205200
case GifConstants.PlainTextLabel:
206-
this.SkipBlock(); // Not supported by any known decoder.
201+
SkipBlock(stream); // Not supported by any known decoder.
207202
break;
208203
}
209204
}
@@ -239,9 +234,10 @@ public ImageInfo Identify(BufferedReadStream stream, CancellationToken cancellat
239234
/// <summary>
240235
/// Reads the graphic control extension.
241236
/// </summary>
242-
private void ReadGraphicalControlExtension()
237+
/// <param name="stream">The <see cref="BufferedReadStream"/> containing image data.</param>
238+
private void ReadGraphicalControlExtension(BufferedReadStream stream)
243239
{
244-
int bytesRead = this.stream.Read(this.buffer, 0, 6);
240+
int bytesRead = stream.Read(this.buffer, 0, 6);
245241
if (bytesRead != 6)
246242
{
247243
GifThrowHelper.ThrowInvalidImageContentException("Not enough data to read the graphic control extension");
@@ -253,9 +249,10 @@ private void ReadGraphicalControlExtension()
253249
/// <summary>
254250
/// Reads the image descriptor.
255251
/// </summary>
256-
private void ReadImageDescriptor()
252+
/// <param name="stream">The <see cref="BufferedReadStream"/> containing image data.</param>
253+
private void ReadImageDescriptor(BufferedReadStream stream)
257254
{
258-
int bytesRead = this.stream.Read(this.buffer, 0, 9);
255+
int bytesRead = stream.Read(this.buffer, 0, 9);
259256
if (bytesRead != 9)
260257
{
261258
GifThrowHelper.ThrowInvalidImageContentException("Not enough data to read the image descriptor");
@@ -271,9 +268,10 @@ private void ReadImageDescriptor()
271268
/// <summary>
272269
/// Reads the logical screen descriptor.
273270
/// </summary>
274-
private void ReadLogicalScreenDescriptor()
271+
/// <param name="stream">The <see cref="BufferedReadStream"/> containing image data.</param>
272+
private void ReadLogicalScreenDescriptor(BufferedReadStream stream)
275273
{
276-
int bytesRead = this.stream.Read(this.buffer, 0, 7);
274+
int bytesRead = stream.Read(this.buffer, 0, 7);
277275
if (bytesRead != 7)
278276
{
279277
GifThrowHelper.ThrowInvalidImageContentException("Not enough data to read the logical screen descriptor");
@@ -286,84 +284,87 @@ private void ReadLogicalScreenDescriptor()
286284
/// Reads the application extension block parsing any animation or XMP information
287285
/// if present.
288286
/// </summary>
289-
private void ReadApplicationExtension()
287+
/// <param name="stream">The <see cref="BufferedReadStream"/> containing image data.</param>
288+
private void ReadApplicationExtension(BufferedReadStream stream)
290289
{
291-
int appLength = this.stream.ReadByte();
290+
int appLength = stream.ReadByte();
292291

293292
// If the length is 11 then it's a valid extension and most likely
294293
// a NETSCAPE, XMP or ANIMEXTS extension. We want the loop count from this.
295-
long position = this.stream.Position;
294+
long position = stream.Position;
296295
if (appLength == GifConstants.ApplicationBlockSize)
297296
{
298-
this.stream.Read(this.buffer, 0, GifConstants.ApplicationBlockSize);
297+
stream.Read(this.buffer, 0, GifConstants.ApplicationBlockSize);
299298
bool isXmp = this.buffer.AsSpan().StartsWith(GifConstants.XmpApplicationIdentificationBytes);
300299
if (isXmp && !this.skipMetadata)
301300
{
302-
GifXmpApplicationExtension extension = GifXmpApplicationExtension.Read(this.stream, this.memoryAllocator);
301+
GifXmpApplicationExtension extension = GifXmpApplicationExtension.Read(stream, this.memoryAllocator);
303302
if (extension.Data.Length > 0)
304303
{
305-
this.metadata.XmpProfile = new XmpProfile(extension.Data);
304+
this.metadata!.XmpProfile = new XmpProfile(extension.Data);
306305
}
307306
else
308307
{
309308
// Reset the stream position and continue.
310-
this.stream.Position = position;
311-
this.SkipBlock(appLength);
309+
stream.Position = position;
310+
SkipBlock(stream, appLength);
312311
}
313312

314313
return;
315314
}
316315

317-
int subBlockSize = this.stream.ReadByte();
316+
int subBlockSize = stream.ReadByte();
318317

319318
// TODO: There's also a NETSCAPE buffer extension.
320319
// http://www.vurdalakov.net/misc/gif/netscape-buffering-application-extension
321320
if (subBlockSize == GifConstants.NetscapeLoopingSubBlockSize)
322321
{
323-
this.stream.Read(this.buffer, 0, GifConstants.NetscapeLoopingSubBlockSize);
324-
this.gifMetadata.RepeatCount = GifNetscapeLoopingApplicationExtension.Parse(this.buffer.AsSpan(1)).RepeatCount;
325-
this.stream.Skip(1); // Skip the terminator.
322+
stream.Read(this.buffer, 0, GifConstants.NetscapeLoopingSubBlockSize);
323+
this.gifMetadata!.RepeatCount = GifNetscapeLoopingApplicationExtension.Parse(this.buffer.AsSpan(1)).RepeatCount;
324+
stream.Skip(1); // Skip the terminator.
326325
return;
327326
}
328327

329328
// Could be something else not supported yet.
330329
// Skip the subblock and terminator.
331-
this.SkipBlock(subBlockSize);
330+
SkipBlock(stream, subBlockSize);
332331

333332
return;
334333
}
335334

336-
this.SkipBlock(appLength); // Not supported by any known decoder.
335+
SkipBlock(stream, appLength); // Not supported by any known decoder.
337336
}
338337

339338
/// <summary>
340339
/// Skips over a block or reads its terminator.
341-
/// <param name="blockSize">The length of the block to skip.</param>
342340
/// </summary>
343-
private void SkipBlock(int blockSize = 0)
341+
/// <param name="stream">The <see cref="BufferedReadStream"/> containing image data.</param>
342+
/// <param name="blockSize">The length of the block to skip.</param>
343+
private static void SkipBlock(BufferedReadStream stream, int blockSize = 0)
344344
{
345345
if (blockSize > 0)
346346
{
347-
this.stream.Skip(blockSize);
347+
stream.Skip(blockSize);
348348
}
349349

350350
int flag;
351351

352-
while ((flag = this.stream.ReadByte()) > 0)
352+
while ((flag = stream.ReadByte()) > 0)
353353
{
354-
this.stream.Skip(flag);
354+
stream.Skip(flag);
355355
}
356356
}
357357

358358
/// <summary>
359359
/// Reads the gif comments.
360360
/// </summary>
361-
private void ReadComments()
361+
/// <param name="stream">The <see cref="BufferedReadStream"/> containing image data.</param>
362+
private void ReadComments(BufferedReadStream stream)
362363
{
363364
int length;
364365

365-
var stringBuilder = new StringBuilder();
366-
while ((length = this.stream.ReadByte()) != 0)
366+
StringBuilder stringBuilder = new();
367+
while ((length = stream.ReadByte()) != 0)
367368
{
368369
if (length > GifConstants.MaxCommentSubBlockLength)
369370
{
@@ -372,49 +373,50 @@ private void ReadComments()
372373

373374
if (this.skipMetadata)
374375
{
375-
this.stream.Seek(length, SeekOrigin.Current);
376+
stream.Seek(length, SeekOrigin.Current);
376377
continue;
377378
}
378379

379380
using IMemoryOwner<byte> commentsBuffer = this.memoryAllocator.Allocate<byte>(length);
380381
Span<byte> commentsSpan = commentsBuffer.GetSpan();
381382

382-
this.stream.Read(commentsSpan);
383+
stream.Read(commentsSpan);
383384
string commentPart = GifConstants.Encoding.GetString(commentsSpan);
384385
stringBuilder.Append(commentPart);
385386
}
386387

387388
if (stringBuilder.Length > 0)
388389
{
389-
this.gifMetadata.Comments.Add(stringBuilder.ToString());
390+
this.gifMetadata!.Comments.Add(stringBuilder.ToString());
390391
}
391392
}
392393

393394
/// <summary>
394395
/// Reads an individual gif frame.
395396
/// </summary>
396397
/// <typeparam name="TPixel">The pixel format.</typeparam>
398+
/// <param name="stream">The <see cref="BufferedReadStream"/> containing image data.</param>
397399
/// <param name="image">The image to decode the information to.</param>
398400
/// <param name="previousFrame">The previous frame.</param>
399-
private void ReadFrame<TPixel>(ref Image<TPixel> image, ref ImageFrame<TPixel> previousFrame)
401+
private void ReadFrame<TPixel>(BufferedReadStream stream, ref Image<TPixel>? image, ref ImageFrame<TPixel>? previousFrame)
400402
where TPixel : unmanaged, IPixel<TPixel>
401403
{
402-
this.ReadImageDescriptor();
404+
this.ReadImageDescriptor(stream);
403405

404-
IMemoryOwner<byte> localColorTable = null;
405-
Buffer2D<byte> indices = null;
406+
IMemoryOwner<byte>? localColorTable = null;
407+
Buffer2D<byte>? indices = null;
406408
try
407409
{
408410
// Determine the color table for this frame. If there is a local one, use it otherwise use the global color table.
409411
if (this.imageDescriptor.LocalColorTableFlag)
410412
{
411413
int length = this.imageDescriptor.LocalColorTableSize * 3;
412414
localColorTable = this.configuration.MemoryAllocator.Allocate<byte>(length, AllocationOptions.Clean);
413-
this.stream.Read(localColorTable.GetSpan());
415+
stream.Read(localColorTable.GetSpan());
414416
}
415417

416418
indices = this.configuration.MemoryAllocator.Allocate2D<byte>(this.imageDescriptor.Width, this.imageDescriptor.Height, AllocationOptions.Clean);
417-
this.ReadFrameIndices(indices);
419+
this.ReadFrameIndices(stream, indices);
418420

419421
Span<byte> rawColorTable = default;
420422
if (localColorTable != null)
@@ -430,7 +432,7 @@ private void ReadFrame<TPixel>(ref Image<TPixel> image, ref ImageFrame<TPixel> p
430432
this.ReadFrameColors(ref image, ref previousFrame, indices, colorTable, this.imageDescriptor);
431433

432434
// Skip any remaining blocks
433-
this.SkipBlock();
435+
SkipBlock(stream);
434436
}
435437
finally
436438
{
@@ -442,12 +444,13 @@ private void ReadFrame<TPixel>(ref Image<TPixel> image, ref ImageFrame<TPixel> p
442444
/// <summary>
443445
/// Reads the frame indices marking the color to use for each pixel.
444446
/// </summary>
447+
/// <param name="stream">The <see cref="BufferedReadStream"/> containing image data.</param>
445448
/// <param name="indices">The 2D pixel buffer to write to.</param>
446449
[MethodImpl(MethodImplOptions.AggressiveInlining)]
447-
private void ReadFrameIndices(Buffer2D<byte> indices)
450+
private void ReadFrameIndices(BufferedReadStream stream, Buffer2D<byte> indices)
448451
{
449-
int minCodeSize = this.stream.ReadByte();
450-
using var lzwDecoder = new LzwDecoder(this.configuration.MemoryAllocator, this.stream);
452+
int minCodeSize = stream.ReadByte();
453+
using LzwDecoder lzwDecoder = new(this.configuration.MemoryAllocator, stream);
451454
lzwDecoder.DecodePixels(minCodeSize, indices);
452455
}
453456

@@ -460,15 +463,15 @@ private void ReadFrameIndices(Buffer2D<byte> indices)
460463
/// <param name="indices">The indexed pixels.</param>
461464
/// <param name="colorTable">The color table containing the available colors.</param>
462465
/// <param name="descriptor">The <see cref="GifImageDescriptor"/></param>
463-
private void ReadFrameColors<TPixel>(ref Image<TPixel> image, ref ImageFrame<TPixel> previousFrame, Buffer2D<byte> indices, ReadOnlySpan<Rgb24> colorTable, in GifImageDescriptor descriptor)
466+
private void ReadFrameColors<TPixel>(ref Image<TPixel>? image, ref ImageFrame<TPixel>? previousFrame, Buffer2D<byte> indices, ReadOnlySpan<Rgb24> colorTable, in GifImageDescriptor descriptor)
464467
where TPixel : unmanaged, IPixel<TPixel>
465468
{
466469
int imageWidth = this.logicalScreenDescriptor.Width;
467470
int imageHeight = this.logicalScreenDescriptor.Height;
468471
bool transFlag = this.graphicsControlExtension.TransparencyFlag;
469472

470-
ImageFrame<TPixel> prevFrame = null;
471-
ImageFrame<TPixel> currentFrame = null;
473+
ImageFrame<TPixel>? prevFrame = null;
474+
ImageFrame<TPixel>? currentFrame = null;
472475
ImageFrame<TPixel> imageFrame;
473476

474477
if (previousFrame is null)
@@ -494,7 +497,7 @@ private void ReadFrameColors<TPixel>(ref Image<TPixel> image, ref ImageFrame<TPi
494497
prevFrame = previousFrame;
495498
}
496499

497-
currentFrame = image.Frames.CreateFrame();
500+
currentFrame = image!.Frames.CreateFrame();
498501

499502
this.SetFrameMetadata(currentFrame.Metadata, false);
500503

@@ -661,13 +664,13 @@ private void SetFrameMetadata(ImageFrameMetadata meta, bool isRoot)
661664
/// Reads the logical screen descriptor and global color table blocks
662665
/// </summary>
663666
/// <param name="stream">The stream containing image data. </param>
667+
[MemberNotNull(nameof(metadata))]
668+
[MemberNotNull(nameof(gifMetadata))]
664669
private void ReadLogicalScreenDescriptorAndGlobalColorTable(BufferedReadStream stream)
665670
{
666-
this.stream = stream;
667-
668671
// Skip the identifier
669-
this.stream.Skip(6);
670-
this.ReadLogicalScreenDescriptor();
672+
stream.Skip(6);
673+
this.ReadLogicalScreenDescriptor(stream);
671674

672675
ImageMetadata meta = new();
673676

0 commit comments

Comments
 (0)