Browse Source

Only write RLE packet, if more then 1 equal pixel is found. Write Raw Packet otherwise

pull/2197/head
Brian Popow 4 years ago
parent
commit
5fff1e4241
  1. 129
      src/ImageSharp/Formats/Tga/TgaEncoderCore.cs

129
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;
}
}
}
/// <summary>
/// Finds consecutive pixels which have the same value.
/// Writes a the pixel to the stream.
/// </summary>
/// <typeparam name="TPixel">The type of the pixel.</typeparam>
/// <param name="stream">The stream to write to.</param>
/// <param name="currentPixel">The current pixel.</param>
/// <param name="color">The color of the pixel to write.</param>
private void WritePixel<TPixel>(Stream stream, TPixel currentPixel, Rgba32 color)
where TPixel : unmanaged, IPixel<TPixel>
{
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;
}
}
/// <summary>
/// Finds consecutive pixels which have the same value up to 128 pixels maximum.
/// </summary>
/// <typeparam name="TPixel">The pixel type.</typeparam>
/// <param name="pixelRow">A pixel row of the image to encode.</param>
@ -254,6 +284,39 @@ namespace SixLabors.ImageSharp.Formats.Tga
return equalPixelCount;
}
/// <summary>
/// Finds consecutive pixels which are unequal up to 128 pixels maximum.
/// </summary>
/// <typeparam name="TPixel">The pixel type.</typeparam>
/// <param name="pixelRow">A pixel row of the image to encode.</param>
/// <param name="xStart">X coordinate to start searching for the unequal pixels.</param>
/// <returns>The number of equal pixels.</returns>
private byte FindUnEqualPixels<TPixel>(Span<TPixel> pixelRow, int xStart)
where TPixel : unmanaged, IPixel<TPixel>
{
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<byte> AllocateRow(int width, int bytesPerPixel)
=> this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, bytesPerPixel, 0);

Loading…
Cancel
Save