Browse Source

Add support for decoding rle tga with palette

af/merge-core
Brian Popow 7 years ago
parent
commit
dce04067d8
  1. 84
      src/ImageSharp/Formats/Tga/TgaDecoderCore.cs

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

@ -72,8 +72,7 @@ namespace SixLabors.ImageSharp.Formats.Tga
try try
{ {
this.ReadFileHeader(stream); this.ReadFileHeader(stream);
this.currentStream.Skip(this.fileHeader.IdLength);
// TODO: parse ID
// Parse the color map, if present. // Parse the color map, if present.
if (this.fileHeader.ColorMapType != 0 && this.fileHeader.ColorMapType != 1) if (this.fileHeader.ColorMapType != 0 && this.fileHeader.ColorMapType != 1)
@ -81,9 +80,12 @@ namespace SixLabors.ImageSharp.Formats.Tga
TgaThrowHelper.ThrowNotSupportedException($"Unknown tga colormap type {this.fileHeader.ColorMapType} found"); TgaThrowHelper.ThrowNotSupportedException($"Unknown tga colormap type {this.fileHeader.ColorMapType} found");
} }
var image = new Image<TPixel>(this.configuration, this.fileHeader.Width, this.fileHeader.Height, this.metadata);
Buffer2D<TPixel> pixels = image.GetRootFramePixelBuffer();
byte[] palette = null; byte[] palette = null;
int colorMapPixelSizeInBytes = 0; int colorMapPixelSizeInBytes = 0;
if (this.fileHeader.ColorMapType == 1) if (this.fileHeader.ColorMapType is 1)
{ {
if (this.fileHeader.CMapLength <= 0) if (this.fileHeader.CMapLength <= 0)
{ {
@ -98,19 +100,16 @@ namespace SixLabors.ImageSharp.Formats.Tga
colorMapPixelSizeInBytes = this.fileHeader.CMapDepth / 8; colorMapPixelSizeInBytes = this.fileHeader.CMapDepth / 8;
palette = new byte[this.fileHeader.CMapLength * colorMapPixelSizeInBytes]; palette = new byte[this.fileHeader.CMapLength * colorMapPixelSizeInBytes];
this.currentStream.Read(palette, this.fileHeader.CMapStart, palette.Length); this.currentStream.Read(palette, this.fileHeader.CMapStart, palette.Length);
}
var image = new Image<TPixel>(this.configuration, this.fileHeader.Width, this.fileHeader.Height, this.metadata); if (this.fileHeader.ImageType is TgaImageType.RleColorMapped)
Buffer2D<TPixel> pixels = image.GetRootFramePixelBuffer(); {
this.ReadPalettedRle(this.fileHeader.Width, this.fileHeader.Height, pixels, palette, colorMapPixelSizeInBytes);
if (this.fileHeader.ImageType == TgaImageType.ColorMapped) }
{ else
if (palette is null)
{ {
TgaThrowHelper.ThrowImageFormatException("Tga image is missing a color palette"); this.ReadPaletted(this.fileHeader.Width, this.fileHeader.Height, pixels, palette, colorMapPixelSizeInBytes);
} }
this.ReadPaletted(this.fileHeader.Width, this.fileHeader.Height, pixels, palette, colorMapPixelSizeInBytes);
return image; return image;
} }
@ -128,6 +127,7 @@ namespace SixLabors.ImageSharp.Formats.Tga
break; break;
case 15:
case 16: case 16:
if (this.fileHeader.ImageType.IsRunLengthEncoded()) if (this.fileHeader.ImageType.IsRunLengthEncoded())
{ {
@ -178,7 +178,7 @@ namespace SixLabors.ImageSharp.Formats.Tga
} }
} }
private void ReadPaletted<TPixel>(int width, int height, Buffer2D<TPixel> pixels, byte[] palette, int pixelSizeInBytes) private void ReadPaletted<TPixel>(int width, int height, Buffer2D<TPixel> pixels, byte[] palette, int colorMapPixelSizeInBytes)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
using (IManagedByteBuffer row = this.memoryAllocator.AllocateManagedByteBuffer(width, AllocationOptions.Clean)) using (IManagedByteBuffer row = this.memoryAllocator.AllocateManagedByteBuffer(width, AllocationOptions.Clean))
@ -190,23 +190,13 @@ namespace SixLabors.ImageSharp.Formats.Tga
{ {
this.currentStream.Read(row); this.currentStream.Read(row);
Span<TPixel> pixelRow = pixels.GetRowSpan(height - y - 1); Span<TPixel> pixelRow = pixels.GetRowSpan(height - y - 1);
switch (pixelSizeInBytes) switch (colorMapPixelSizeInBytes)
{ {
case 1:
for (int x = 0; x < width; x++)
{
int colorIndex = rowSpan[x];
color.FromGray8(Unsafe.As<byte, Gray8>(ref palette[colorIndex]));
pixelRow[x] = color;
}
break;
case 2: case 2:
for (int x = 0; x < width; x++) for (int x = 0; x < width; x++)
{ {
int colorIndex = rowSpan[x]; int colorIndex = rowSpan[x];
color.FromBgra5551(Unsafe.As<byte, Bgra5551>(ref palette[colorIndex * pixelSizeInBytes])); color.FromBgra5551(Unsafe.As<byte, Bgra5551>(ref palette[colorIndex * colorMapPixelSizeInBytes]));
pixelRow[x] = color; pixelRow[x] = color;
} }
@ -216,7 +206,7 @@ namespace SixLabors.ImageSharp.Formats.Tga
for (int x = 0; x < width; x++) for (int x = 0; x < width; x++)
{ {
int colorIndex = rowSpan[x]; int colorIndex = rowSpan[x];
color.FromBgr24(Unsafe.As<byte, Bgr24>(ref palette[colorIndex * pixelSizeInBytes])); color.FromBgr24(Unsafe.As<byte, Bgr24>(ref palette[colorIndex * colorMapPixelSizeInBytes]));
pixelRow[x] = color; pixelRow[x] = color;
} }
@ -226,7 +216,7 @@ namespace SixLabors.ImageSharp.Formats.Tga
for (int x = 0; x < width; x++) for (int x = 0; x < width; x++)
{ {
int colorIndex = rowSpan[x]; int colorIndex = rowSpan[x];
color.FromBgra32(Unsafe.As<byte, Bgra32>(ref palette[colorIndex * pixelSizeInBytes])); color.FromBgra32(Unsafe.As<byte, Bgra32>(ref palette[colorIndex * colorMapPixelSizeInBytes]));
pixelRow[x] = color; pixelRow[x] = color;
} }
@ -236,6 +226,45 @@ namespace SixLabors.ImageSharp.Formats.Tga
} }
} }
private void ReadPalettedRle<TPixel>(int width, int height, Buffer2D<TPixel> pixels, byte[] palette, int colorMapPixelSizeInBytes)
where TPixel : struct, IPixel<TPixel>
{
int bytesPerPixel = 1;
using (IMemoryOwner<byte> buffer = this.memoryAllocator.Allocate<byte>(width * height * bytesPerPixel, AllocationOptions.Clean))
{
TPixel color = default;
Span<byte> bufferSpan = buffer.GetSpan();
this.UncompressRle(width, height, bufferSpan, bytesPerPixel: 1);
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 = rowStartIdx + x;
switch (colorMapPixelSizeInBytes)
{
case 1:
color.FromGray8(Unsafe.As<byte, Gray8>(ref palette[bufferSpan[idx] * colorMapPixelSizeInBytes]));
break;
case 2:
color.FromBgra5551(Unsafe.As<byte, Bgra5551>(ref palette[bufferSpan[idx] * colorMapPixelSizeInBytes]));
break;
case 3:
color.FromBgr24(Unsafe.As<byte, Bgr24>(ref palette[bufferSpan[idx] * colorMapPixelSizeInBytes]));
break;
case 4:
color.FromBgra32(Unsafe.As<byte, Bgra32>(ref palette[bufferSpan[idx] * colorMapPixelSizeInBytes]));
break;
}
pixelRow[x] = color;
}
}
}
}
private void ReadMonoChrome<TPixel>(int width, int height, Buffer2D<TPixel> pixels) private void ReadMonoChrome<TPixel>(int width, int height, Buffer2D<TPixel> pixels)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
@ -335,6 +364,7 @@ namespace SixLabors.ImageSharp.Formats.Tga
color.FromGray8(Unsafe.As<byte, Gray8>(ref bufferSpan[idx])); color.FromGray8(Unsafe.As<byte, Gray8>(ref bufferSpan[idx]));
break; break;
case 2: case 2:
// Set bit 16 to 1, to treat it as opaque for Bgra5551.
bufferSpan[idx + 1] = (byte)(bufferSpan[idx + 1] | 128); bufferSpan[idx + 1] = (byte)(bufferSpan[idx + 1] | 128);
color.FromBgra5551(Unsafe.As<byte, Bgra5551>(ref bufferSpan[idx])); color.FromBgra5551(Unsafe.As<byte, Bgra5551>(ref bufferSpan[idx]));
break; break;

Loading…
Cancel
Save