Browse Source

Unified reading rle images

af/merge-core
Brian Popow 6 years ago
parent
commit
2bfe960d6a
  1. 98
      src/ImageSharp/Formats/Tga/TgaDecoderCore.cs

98
src/ImageSharp/Formats/Tga/TgaDecoderCore.cs

@ -84,7 +84,7 @@ namespace SixLabors.ImageSharp.Formats.Tga
case 24:
if (this.fileHeader.ImageType.IsRunLengthEncoded())
{
this.ReadRle24(pixels, this.fileHeader.Width, this.fileHeader.Height);
this.ReadRle(this.fileHeader.Width, this.fileHeader.Height, pixels, 3);
}
else
{
@ -96,7 +96,7 @@ namespace SixLabors.ImageSharp.Formats.Tga
case 32:
if (this.fileHeader.ImageType.IsRunLengthEncoded())
{
this.ReadRle32(pixels, this.fileHeader.Width, this.fileHeader.Height);
this.ReadRle(this.fileHeader.Width, this.fileHeader.Height, pixels, 4);
}
else
{
@ -197,64 +197,6 @@ namespace SixLabors.ImageSharp.Formats.Tga
}
}
private void ReadRle24<TPixel>(Buffer2D<TPixel> pixels, int width, int height)
where TPixel : struct, IPixel<TPixel>
{
TPixel color = default;
using (IMemoryOwner<byte> buffer = this.memoryAllocator.Allocate<byte>(width * height * 3, AllocationOptions.Clean))
{
Span<byte> bufferSpan = buffer.GetSpan();
this.UncompressRle24(width, height, bufferSpan);
for (int y = 0; y < height; y++)
{
Span<TPixel> pixelRow = pixels.GetRowSpan(this.fileHeader.Height - y - 1);
for (int x = 0; x < width; x++)
{
int idx = (y * width * 3) + (x * 3);
color.FromBgr24(Unsafe.As<byte, Bgr24>(ref bufferSpan[idx]));
pixelRow[x] = color;
}
}
}
}
private void UncompressRle24(int width, int height, Span<byte> buffer)
{
int uncompressedPixels = 0;
var pixel = new byte[3];
int totalPixels = width * height;
while (uncompressedPixels < totalPixels)
{
byte runLengthByte = (byte)this.currentStream.ReadByte();
// The high bit of a run length packet is set to 1.
int highBit = runLengthByte >> 7;
if (highBit == 1)
{
int runLength = runLengthByte & 127;
this.currentStream.Read(pixel, 0, 3);
int bufferIdx = uncompressedPixels * 3;
for (int i = 0; i < runLength + 1; i++, uncompressedPixels++)
{
pixel.AsSpan().CopyTo(buffer.Slice(bufferIdx));
bufferIdx += 3;
}
}
else
{
// Non-run-length encoded packet.
int runLength = runLengthByte;
int bufferIdx = uncompressedPixels * 3;
for (int i = 0; i < runLength + 1; i++, uncompressedPixels++)
{
this.currentStream.Read(pixel, 0, 3);
pixel.AsSpan().CopyTo(buffer.Slice(bufferIdx));
bufferIdx += 3;
}
}
}
}
private void ReadBgra32<TPixel>(Buffer2D<TPixel> pixels)
where TPixel : struct, IPixel<TPixel>
{
@ -273,31 +215,41 @@ namespace SixLabors.ImageSharp.Formats.Tga
}
}
private void ReadRle32<TPixel>(Buffer2D<TPixel> pixels, int width, int height)
private void ReadRle<TPixel>(int width, int height, Buffer2D<TPixel> pixels, int bytesPerPixel)
where TPixel : struct, IPixel<TPixel>
{
TPixel color = default;
using (IMemoryOwner<byte> buffer = this.memoryAllocator.Allocate<byte>(width * height * 4, AllocationOptions.Clean))
using (IMemoryOwner<byte> buffer = this.memoryAllocator.Allocate<byte>(width * height * bytesPerPixel, AllocationOptions.Clean))
{
Span<byte> bufferSpan = buffer.GetSpan();
this.UncompressRle32(width, height, bufferSpan);
this.UncompressRle(width, height, bufferSpan, bytesPerPixel);
for (int y = 0; y < height; y++)
{
Span<TPixel> pixelRow = pixels.GetRowSpan(this.fileHeader.Height - y - 1);
int rowStartIdx = y * width * bytesPerPixel;
for (int x = 0; x < width; x++)
{
int idx = (y * width * 4) + (x * 4);
color.FromBgra32(Unsafe.As<byte, Bgra32>(ref bufferSpan[idx]));
int idx = rowStartIdx + (x * bytesPerPixel);
switch (bytesPerPixel)
{
case 4:
color.FromBgra32(Unsafe.As<byte, Bgra32>(ref bufferSpan[idx]));
break;
case 3:
color.FromBgr24(Unsafe.As<byte, Bgr24>(ref bufferSpan[idx]));
break;
}
pixelRow[x] = color;
}
}
}
}
private void UncompressRle32(int width, int height, Span<byte> buffer)
private void UncompressRle(int width, int height, Span<byte> buffer, int bytesPerPixel)
{
int uncompressedPixels = 0;
var pixel = new byte[4];
var pixel = new byte[bytesPerPixel];
int totalPixels = width * height;
while (uncompressedPixels < totalPixels)
{
@ -308,24 +260,24 @@ namespace SixLabors.ImageSharp.Formats.Tga
if (highBit == 1)
{
int runLength = runLengthByte & 127;
this.currentStream.Read(pixel, 0, 4);
int bufferIdx = uncompressedPixels * 4;
this.currentStream.Read(pixel, 0, bytesPerPixel);
int bufferIdx = uncompressedPixels * bytesPerPixel;
for (int i = 0; i < runLength + 1; i++, uncompressedPixels++)
{
pixel.AsSpan().CopyTo(buffer.Slice(bufferIdx));
bufferIdx += 4;
bufferIdx += bytesPerPixel;
}
}
else
{
// Non-run-length encoded packet.
int runLength = runLengthByte;
int bufferIdx = uncompressedPixels * 4;
int bufferIdx = uncompressedPixels * bytesPerPixel;
for (int i = 0; i < runLength + 1; i++, uncompressedPixels++)
{
this.currentStream.Read(pixel, 0, 4);
this.currentStream.Read(pixel, 0, bytesPerPixel);
pixel.AsSpan().CopyTo(buffer.Slice(bufferIdx));
bufferIdx += 4;
bufferIdx += bytesPerPixel;
}
}
}

Loading…
Cancel
Save