diff --git a/src/ImageSharp/Formats/Tga/TgaEncoderCore.cs b/src/ImageSharp/Formats/Tga/TgaEncoderCore.cs
index 91a738c26d..b891885793 100644
--- a/src/ImageSharp/Formats/Tga/TgaEncoderCore.cs
+++ b/src/ImageSharp/Formats/Tga/TgaEncoderCore.cs
@@ -183,46 +183,76 @@ namespace SixLabors.ImageSharp.Formats.Tga
currentPixel.ToRgba32(ref color);
byte equalPixelCount = this.FindEqualPixels(pixelRow, x);
- // Write the number of equal pixels, with the high bit set, indicating ist a compressed pixel run.
- stream.WriteByte((byte)(equalPixelCount | 128));
- switch (this.bitsPerPixel)
+ if (equalPixelCount > 0)
{
- case TgaBitsPerPixel.Pixel8:
- int luminance = GetLuminance(currentPixel);
- stream.WriteByte((byte)luminance);
- break;
-
- case TgaBitsPerPixel.Pixel16:
- var bgra5551 = new Bgra5551(color.ToVector4());
- BinaryPrimitives.TryWriteInt16LittleEndian(this.buffer, (short)bgra5551.PackedValue);
- stream.WriteByte(this.buffer[0]);
- stream.WriteByte(this.buffer[1]);
-
- break;
-
- case TgaBitsPerPixel.Pixel24:
- stream.WriteByte(color.B);
- stream.WriteByte(color.G);
- stream.WriteByte(color.R);
- break;
-
- case TgaBitsPerPixel.Pixel32:
- stream.WriteByte(color.B);
- stream.WriteByte(color.G);
- stream.WriteByte(color.R);
- stream.WriteByte(color.A);
- break;
- default:
- break;
+ // Write the number of equal pixels, with the high bit set, indicating ist a compressed pixel run.
+ stream.WriteByte((byte)(equalPixelCount | 128));
+ this.WritePixel(stream, currentPixel, color);
+ x += equalPixelCount + 1;
+ }
+ else
+ {
+ // Write Raw Packet (i.e., Non-Run-Length Encoded):
+ byte unEqualPixelCount = this.FindUnEqualPixels(pixelRow, x);
+ stream.WriteByte(unEqualPixelCount);
+ this.WritePixel(stream, currentPixel, color);
+ x++;
+ for (int i = 0; i < unEqualPixelCount; i++)
+ {
+ currentPixel = pixelRow[x];
+ currentPixel.ToRgba32(ref color);
+ this.WritePixel(stream, currentPixel, color);
+ x++;
+ }
}
-
- x += equalPixelCount + 1;
}
}
}
///
- /// Finds consecutive pixels which have the same value.
+ /// Writes a the pixel to the stream.
+ ///
+ /// The type of the pixel.
+ /// The stream to write to.
+ /// The current pixel.
+ /// The color of the pixel to write.
+ private void WritePixel(Stream stream, TPixel currentPixel, Rgba32 color)
+ where TPixel : unmanaged, IPixel
+ {
+ switch (this.bitsPerPixel)
+ {
+ case TgaBitsPerPixel.Pixel8:
+ int luminance = GetLuminance(currentPixel);
+ stream.WriteByte((byte)luminance);
+ break;
+
+ case TgaBitsPerPixel.Pixel16:
+ var bgra5551 = new Bgra5551(color.ToVector4());
+ BinaryPrimitives.TryWriteInt16LittleEndian(this.buffer, (short)bgra5551.PackedValue);
+ stream.WriteByte(this.buffer[0]);
+ stream.WriteByte(this.buffer[1]);
+
+ break;
+
+ case TgaBitsPerPixel.Pixel24:
+ stream.WriteByte(color.B);
+ stream.WriteByte(color.G);
+ stream.WriteByte(color.R);
+ break;
+
+ case TgaBitsPerPixel.Pixel32:
+ stream.WriteByte(color.B);
+ stream.WriteByte(color.G);
+ stream.WriteByte(color.R);
+ stream.WriteByte(color.A);
+ break;
+ default:
+ break;
+ }
+ }
+
+ ///
+ /// Finds consecutive pixels which have the same value up to 128 pixels maximum.
///
/// The pixel type.
/// A pixel row of the image to encode.
@@ -254,6 +284,39 @@ namespace SixLabors.ImageSharp.Formats.Tga
return equalPixelCount;
}
+ ///
+ /// Finds consecutive pixels which are unequal up to 128 pixels maximum.
+ ///
+ /// The pixel type.
+ /// A pixel row of the image to encode.
+ /// X coordinate to start searching for the unequal pixels.
+ /// The number of equal pixels.
+ private byte FindUnEqualPixels(Span pixelRow, int xStart)
+ where TPixel : unmanaged, IPixel
+ {
+ byte unEqualPixelCount = 0;
+ TPixel currentPixel = pixelRow[xStart];
+ for (int x = xStart + 1; x < pixelRow.Length; x++)
+ {
+ TPixel nextPixel = pixelRow[x];
+ if (currentPixel.Equals(nextPixel))
+ {
+ return (byte)Math.Max(0, unEqualPixelCount - 1);
+ }
+
+ unEqualPixelCount++;
+
+ if (unEqualPixelCount >= 127)
+ {
+ return unEqualPixelCount;
+ }
+
+ currentPixel = nextPixel;
+ }
+
+ return (byte)Math.Max(0, unEqualPixelCount - 1);
+ }
+
private IMemoryOwner AllocateRow(int width, int bytesPerPixel)
=> this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, bytesPerPixel, 0);