From b38146dfaa2d25ea7fa85847a4012c88caa902f9 Mon Sep 17 00:00:00 2001 From: antonfirsov Date: Tue, 17 Dec 2024 01:37:18 +0100 Subject: [PATCH] GifDecoder: get rid of Unsafe --- src/ImageSharp/Formats/Gif/GifDecoderCore.cs | 39 ++++++++++---------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs index 3d6990478d..e18166c4b8 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs @@ -423,19 +423,14 @@ private void ReadFrame(BufferedReadStream stream, ref Image? ima // Determine the color table for this frame. If there is a local one, use it otherwise use the global color table. bool hasLocalColorTable = this.imageDescriptor.LocalColorTableFlag; - + Span rawColorTable = default; if (hasLocalColorTable) { // Read and store the local color table. We allocate the maximum possible size and slice to match. int length = this.currentLocalColorTableSize = this.imageDescriptor.LocalColorTableSize * 3; this.currentLocalColorTable ??= this.configuration.MemoryAllocator.Allocate(768, AllocationOptions.Clean); stream.Read(this.currentLocalColorTable.GetSpan()[..length]); - } - - Span rawColorTable = default; - if (hasLocalColorTable) - { - rawColorTable = this.currentLocalColorTable!.GetSpan()[..this.currentLocalColorTableSize]; + rawColorTable = this.currentLocalColorTable!.GetSpan()[..length]; } else if (this.globalColorTable != null) { @@ -443,7 +438,7 @@ private void ReadFrame(BufferedReadStream stream, ref Image? ima } ReadOnlySpan colorTable = MemoryMarshal.Cast(rawColorTable); - this.ReadFrameColors(stream, ref image, ref previousFrame, colorTable, this.imageDescriptor); + this.ReadFrameColors(stream, ref image, ref previousFrame, colorTable); // Skip any remaining blocks SkipBlock(stream); @@ -457,15 +452,14 @@ private void ReadFrame(BufferedReadStream stream, ref Image? ima /// The image to decode the information to. /// The previous frame. /// The color table containing the available colors. - /// The private void ReadFrameColors( BufferedReadStream stream, ref Image? image, ref ImageFrame? previousFrame, - ReadOnlySpan colorTable, - in GifImageDescriptor descriptor) + ReadOnlySpan colorTable) where TPixel : unmanaged, IPixel { + GifImageDescriptor descriptor = this.imageDescriptor; int imageWidth = this.logicalScreenDescriptor.Width; int imageHeight = this.logicalScreenDescriptor.Height; bool transFlag = this.graphicsControlExtension.TransparencyFlag; @@ -528,7 +522,6 @@ private void ReadFrameColors( // However we have images that exceed this that can be decoded by other libraries. #1530 using IMemoryOwner indicesRowOwner = this.memoryAllocator.Allocate(descriptor.Width); Span indicesRow = indicesRowOwner.Memory.Span; - ref byte indicesRowRef = ref MemoryMarshal.GetReference(indicesRow); int minCodeSize = stream.ReadByte(); if (LzwDecoder.IsValidMinCodeSize(minCodeSize)) @@ -572,22 +565,28 @@ private void ReadFrameColors( } lzwDecoder.DecodePixelRow(indicesRow); - ref TPixel rowRef = ref MemoryMarshal.GetReference(imageFrame.PixelBuffer.DangerousGetRowSpan(writeY)); + + // #403 The left + width value can be larger than the image width + int maxX = Math.Min(descriptorRight, imageWidth); + Span row = imageFrame.PixelBuffer.DangerousGetRowSpan(writeY); + + // Take the descriptorLeft..maxX slice of the row, so the loop can be simplified. + row = row[descriptorLeft..maxX]; if (!transFlag) { - // #403 The left + width value can be larger than the image width - for (int x = descriptorLeft; x < descriptorRight && x < imageWidth; x++) + for (int x = 0; x < row.Length; x++) { - int index = Numerics.Clamp(Unsafe.Add(ref indicesRowRef, (uint)(x - descriptorLeft)), 0, colorTableMaxIdx); - Unsafe.Add(ref rowRef, (uint)x) = TPixel.FromRgb24(colorTable[index]); + int index = indicesRow[x]; + index = Numerics.Clamp(index, 0, colorTableMaxIdx); + row[x] = TPixel.FromRgb24(colorTable[index]); } } else { - for (int x = descriptorLeft; x < descriptorRight && x < imageWidth; x++) + for (int x = 0; x < row.Length; x++) { - int index = Unsafe.Add(ref indicesRowRef, (uint)(x - descriptorLeft)); + int index = indicesRow[x]; // Treat any out of bounds values as transparent. if (index > colorTableMaxIdx || index == transIndex) @@ -595,7 +594,7 @@ private void ReadFrameColors( continue; } - Unsafe.Add(ref rowRef, (uint)x) = TPixel.FromRgb24(colorTable[index]); + row[x] = TPixel.FromRgb24(colorTable[index]); } } }