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: case 24:
if (this.fileHeader.ImageType.IsRunLengthEncoded()) 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 else
{ {
@ -96,7 +96,7 @@ namespace SixLabors.ImageSharp.Formats.Tga
case 32: case 32:
if (this.fileHeader.ImageType.IsRunLengthEncoded()) 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 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) private void ReadBgra32<TPixel>(Buffer2D<TPixel> pixels)
where TPixel : struct, IPixel<TPixel> 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> where TPixel : struct, IPixel<TPixel>
{ {
TPixel color = default; 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(); Span<byte> bufferSpan = buffer.GetSpan();
this.UncompressRle32(width, height, bufferSpan); this.UncompressRle(width, height, bufferSpan, bytesPerPixel);
for (int y = 0; y < height; y++) for (int y = 0; y < height; y++)
{ {
Span<TPixel> pixelRow = pixels.GetRowSpan(this.fileHeader.Height - y - 1); Span<TPixel> pixelRow = pixels.GetRowSpan(this.fileHeader.Height - y - 1);
int rowStartIdx = y * width * bytesPerPixel;
for (int x = 0; x < width; x++) for (int x = 0; x < width; x++)
{ {
int idx = (y * width * 4) + (x * 4); int idx = rowStartIdx + (x * bytesPerPixel);
color.FromBgra32(Unsafe.As<byte, Bgra32>(ref bufferSpan[idx])); 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; 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; int uncompressedPixels = 0;
var pixel = new byte[4]; var pixel = new byte[bytesPerPixel];
int totalPixels = width * height; int totalPixels = width * height;
while (uncompressedPixels < totalPixels) while (uncompressedPixels < totalPixels)
{ {
@ -308,24 +260,24 @@ namespace SixLabors.ImageSharp.Formats.Tga
if (highBit == 1) if (highBit == 1)
{ {
int runLength = runLengthByte & 127; int runLength = runLengthByte & 127;
this.currentStream.Read(pixel, 0, 4); this.currentStream.Read(pixel, 0, bytesPerPixel);
int bufferIdx = uncompressedPixels * 4; int bufferIdx = uncompressedPixels * bytesPerPixel;
for (int i = 0; i < runLength + 1; i++, uncompressedPixels++) for (int i = 0; i < runLength + 1; i++, uncompressedPixels++)
{ {
pixel.AsSpan().CopyTo(buffer.Slice(bufferIdx)); pixel.AsSpan().CopyTo(buffer.Slice(bufferIdx));
bufferIdx += 4; bufferIdx += bytesPerPixel;
} }
} }
else else
{ {
// Non-run-length encoded packet. // Non-run-length encoded packet.
int runLength = runLengthByte; int runLength = runLengthByte;
int bufferIdx = uncompressedPixels * 4; int bufferIdx = uncompressedPixels * bytesPerPixel;
for (int i = 0; i < runLength + 1; i++, uncompressedPixels++) 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)); pixel.AsSpan().CopyTo(buffer.Slice(bufferIdx));
bufferIdx += 4; bufferIdx += bytesPerPixel;
} }
} }
} }

Loading…
Cancel
Save