diff --git a/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs b/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs
index e7dca00f79..26e057bff9 100644
--- a/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs
+++ b/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs
@@ -17,11 +17,6 @@ namespace SixLabors.ImageSharp.Formats.Tga;
///
internal sealed class TgaDecoderCore : IImageDecoderInternals
{
- ///
- /// A scratch buffer to reduce allocations.
- ///
- private readonly byte[] scratchBuffer = new byte[4];
-
///
/// General configuration options.
///
@@ -407,6 +402,7 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
bool invertX = InvertX(origin);
using IMemoryOwner row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 2, 0);
Span rowSpan = row.GetSpan();
+ Span scratchBuffer = stackalloc byte[2];
for (int y = 0; y < height; y++)
{
@@ -417,7 +413,7 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
{
for (int x = width - 1; x >= 0; x--)
{
- int bytesRead = stream.Read(this.scratchBuffer, 0, 2);
+ int bytesRead = stream.Read(scratchBuffer);
if (bytesRead != 2)
{
TgaThrowHelper.ThrowInvalidImageContentException("Not enough data to read a pixel row");
@@ -425,16 +421,16 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
if (!this.hasAlpha)
{
- this.scratchBuffer[1] |= 1 << 7;
+ scratchBuffer[1] |= 1 << 7;
}
if (this.fileHeader.ImageType == TgaImageType.BlackAndWhite)
{
- color.FromLa16(Unsafe.As(ref MemoryMarshal.GetArrayDataReference(this.scratchBuffer)));
+ color.FromLa16(Unsafe.As(ref MemoryMarshal.GetReference(scratchBuffer)));
}
else
{
- color.FromBgra5551(Unsafe.As(ref MemoryMarshal.GetArrayDataReference(this.scratchBuffer)));
+ color.FromBgra5551(Unsafe.As(ref MemoryMarshal.GetReference(scratchBuffer)));
}
pixelSpan[x] = color;
@@ -484,6 +480,7 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
bool invertX = InvertX(origin);
if (invertX)
{
+ Span scratchBuffer = stackalloc byte[4];
TPixel color = default;
for (int y = 0; y < height; y++)
{
@@ -491,7 +488,7 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
Span pixelSpan = pixels.DangerousGetRowSpan(newY);
for (int x = width - 1; x >= 0; x--)
{
- this.ReadBgr24Pixel(stream, color, x, pixelSpan);
+ ReadBgr24Pixel(stream, color, x, pixelSpan, scratchBuffer);
}
}
@@ -558,6 +555,8 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
return;
}
+ Span scratchBuffer = stackalloc byte[4];
+
for (int y = 0; y < height; y++)
{
int newY = InvertY(y, height, origin);
@@ -566,14 +565,14 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
{
for (int x = width - 1; x >= 0; x--)
{
- this.ReadBgra32Pixel(stream, x, color, pixelRow);
+ this.ReadBgra32Pixel(stream, x, color, pixelRow, scratchBuffer);
}
}
else
{
for (int x = 0; x < width; x++)
{
- this.ReadBgra32Pixel(stream, x, color, pixelRow);
+ this.ReadBgra32Pixel(stream, x, color, pixelRow, scratchBuffer);
}
}
}
@@ -687,16 +686,16 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void ReadBgr24Pixel(BufferedReadStream stream, TPixel color, int x, Span pixelSpan)
+ private static void ReadBgr24Pixel(BufferedReadStream stream, TPixel color, int x, Span pixelSpan, Span scratchBuffer)
where TPixel : unmanaged, IPixel
{
- int bytesRead = stream.Read(this.scratchBuffer, 0, 3);
+ int bytesRead = stream.Read(scratchBuffer, 0, 3);
if (bytesRead != 3)
{
TgaThrowHelper.ThrowInvalidImageContentException("Not enough data to read a bgr pixel");
}
- color.FromBgr24(Unsafe.As(ref MemoryMarshal.GetArrayDataReference(this.scratchBuffer)));
+ color.FromBgr24(Unsafe.As(ref MemoryMarshal.GetReference(scratchBuffer)));
pixelSpan[x] = color;
}
@@ -715,10 +714,10 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void ReadBgra32Pixel(BufferedReadStream stream, int x, TPixel color, Span pixelRow)
+ private void ReadBgra32Pixel(BufferedReadStream stream, int x, TPixel color, Span pixelRow, Span scratchBuffer)
where TPixel : unmanaged, IPixel
{
- int bytesRead = stream.Read(this.scratchBuffer, 0, 4);
+ int bytesRead = stream.Read(scratchBuffer, 0, 4);
if (bytesRead != 4)
{
TgaThrowHelper.ThrowInvalidImageContentException("Not enough data to read a bgra pixel");
@@ -726,8 +725,8 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
Guard.NotNull(this.tgaMetadata);
- byte alpha = this.tgaMetadata.AlphaChannelBits == 0 ? byte.MaxValue : this.scratchBuffer[3];
- color.FromBgra32(new Bgra32(this.scratchBuffer[2], this.scratchBuffer[1], this.scratchBuffer[0], alpha));
+ byte alpha = this.tgaMetadata.AlphaChannelBits == 0 ? byte.MaxValue : scratchBuffer[3];
+ color.FromBgra32(new Bgra32(scratchBuffer[2], scratchBuffer[1], scratchBuffer[0], alpha));
pixelRow[x] = color;
}
@@ -814,7 +813,7 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
private void UncompressRle(BufferedReadStream stream, int width, int height, Span buffer, int bytesPerPixel)
{
int uncompressedPixels = 0;
- Span pixel = this.scratchBuffer.AsSpan(0, bytesPerPixel);
+ Span pixel = stackalloc byte[bytesPerPixel];
int totalPixels = width * height;
while (uncompressedPixels < totalPixels)
{
@@ -825,7 +824,7 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
if (highBit == 1)
{
int runLength = runLengthByte & 127;
- int bytesRead = stream.Read(pixel, 0, bytesPerPixel);
+ int bytesRead = stream.Read(pixel);
if (bytesRead != bytesPerPixel)
{
TgaThrowHelper.ThrowInvalidImageContentException("Not enough data to read a pixel from the stream");
@@ -845,7 +844,7 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
int bufferIdx = uncompressedPixels * bytesPerPixel;
for (int i = 0; i < runLength + 1; i++, uncompressedPixels++)
{
- int bytesRead = stream.Read(pixel, 0, bytesPerPixel);
+ int bytesRead = stream.Read(pixel);
if (bytesRead != bytesPerPixel)
{
TgaThrowHelper.ThrowInvalidImageContentException("Not enough data to read a pixel from the stream");
diff --git a/src/ImageSharp/Formats/Tga/TgaEncoderCore.cs b/src/ImageSharp/Formats/Tga/TgaEncoderCore.cs
index f468ab9ae7..ad63bd356d 100644
--- a/src/ImageSharp/Formats/Tga/TgaEncoderCore.cs
+++ b/src/ImageSharp/Formats/Tga/TgaEncoderCore.cs
@@ -22,11 +22,6 @@ internal sealed class TgaEncoderCore : IImageEncoderInternals
///
private readonly MemoryAllocator memoryAllocator;
- ///
- /// Reusable buffer for writing data.
- ///
- private readonly byte[] buffer = new byte[2];
-
///
/// The color depth, in number of bits per pixel.
///
@@ -221,9 +216,10 @@ internal sealed class TgaEncoderCore : IImageEncoderInternals
case TgaBitsPerPixel.Pixel16:
Bgra5551 bgra5551 = new(color.ToVector4());
- BinaryPrimitives.WriteInt16LittleEndian(this.buffer, (short)bgra5551.PackedValue);
- stream.WriteByte(this.buffer[0]);
- stream.WriteByte(this.buffer[1]);
+ Span buffer = stackalloc byte[2];
+ BinaryPrimitives.WriteInt16LittleEndian(buffer, (short)bgra5551.PackedValue);
+ stream.WriteByte(buffer[0]);
+ stream.WriteByte(buffer[1]);
break;