Browse Source

Merge pull request #1160 from SixLabors/bp/tgaImageOrigin

TGA image origin and support decoding 16bit monochome images
pull/1171/head
James Jackson-South 6 years ago
committed by GitHub
parent
commit
fedf5b776a
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 494
      src/ImageSharp/Formats/Tga/TgaDecoderCore.cs
  2. 28
      src/ImageSharp/Formats/Tga/TgaImageOrigin.cs
  3. 2
      tests/Directory.Build.targets
  4. 2
      tests/ImageSharp.Benchmarks/Codecs/DecodeTga.cs
  5. 2
      tests/ImageSharp.Benchmarks/Codecs/EncodeTga.cs
  6. 460
      tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs
  7. 32
      tests/ImageSharp.Tests/Formats/Tga/TgaEncoderTests.cs
  8. 1
      tests/ImageSharp.Tests/Formats/Tga/TgaTestUtils.cs
  9. 64
      tests/ImageSharp.Tests/TestImages.cs
  10. 2
      tests/Images/External
  11. BIN
      tests/Images/Input/Tga/grayscale_LL.tga
  12. BIN
      tests/Images/Input/Tga/grayscale_LR.tga
  13. BIN
      tests/Images/Input/Tga/grayscale_UL.tga
  14. BIN
      tests/Images/Input/Tga/grayscale_UR.tga
  15. BIN
      tests/Images/Input/Tga/grayscale_a_LL.tga
  16. BIN
      tests/Images/Input/Tga/grayscale_a_LR.tga
  17. BIN
      tests/Images/Input/Tga/grayscale_a_UL.tga
  18. BIN
      tests/Images/Input/Tga/grayscale_a_UR.tga
  19. BIN
      tests/Images/Input/Tga/grayscale_a_rle_LL.tga
  20. BIN
      tests/Images/Input/Tga/grayscale_a_rle_LR.tga
  21. BIN
      tests/Images/Input/Tga/grayscale_a_rle_UL.tga
  22. BIN
      tests/Images/Input/Tga/grayscale_a_rle_UR.tga
  23. BIN
      tests/Images/Input/Tga/grayscale_rle_LR.tga
  24. BIN
      tests/Images/Input/Tga/grayscale_rle_UL.tga
  25. BIN
      tests/Images/Input/Tga/grayscale_rle_UR.tga
  26. BIN
      tests/Images/Input/Tga/indexed_LR.tga
  27. BIN
      tests/Images/Input/Tga/indexed_UL.tga
  28. BIN
      tests/Images/Input/Tga/indexed_UR.tga
  29. BIN
      tests/Images/Input/Tga/indexed_a_LL.tga
  30. BIN
      tests/Images/Input/Tga/indexed_a_LR.tga
  31. BIN
      tests/Images/Input/Tga/indexed_a_UL.tga
  32. BIN
      tests/Images/Input/Tga/indexed_a_UR.tga
  33. BIN
      tests/Images/Input/Tga/rgb24_top_left.tga
  34. BIN
      tests/Images/Input/Tga/rgb_LR.tga
  35. BIN
      tests/Images/Input/Tga/rgb_UR.tga
  36. BIN
      tests/Images/Input/Tga/rgb_a_LL.tga
  37. BIN
      tests/Images/Input/Tga/rgb_a_LR.tga
  38. BIN
      tests/Images/Input/Tga/rgb_a_UL.tga
  39. BIN
      tests/Images/Input/Tga/rgb_a_UR.tga
  40. BIN
      tests/Images/Input/Tga/rgb_a_rle_LR.tga
  41. BIN
      tests/Images/Input/Tga/rgb_a_rle_UL.tga
  42. BIN
      tests/Images/Input/Tga/rgb_a_rle_UR.tga
  43. BIN
      tests/Images/Input/Tga/rgb_rle_LR.tga
  44. BIN
      tests/Images/Input/Tga/rgb_rle_UR.tga

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

@ -17,6 +17,11 @@ namespace SixLabors.ImageSharp.Formats.Tga
/// </summary>
internal sealed class TgaDecoderCore
{
/// <summary>
/// A scratch buffer to reduce allocations.
/// </summary>
private readonly byte[] scratchBuffer = new byte[4];
/// <summary>
/// The metadata.
/// </summary>
@ -88,7 +93,7 @@ namespace SixLabors.ImageSharp.Formats.Tga
{
try
{
bool inverted = this.ReadFileHeader(stream);
TgaImageOrigin origin = this.ReadFileHeader(stream);
this.currentStream.Skip(this.fileHeader.IdLength);
// Parse the color map, if present.
@ -131,7 +136,7 @@ namespace SixLabors.ImageSharp.Formats.Tga
pixels,
palette.Array,
colorMapPixelSizeInBytes,
inverted);
origin);
}
else
{
@ -141,7 +146,7 @@ namespace SixLabors.ImageSharp.Formats.Tga
pixels,
palette.Array,
colorMapPixelSizeInBytes,
inverted);
origin);
}
}
@ -160,11 +165,11 @@ namespace SixLabors.ImageSharp.Formats.Tga
case 8:
if (this.fileHeader.ImageType.IsRunLengthEncoded())
{
this.ReadRle(this.fileHeader.Width, this.fileHeader.Height, pixels, 1, inverted);
this.ReadRle(this.fileHeader.Width, this.fileHeader.Height, pixels, 1, origin);
}
else
{
this.ReadMonoChrome(this.fileHeader.Width, this.fileHeader.Height, pixels, inverted);
this.ReadMonoChrome(this.fileHeader.Width, this.fileHeader.Height, pixels, origin);
}
break;
@ -173,11 +178,11 @@ namespace SixLabors.ImageSharp.Formats.Tga
case 16:
if (this.fileHeader.ImageType.IsRunLengthEncoded())
{
this.ReadRle(this.fileHeader.Width, this.fileHeader.Height, pixels, 2, inverted);
this.ReadRle(this.fileHeader.Width, this.fileHeader.Height, pixels, 2, origin);
}
else
{
this.ReadBgra16(this.fileHeader.Width, this.fileHeader.Height, pixels, inverted);
this.ReadBgra16(this.fileHeader.Width, this.fileHeader.Height, pixels, origin);
}
break;
@ -185,11 +190,11 @@ namespace SixLabors.ImageSharp.Formats.Tga
case 24:
if (this.fileHeader.ImageType.IsRunLengthEncoded())
{
this.ReadRle(this.fileHeader.Width, this.fileHeader.Height, pixels, 3, inverted);
this.ReadRle(this.fileHeader.Width, this.fileHeader.Height, pixels, 3, origin);
}
else
{
this.ReadBgr24(this.fileHeader.Width, this.fileHeader.Height, pixels, inverted);
this.ReadBgr24(this.fileHeader.Width, this.fileHeader.Height, pixels, origin);
}
break;
@ -197,11 +202,11 @@ namespace SixLabors.ImageSharp.Formats.Tga
case 32:
if (this.fileHeader.ImageType.IsRunLengthEncoded())
{
this.ReadRle(this.fileHeader.Width, this.fileHeader.Height, pixels, 4, inverted);
this.ReadRle(this.fileHeader.Width, this.fileHeader.Height, pixels, 4, origin);
}
else
{
this.ReadBgra32(this.fileHeader.Width, this.fileHeader.Height, pixels, inverted);
this.ReadBgra32(this.fileHeader.Width, this.fileHeader.Height, pixels, origin);
}
break;
@ -228,60 +233,73 @@ namespace SixLabors.ImageSharp.Formats.Tga
/// <param name="pixels">The <see cref="Buffer2D{TPixel}"/> to assign the palette to.</param>
/// <param name="palette">The color palette.</param>
/// <param name="colorMapPixelSizeInBytes">Color map size of one entry in bytes.</param>
/// <param name="inverted">Indicates, if the origin of the image is top left rather the bottom left (the default).</param>
private void ReadPaletted<TPixel>(int width, int height, Buffer2D<TPixel> pixels, byte[] palette, int colorMapPixelSizeInBytes, bool inverted)
/// <param name="origin">The image origin.</param>
private void ReadPaletted<TPixel>(int width, int height, Buffer2D<TPixel> pixels, byte[] palette, int colorMapPixelSizeInBytes, TgaImageOrigin origin)
where TPixel : unmanaged, IPixel<TPixel>
{
using (IManagedByteBuffer row = this.memoryAllocator.AllocateManagedByteBuffer(width, AllocationOptions.Clean))
TPixel color = default;
bool invertX = InvertX(origin);
for (int y = 0; y < height; y++)
{
TPixel color = default;
Span<byte> rowSpan = row.GetSpan();
int newY = InvertY(y, height, origin);
Span<TPixel> pixelRow = pixels.GetRowSpan(newY);
for (int y = 0; y < height; y++)
switch (colorMapPixelSizeInBytes)
{
this.currentStream.Read(row);
int newY = Invert(y, height, inverted);
Span<TPixel> pixelRow = pixels.GetRowSpan(newY);
switch (colorMapPixelSizeInBytes)
{
case 2:
case 2:
if (invertX)
{
for (int x = width - 1; x >= 0; x--)
{
this.ReadPalettedBgr16Pixel(palette, colorMapPixelSizeInBytes, x, color, pixelRow);
}
}
else
{
for (int x = 0; x < width; x++)
{
int colorIndex = rowSpan[x];
Bgra5551 bgra = Unsafe.As<byte, Bgra5551>(ref palette[colorIndex * colorMapPixelSizeInBytes]);
if (!this.hasAlpha)
{
// Set alpha value to 1, to treat it as opaque for Bgra5551.
bgra.PackedValue = (ushort)(bgra.PackedValue | 0x8000);
}
color.FromBgra5551(bgra);
pixelRow[x] = color;
this.ReadPalettedBgr16Pixel(palette, colorMapPixelSizeInBytes, x, color, pixelRow);
}
}
break;
break;
case 3:
case 3:
if (invertX)
{
for (int x = width - 1; x >= 0; x--)
{
this.ReadPalettedBgr24Pixel(palette, colorMapPixelSizeInBytes, x, color, pixelRow);
}
}
else
{
for (int x = 0; x < width; x++)
{
int colorIndex = rowSpan[x];
color.FromBgr24(Unsafe.As<byte, Bgr24>(ref palette[colorIndex * colorMapPixelSizeInBytes]));
pixelRow[x] = color;
this.ReadPalettedBgr24Pixel(palette, colorMapPixelSizeInBytes, x, color, pixelRow);
}
}
break;
break;
case 4:
case 4:
if (invertX)
{
for (int x = width - 1; x >= 0; x--)
{
this.ReadPalettedBgra32Pixel(palette, colorMapPixelSizeInBytes, x, color, pixelRow);
}
}
else
{
for (int x = 0; x < width; x++)
{
int colorIndex = rowSpan[x];
color.FromBgra32(Unsafe.As<byte, Bgra32>(ref palette[colorIndex * colorMapPixelSizeInBytes]));
pixelRow[x] = color;
this.ReadPalettedBgra32Pixel(palette, colorMapPixelSizeInBytes, x, color, pixelRow);
}
}
break;
}
break;
}
}
}
@ -295,8 +313,8 @@ namespace SixLabors.ImageSharp.Formats.Tga
/// <param name="pixels">The <see cref="Buffer2D{TPixel}"/> to assign the palette to.</param>
/// <param name="palette">The color palette.</param>
/// <param name="colorMapPixelSizeInBytes">Color map size of one entry in bytes.</param>
/// <param name="inverted">Indicates, if the origin of the image is top left rather the bottom left (the default).</param>
private void ReadPalettedRle<TPixel>(int width, int height, Buffer2D<TPixel> pixels, byte[] palette, int colorMapPixelSizeInBytes, bool inverted)
/// <param name="origin">The image origin.</param>
private void ReadPalettedRle<TPixel>(int width, int height, Buffer2D<TPixel> pixels, byte[] palette, int colorMapPixelSizeInBytes, TgaImageOrigin origin)
where TPixel : unmanaged, IPixel<TPixel>
{
int bytesPerPixel = 1;
@ -309,7 +327,7 @@ namespace SixLabors.ImageSharp.Formats.Tga
for (int y = 0; y < height; y++)
{
int newY = Invert(y, height, inverted);
int newY = InvertY(y, height, origin);
Span<TPixel> pixelRow = pixels.GetRowSpan(newY);
int rowStartIdx = y * width * bytesPerPixel;
for (int x = 0; x < width; x++)
@ -348,7 +366,8 @@ namespace SixLabors.ImageSharp.Formats.Tga
break;
}
pixelRow[x] = color;
int newX = InvertX(x, width, origin);
pixelRow[newX] = color;
}
}
}
@ -361,18 +380,43 @@ namespace SixLabors.ImageSharp.Formats.Tga
/// <param name="width">The width of the image.</param>
/// <param name="height">The height of the image.</param>
/// <param name="pixels">The <see cref="Buffer2D{TPixel}"/> to assign the palette to.</param>
/// <param name="inverted">Indicates, if the origin of the image is top left rather the bottom left (the default).</param>
private void ReadMonoChrome<TPixel>(int width, int height, Buffer2D<TPixel> pixels, bool inverted)
/// <param name="origin">the image origin.</param>
private void ReadMonoChrome<TPixel>(int width, int height, Buffer2D<TPixel> pixels, TgaImageOrigin origin)
where TPixel : unmanaged, IPixel<TPixel>
{
using (IManagedByteBuffer row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 1, 0))
bool invertX = InvertX(origin);
if (invertX)
{
TPixel color = default;
for (int y = 0; y < height; y++)
{
this.currentStream.Read(row);
int newY = Invert(y, height, inverted);
int newY = InvertY(y, height, origin);
Span<TPixel> pixelSpan = pixels.GetRowSpan(newY);
PixelOperations<TPixel>.Instance.FromL8Bytes(this.configuration, row.GetSpan(), pixelSpan, width);
for (int x = width - 1; x >= 0; x--)
{
this.ReadL8Pixel(color, x, pixelSpan);
}
}
return;
}
using (IManagedByteBuffer row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 1, 0))
{
bool invertY = InvertY(origin);
if (invertY)
{
for (int y = height - 1; y >= 0; y--)
{
this.ReadL8Row(width, pixels, row, y);
}
}
else
{
for (int y = 0; y < height; y++)
{
this.ReadL8Row(width, pixels, row, y);
}
}
}
}
@ -384,29 +428,64 @@ namespace SixLabors.ImageSharp.Formats.Tga
/// <param name="width">The width of the image.</param>
/// <param name="height">The height of the image.</param>
/// <param name="pixels">The <see cref="Buffer2D{TPixel}"/> to assign the palette to.</param>
/// <param name="inverted">Indicates, if the origin of the image is top left rather the bottom left (the default).</param>
private void ReadBgra16<TPixel>(int width, int height, Buffer2D<TPixel> pixels, bool inverted)
/// <param name="origin">The image origin.</param>
private void ReadBgra16<TPixel>(int width, int height, Buffer2D<TPixel> pixels, TgaImageOrigin origin)
where TPixel : unmanaged, IPixel<TPixel>
{
TPixel color = default;
bool invertX = InvertX(origin);
using (IManagedByteBuffer row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 2, 0))
{
for (int y = 0; y < height; y++)
{
this.currentStream.Read(row);
Span<byte> rowSpan = row.GetSpan();
int newY = InvertY(y, height, origin);
Span<TPixel> pixelSpan = pixels.GetRowSpan(newY);
if (!this.hasAlpha)
if (invertX)
{
// We need to set the alpha component value to fully opaque.
for (int x = 1; x < rowSpan.Length; x += 2)
for (int x = width - 1; x >= 0; x--)
{
rowSpan[x] = (byte)(rowSpan[x] | (1 << 7));
this.currentStream.Read(this.scratchBuffer, 0, 2);
if (!this.hasAlpha)
{
this.scratchBuffer[1] |= 1 << 7;
}
if (this.fileHeader.ImageType == TgaImageType.BlackAndWhite)
{
color.FromLa16(Unsafe.As<byte, La16>(ref this.scratchBuffer[0]));
}
else
{
color.FromBgra5551(Unsafe.As<byte, Bgra5551>(ref this.scratchBuffer[0]));
}
pixelSpan[x] = color;
}
}
else
{
this.currentStream.Read(row);
Span<byte> rowSpan = row.GetSpan();
int newY = Invert(y, height, inverted);
Span<TPixel> pixelSpan = pixels.GetRowSpan(newY);
PixelOperations<TPixel>.Instance.FromBgra5551Bytes(this.configuration, rowSpan, pixelSpan, width);
if (!this.hasAlpha)
{
// We need to set the alpha component value to fully opaque.
for (int x = 1; x < rowSpan.Length; x += 2)
{
rowSpan[x] |= 1 << 7;
}
}
if (this.fileHeader.ImageType == TgaImageType.BlackAndWhite)
{
PixelOperations<TPixel>.Instance.FromLa16Bytes(this.configuration, rowSpan, pixelSpan, width);
}
else
{
PixelOperations<TPixel>.Instance.FromBgra5551Bytes(this.configuration, rowSpan, pixelSpan, width);
}
}
}
}
}
@ -418,18 +497,44 @@ namespace SixLabors.ImageSharp.Formats.Tga
/// <param name="width">The width of the image.</param>
/// <param name="height">The height of the image.</param>
/// <param name="pixels">The <see cref="Buffer2D{TPixel}"/> to assign the palette to.</param>
/// <param name="inverted">Indicates, if the origin of the image is top left rather the bottom left (the default).</param>
private void ReadBgr24<TPixel>(int width, int height, Buffer2D<TPixel> pixels, bool inverted)
/// <param name="origin">The image origin.</param>
private void ReadBgr24<TPixel>(int width, int height, Buffer2D<TPixel> pixels, TgaImageOrigin origin)
where TPixel : unmanaged, IPixel<TPixel>
{
using (IManagedByteBuffer row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 3, 0))
bool invertX = InvertX(origin);
if (invertX)
{
TPixel color = default;
for (int y = 0; y < height; y++)
{
this.currentStream.Read(row);
int newY = Invert(y, height, inverted);
int newY = InvertY(y, height, origin);
Span<TPixel> pixelSpan = pixels.GetRowSpan(newY);
PixelOperations<TPixel>.Instance.FromBgr24Bytes(this.configuration, row.GetSpan(), pixelSpan, width);
for (int x = width - 1; x >= 0; x--)
{
this.ReadBgr24Pixel(color, x, pixelSpan);
}
}
return;
}
using (IManagedByteBuffer row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 3, 0))
{
bool invertY = InvertY(origin);
if (invertY)
{
for (int y = height - 1; y >= 0; y--)
{
this.ReadBgr24Row(width, pixels, row, y);
}
}
else
{
for (int y = 0; y < height; y++)
{
this.ReadBgr24Row(width, pixels, row, y);
}
}
}
}
@ -441,44 +546,51 @@ namespace SixLabors.ImageSharp.Formats.Tga
/// <param name="width">The width of the image.</param>
/// <param name="height">The height of the image.</param>
/// <param name="pixels">The <see cref="Buffer2D{TPixel}"/> to assign the palette to.</param>
/// <param name="inverted">Indicates, if the origin of the image is top left rather the bottom left (the default).</param>
private void ReadBgra32<TPixel>(int width, int height, Buffer2D<TPixel> pixels, bool inverted)
/// <param name="origin">The image origin.</param>
private void ReadBgra32<TPixel>(int width, int height, Buffer2D<TPixel> pixels, TgaImageOrigin origin)
where TPixel : unmanaged, IPixel<TPixel>
{
if (this.tgaMetadata.AlphaChannelBits == 8)
TPixel color = default;
bool invertX = InvertX(origin);
if (this.tgaMetadata.AlphaChannelBits == 8 && !invertX)
{
using (IManagedByteBuffer row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 4, 0))
{
for (int y = 0; y < height; y++)
if (InvertY(origin))
{
this.currentStream.Read(row);
int newY = Invert(y, height, inverted);
Span<TPixel> pixelSpan = pixels.GetRowSpan(newY);
PixelOperations<TPixel>.Instance.FromBgra32Bytes(this.configuration, row.GetSpan(), pixelSpan, width);
for (int y = height - 1; y >= 0; y--)
{
this.ReadBgra32Row(width, pixels, row, y);
}
}
else
{
for (int y = 0; y < height; y++)
{
this.ReadBgra32Row(width, pixels, row, y);
}
}
}
return;
}
TPixel color = default;
var alphaBits = this.tgaMetadata.AlphaChannelBits;
using (IManagedByteBuffer row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 4, 0))
for (int y = 0; y < height; y++)
{
for (int y = 0; y < height; y++)
int newY = InvertY(y, height, origin);
Span<TPixel> pixelRow = pixels.GetRowSpan(newY);
if (invertX)
{
for (int x = width - 1; x >= 0; x--)
{
this.ReadBgra32Pixel(x, color, pixelRow);
}
}
else
{
this.currentStream.Read(row);
int newY = Invert(y, height, inverted);
Span<TPixel> pixelRow = pixels.GetRowSpan(newY);
Span<byte> rowSpan = row.GetSpan();
for (int x = 0; x < width; x++)
{
int idx = x * 4;
var alpha = alphaBits == 0 ? byte.MaxValue : rowSpan[idx + 3];
color.FromBgra32(new Bgra32(rowSpan[idx + 2], rowSpan[idx + 1], rowSpan[idx], (byte)alpha));
pixelRow[x] = color;
this.ReadBgra32Pixel(x, color, pixelRow);
}
}
}
@ -492,8 +604,8 @@ namespace SixLabors.ImageSharp.Formats.Tga
/// <param name="height">The height of the image.</param>
/// <param name="pixels">The <see cref="Buffer2D{TPixel}"/> to assign the palette to.</param>
/// <param name="bytesPerPixel">The bytes per pixel.</param>
/// <param name="inverted">Indicates, if the origin of the image is top left rather the bottom left (the default).</param>
private void ReadRle<TPixel>(int width, int height, Buffer2D<TPixel> pixels, int bytesPerPixel, bool inverted)
/// <param name="origin">The image origin.</param>
private void ReadRle<TPixel>(int width, int height, Buffer2D<TPixel> pixels, int bytesPerPixel, TgaImageOrigin origin)
where TPixel : unmanaged, IPixel<TPixel>
{
TPixel color = default;
@ -504,7 +616,7 @@ namespace SixLabors.ImageSharp.Formats.Tga
this.UncompressRle(width, height, bufferSpan, bytesPerPixel);
for (int y = 0; y < height; y++)
{
int newY = Invert(y, height, inverted);
int newY = InvertY(y, height, origin);
Span<TPixel> pixelRow = pixels.GetRowSpan(newY);
int rowStartIdx = y * width * bytesPerPixel;
for (int x = 0; x < width; x++)
@ -522,7 +634,15 @@ namespace SixLabors.ImageSharp.Formats.Tga
bufferSpan[idx + 1] = (byte)(bufferSpan[idx + 1] | 128);
}
color.FromBgra5551(Unsafe.As<byte, Bgra5551>(ref bufferSpan[idx]));
if (this.fileHeader.ImageType == TgaImageType.RleBlackAndWhite)
{
color.FromLa16(Unsafe.As<byte, La16>(ref bufferSpan[idx]));
}
else
{
color.FromBgra5551(Unsafe.As<byte, Bgra5551>(ref bufferSpan[idx]));
}
break;
case 3:
color.FromBgr24(Unsafe.As<byte, Bgr24>(ref bufferSpan[idx]));
@ -541,7 +661,8 @@ namespace SixLabors.ImageSharp.Formats.Tga
break;
}
pixelRow[x] = color;
int newX = InvertX(x, width, origin);
pixelRow[newX] = color;
}
}
}
@ -561,6 +682,95 @@ namespace SixLabors.ImageSharp.Formats.Tga
this.metadata);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ReadL8Row<TPixel>(int width, Buffer2D<TPixel> pixels, IManagedByteBuffer row, int y)
where TPixel : unmanaged, IPixel<TPixel>
{
this.currentStream.Read(row);
Span<TPixel> pixelSpan = pixels.GetRowSpan(y);
PixelOperations<TPixel>.Instance.FromL8Bytes(this.configuration, row.GetSpan(), pixelSpan, width);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ReadL8Pixel<TPixel>(TPixel color, int x, Span<TPixel> pixelSpan)
where TPixel : unmanaged, IPixel<TPixel>
{
var pixelValue = (byte)this.currentStream.ReadByte();
color.FromL8(Unsafe.As<byte, L8>(ref pixelValue));
pixelSpan[x] = color;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ReadBgr24Pixel<TPixel>(TPixel color, int x, Span<TPixel> pixelSpan)
where TPixel : unmanaged, IPixel<TPixel>
{
this.currentStream.Read(this.scratchBuffer, 0, 3);
color.FromBgr24(Unsafe.As<byte, Bgr24>(ref this.scratchBuffer[0]));
pixelSpan[x] = color;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ReadBgr24Row<TPixel>(int width, Buffer2D<TPixel> pixels, IManagedByteBuffer row, int y)
where TPixel : unmanaged, IPixel<TPixel>
{
this.currentStream.Read(row);
Span<TPixel> pixelSpan = pixels.GetRowSpan(y);
PixelOperations<TPixel>.Instance.FromBgr24Bytes(this.configuration, row.GetSpan(), pixelSpan, width);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ReadBgra32Pixel<TPixel>(int x, TPixel color, Span<TPixel> pixelRow)
where TPixel : unmanaged, IPixel<TPixel>
{
this.currentStream.Read(this.scratchBuffer, 0, 4);
var alpha = this.tgaMetadata.AlphaChannelBits == 0 ? byte.MaxValue : this.scratchBuffer[3];
color.FromBgra32(new Bgra32(this.scratchBuffer[2], this.scratchBuffer[1], this.scratchBuffer[0], alpha));
pixelRow[x] = color;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ReadBgra32Row<TPixel>(int width, Buffer2D<TPixel> pixels, IManagedByteBuffer row, int y)
where TPixel : unmanaged, IPixel<TPixel>
{
this.currentStream.Read(row);
Span<TPixel> pixelSpan = pixels.GetRowSpan(y);
PixelOperations<TPixel>.Instance.FromBgra32Bytes(this.configuration, row.GetSpan(), pixelSpan, width);
}
private void ReadPalettedBgr16Pixel<TPixel>(byte[] palette, int colorMapPixelSizeInBytes, int x, TPixel color, Span<TPixel> pixelRow)
where TPixel : unmanaged, IPixel<TPixel>
{
int colorIndex = this.currentStream.ReadByte();
Bgra5551 bgra = default;
bgra.FromBgra5551(Unsafe.As<byte, Bgra5551>(ref palette[colorIndex * colorMapPixelSizeInBytes]));
if (!this.hasAlpha)
{
// Set alpha value to 1, to treat it as opaque for Bgra5551.
bgra.PackedValue = (ushort)(bgra.PackedValue | 0x8000);
}
color.FromBgra5551(bgra);
pixelRow[x] = color;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ReadPalettedBgr24Pixel<TPixel>(byte[] palette, int colorMapPixelSizeInBytes, int x, TPixel color, Span<TPixel> pixelRow)
where TPixel : unmanaged, IPixel<TPixel>
{
int colorIndex = this.currentStream.ReadByte();
color.FromBgr24(Unsafe.As<byte, Bgr24>(ref palette[colorIndex * colorMapPixelSizeInBytes]));
pixelRow[x] = color;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ReadPalettedBgra32Pixel<TPixel>(byte[] palette, int colorMapPixelSizeInBytes, int x, TPixel color, Span<TPixel> pixelRow)
where TPixel : unmanaged, IPixel<TPixel>
{
int colorIndex = this.currentStream.ReadByte();
color.FromBgra32(Unsafe.As<byte, Bgra32>(ref palette[colorIndex * colorMapPixelSizeInBytes]));
pixelRow[x] = color;
}
/// <summary>
/// Produce uncompressed tga data from a run length encoded stream.
/// </summary>
@ -609,18 +819,80 @@ namespace SixLabors.ImageSharp.Formats.Tga
/// Returns the y- value based on the given height.
/// </summary>
/// <param name="y">The y- value representing the current row.</param>
/// <param name="height">The height of the bitmap.</param>
/// <param name="inverted">Whether the bitmap is inverted.</param>
/// <param name="height">The height of the image.</param>
/// <param name="origin">The image origin.</param>
/// <returns>The <see cref="int"/> representing the inverted value.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int InvertY(int y, int height, TgaImageOrigin origin)
{
if (InvertY(origin))
{
return height - y - 1;
}
return y;
}
/// <summary>
/// Indicates whether the y coordinates needs to be inverted, to keep a top left origin.
/// </summary>
/// <param name="origin">The image origin.</param>
/// <returns>True, if y coordinate needs to be inverted.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool InvertY(TgaImageOrigin origin)
{
switch (origin)
{
case TgaImageOrigin.BottomLeft:
case TgaImageOrigin.BottomRight:
return true;
default:
return false;
}
}
/// <summary>
/// Returns the x- value based on the given width.
/// </summary>
/// <param name="x">The x- value representing the current column.</param>
/// <param name="width">The width of the image.</param>
/// <param name="origin">The image origin.</param>
/// <returns>The <see cref="int"/> representing the inverted value.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int Invert(int y, int height, bool inverted) => (!inverted) ? height - y - 1 : y;
private static int InvertX(int x, int width, TgaImageOrigin origin)
{
if (InvertX(origin))
{
return width - x - 1;
}
return x;
}
/// <summary>
/// Indicates whether the x coordinates needs to be inverted, to keep a top left origin.
/// </summary>
/// <param name="origin">The image origin.</param>
/// <returns>True, if x coordinate needs to be inverted.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool InvertX(TgaImageOrigin origin)
{
switch (origin)
{
case TgaImageOrigin.TopRight:
case TgaImageOrigin.BottomRight:
return true;
default:
return false;
}
}
/// <summary>
/// Reads the tga file header from the stream.
/// </summary>
/// <param name="stream">The <see cref="Stream"/> containing image data.</param>
/// <returns>true, if the image origin is top left.</returns>
private bool ReadFileHeader(Stream stream)
/// <returns>The image origin.</returns>
private TgaImageOrigin ReadFileHeader(Stream stream)
{
this.currentStream = stream;
@ -641,15 +913,9 @@ namespace SixLabors.ImageSharp.Formats.Tga
this.tgaMetadata.AlphaChannelBits = (byte)alphaBits;
this.hasAlpha = alphaBits > 0;
// TODO: bits 4 and 5 describe the image origin. See spec page 9. bit 4 is currently ignored.
// Theoretically the origin could also be top right and bottom right.
// Bit at position 5 of the descriptor indicates, that the origin is top left instead of bottom left.
if ((this.fileHeader.ImageDescriptor & (1 << 5)) != 0)
{
return true;
}
return false;
// Bits 4 and 5 describe the image origin.
var origin = (TgaImageOrigin)((this.fileHeader.ImageDescriptor & 0x30) >> 4);
return origin;
}
}
}

28
src/ImageSharp/Formats/Tga/TgaImageOrigin.cs

@ -0,0 +1,28 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.Formats.Tga
{
internal enum TgaImageOrigin
{
/// <summary>
/// Bottom left origin.
/// </summary>
BottomLeft = 0,
/// <summary>
/// Bottom right origin.
/// </summary>
BottomRight = 1,
/// <summary>
/// Top left origin.
/// </summary>
TopLeft = 2,
/// <summary>
/// Top right origin.
/// </summary>
TopRight = 3,
}
}

2
tests/Directory.Build.targets

@ -29,7 +29,7 @@
<PackageReference Update="BenchmarkDotNet.Diagnostics.Windows" Version="0.12.0" Condition="'$(OS)' == 'Windows_NT'" />
<PackageReference Update="Colourful" Version="2.0.3" />
<PackageReference Update="coverlet.collector" Version="1.2.0" PrivateAssets="All"/>
<PackageReference Update="Magick.NET-Q16-AnyCPU" Version="7.14.4" />
<PackageReference Update="Magick.NET-Q16-AnyCPU" Version="7.15.5" />
<PackageReference Update="Microsoft.DotNet.RemoteExecutor" Version="5.0.0-beta.20069.1" />
<PackageReference Update="Microsoft.NET.Test.Sdk" Version="16.5.0-preview-20200116-01" />
<PackageReference Update="Moq" Version="4.10.0" />

2
tests/ImageSharp.Benchmarks/Codecs/DecodeTga.cs

@ -23,7 +23,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
private byte[] data;
[Params(TestImages.Tga.Bit24)]
[Params(TestImages.Tga.Bit24BottomLeft)]
public string TestImage { get; set; }
[GlobalSetup]

2
tests/ImageSharp.Benchmarks/Codecs/EncodeTga.cs

@ -20,7 +20,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
private string TestImageFullPath => Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImage);
[Params(TestImages.Tga.Bit24)]
[Params(TestImages.Tga.Bit24BottomLeft)]
public string TestImage { get; set; }
[GlobalSetup]

460
tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs

@ -20,8 +20,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga
private static TgaDecoder TgaDecoder => new TgaDecoder();
[Theory]
[WithFile(Grey, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_Uncompressed_MonoChrome<TPixel>(TestImageProvider<TPixel> provider)
[WithFile(Gray8BitTopLeft, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_Gray_WithTopLeftOrigin_8Bit<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage(TgaDecoder))
@ -31,9 +31,213 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga
}
}
[Theory]
[WithFile(Gray8BitBottomLeft, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_Gray_WithBottomLeftOrigin_8Bit<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage(TgaDecoder))
{
image.DebugSave(provider);
TgaTestUtils.CompareWithReferenceDecoder(provider, image);
}
}
[Theory]
[WithFile(Gray8BitTopRight, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_Gray_WithTopRightOrigin_8Bit<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage(TgaDecoder))
{
image.DebugSave(provider);
TgaTestUtils.CompareWithReferenceDecoder(provider, image);
}
}
[Theory]
[WithFile(Gray8BitBottomRight, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_Gray_WithBottomRightOrigin_8Bit<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage(TgaDecoder))
{
image.DebugSave(provider);
TgaTestUtils.CompareWithReferenceDecoder(provider, image);
}
}
[Theory]
[WithFile(Gray8BitRleTopLeft, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_RunLengthEncoded_Gray_WithTopLeftOrigin_8Bit<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage(TgaDecoder))
{
image.DebugSave(provider);
TgaTestUtils.CompareWithReferenceDecoder(provider, image);
}
}
[Theory]
[WithFile(Gray8BitRleTopRight, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_RunLengthEncoded_Gray_WithTopRightOrigin_8Bit<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage(TgaDecoder))
{
image.DebugSave(provider);
TgaTestUtils.CompareWithReferenceDecoder(provider, image);
}
}
[Theory]
[WithFile(Gray8BitRleBottomLeft, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_RunLengthEncoded_Gray_WithBottomLeftOrigin_8Bit<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage(TgaDecoder))
{
image.DebugSave(provider);
TgaTestUtils.CompareWithReferenceDecoder(provider, image);
}
}
[Theory]
[WithFile(Gray8BitRleBottomRight, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_RunLengthEncoded_Gray_WithBottomRightOrigin_8Bit<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage(TgaDecoder))
{
image.DebugSave(provider);
TgaTestUtils.CompareWithReferenceDecoder(provider, image);
}
}
[Theory]
[WithFile(Gray16BitTopLeft, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_Gray_16Bit<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage(TgaDecoder))
{
image.DebugSave(provider);
// Using here the reference output instead of the the reference decoder,
// because the reference decoder output seems not to be correct for 16bit gray images.
image.CompareToReferenceOutput(ImageComparer.Exact, provider);
}
}
[Theory]
[WithFile(Gray16BitBottomLeft, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_Gray_WithBottomLeftOrigin_16Bit<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage(TgaDecoder))
{
image.DebugSave(provider);
// Using here the reference output instead of the the reference decoder,
// because the reference decoder output seems not to be correct for 16bit gray images.
image.CompareToReferenceOutput(ImageComparer.Exact, provider);
}
}
[Theory]
[WithFile(Gray16BitBottomRight, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_Gray_WithBottomRightOrigin_16Bit<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage(TgaDecoder))
{
image.DebugSave(provider);
// Using here the reference output instead of the the reference decoder,
// because the reference decoder output seems not to be correct for 16bit gray images.
image.CompareToReferenceOutput(ImageComparer.Exact, provider);
}
}
[Theory]
[WithFile(Gray16BitTopRight, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_Gray_WithTopRightOrigin_16Bit<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage(TgaDecoder))
{
image.DebugSave(provider);
// Using here the reference output instead of the the reference decoder,
// because the reference decoder output seems not to be correct for 16bit gray images.
image.CompareToReferenceOutput(ImageComparer.Exact, provider);
}
}
[Theory]
[WithFile(Gray16BitRleTopLeft, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_RunLengthEncoded_Gray_16Bit<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage(TgaDecoder))
{
image.DebugSave(provider);
// Using here the reference output instead of the the reference decoder,
// because the reference decoder output seems not to be correct for 16bit gray images.
image.CompareToReferenceOutput(ImageComparer.Exact, provider);
}
}
[Theory]
[WithFile(Gray16BitRleBottomLeft, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_RunLengthEncoded_Gray_WithBottomLeftOrigin_16Bit<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage(TgaDecoder))
{
image.DebugSave(provider);
// Using here the reference output instead of the the reference decoder,
// because the reference decoder output seems not to be correct for 16bit gray images.
image.CompareToReferenceOutput(ImageComparer.Exact, provider);
}
}
[Theory]
[WithFile(Gray16BitRleBottomRight, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_RunLengthEncoded_Gray_WithBottomRightOrigin_16Bit<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage(TgaDecoder))
{
image.DebugSave(provider);
// Using here the reference output instead of the the reference decoder,
// because the reference decoder output seems not to be correct for 16bit gray images.
image.CompareToReferenceOutput(ImageComparer.Exact, provider);
}
}
[Theory]
[WithFile(Gray16BitRleTopRight, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_RunLengthEncoded_Gray_WithTopRightOrigin_16Bit<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage(TgaDecoder))
{
image.DebugSave(provider);
// Using here the reference output instead of the the reference decoder,
// because the reference decoder output seems not to be correct for 16bit gray images.
image.CompareToReferenceOutput(ImageComparer.Exact, provider);
}
}
[Theory]
[WithFile(Bit15, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_Uncompressed_15Bit<TPixel>(TestImageProvider<TPixel> provider)
public void TgaDecoder_CanDecode_15Bit<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage(TgaDecoder))
@ -56,8 +260,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga
}
[Theory]
[WithFile(Bit16, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_Uncompressed_16Bit<TPixel>(TestImageProvider<TPixel> provider)
[WithFile(Bit16BottomLeft, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_WithBottomLeftOrigin_16Bit<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage(TgaDecoder))
@ -80,8 +284,44 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga
}
[Theory]
[WithFile(Bit24, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_Uncompressed_24Bit<TPixel>(TestImageProvider<TPixel> provider)
[WithFile(Bit24TopLeft, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_WithTopLeftOrigin_24Bit<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage(TgaDecoder))
{
image.DebugSave(provider);
TgaTestUtils.CompareWithReferenceDecoder(provider, image);
}
}
[Theory]
[WithFile(Bit24BottomLeft, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_WithBottomLeftOrigin_24Bit<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage(TgaDecoder))
{
image.DebugSave(provider);
TgaTestUtils.CompareWithReferenceDecoder(provider, image);
}
}
[Theory]
[WithFile(Bit24TopRight, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_WithTopRightOrigin_24Bit<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage(TgaDecoder))
{
image.DebugSave(provider);
TgaTestUtils.CompareWithReferenceDecoder(provider, image);
}
}
[Theory]
[WithFile(Bit24BottomRight, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_WithBottomRightOrigin_24Bit<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage(TgaDecoder))
@ -103,6 +343,30 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga
}
}
[Theory]
[WithFile(Bit24RleTopRight, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_RunLengthEncoded_WithTopRightOrigin_24Bit<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage(TgaDecoder))
{
image.DebugSave(provider);
TgaTestUtils.CompareWithReferenceDecoder(provider, image);
}
}
[Theory]
[WithFile(Bit24RleBottomRight, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_RunLengthEncoded_WithBottomRightOrigin_24Bit<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage(TgaDecoder))
{
image.DebugSave(provider);
TgaTestUtils.CompareWithReferenceDecoder(provider, image);
}
}
[Theory]
[WithFile(Bit24TopLeft, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_Palette_WithTopLeftOrigin_24Bit<TPixel>(TestImageProvider<TPixel> provider)
@ -116,8 +380,152 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga
}
[Theory]
[WithFile(Bit32, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_Uncompressed_32Bit<TPixel>(TestImageProvider<TPixel> provider)
[WithFile(Bit32TopLeft, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_WithTopLeftOrigin_32Bit<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage(TgaDecoder))
{
image.DebugSave(provider);
TgaTestUtils.CompareWithReferenceDecoder(provider, image);
}
}
[Theory]
[WithFile(Bit32TopRight, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_WithTopRightOrigin_32Bit<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage(TgaDecoder))
{
image.DebugSave(provider);
TgaTestUtils.CompareWithReferenceDecoder(provider, image);
}
}
[Theory]
[WithFile(Bit32BottomLeft, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_WithBottomLeftOrigin_32Bit<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage(TgaDecoder))
{
image.DebugSave(provider);
TgaTestUtils.CompareWithReferenceDecoder(provider, image);
}
}
[Theory]
[WithFile(Bit32BottomRight, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_WithBottomRightOrigin_32Bit<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage(TgaDecoder))
{
image.DebugSave(provider);
TgaTestUtils.CompareWithReferenceDecoder(provider, image);
}
}
[Theory]
[WithFile(Bit16RleBottomLeft, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_RunLengthEncoded_WithBottomLeftOrigin_16Bit<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage(TgaDecoder))
{
image.DebugSave(provider);
TgaTestUtils.CompareWithReferenceDecoder(provider, image);
}
}
[Theory]
[WithFile(Bit24RleBottomLeft, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_RunLengthEncoded_WithBottomLeftOrigin_24Bit<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage(TgaDecoder))
{
image.DebugSave(provider);
TgaTestUtils.CompareWithReferenceDecoder(provider, image);
}
}
[Theory]
[WithFile(Bit32RleTopLeft, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_RunLengthEncoded_WithTopLeftOrigin_32Bit<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage(TgaDecoder))
{
image.DebugSave(provider);
TgaTestUtils.CompareWithReferenceDecoder(provider, image);
}
}
[Theory]
[WithFile(Bit32RleBottomLeft, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_RunLengthEncoded_WithBottomLeftOrigin_32Bit<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage(TgaDecoder))
{
image.DebugSave(provider);
TgaTestUtils.CompareWithReferenceDecoder(provider, image);
}
}
[Theory]
[WithFile(Bit32RleTopRight, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_RunLengthEncoded_WithTopRightOrigin_32Bit<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage(TgaDecoder))
{
image.DebugSave(provider);
TgaTestUtils.CompareWithReferenceDecoder(provider, image);
}
}
[Theory]
[WithFile(Bit32RleBottomRight, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_RunLengthEncoded_WithBottomRightOrigin_32Bit<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage(TgaDecoder))
{
image.DebugSave(provider);
TgaTestUtils.CompareWithReferenceDecoder(provider, image);
}
}
[Theory]
[WithFile(Bit16PalBottomLeft, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_WithPaletteBottomLeftOrigin_16Bit<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage(TgaDecoder))
{
image.DebugSave(provider);
TgaTestUtils.CompareWithReferenceDecoder(provider, image);
}
}
[Theory]
[WithFile(Bit24PalTopLeft, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_WithPaletteTopLeftOrigin_24Bit<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage(TgaDecoder))
{
image.DebugSave(provider);
TgaTestUtils.CompareWithReferenceDecoder(provider, image);
}
}
[Theory]
[WithFile(Bit24PalTopRight, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_WithPaletteTopRightOrigin_24Bit<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage(TgaDecoder))
@ -128,8 +536,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga
}
[Theory]
[WithFile(GreyRle, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_RunLengthEncoded_MonoChrome<TPixel>(TestImageProvider<TPixel> provider)
[WithFile(Bit24PalBottomLeft, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_WithPaletteBottomLeftOrigin_24Bit<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage(TgaDecoder))
@ -140,8 +548,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga
}
[Theory]
[WithFile(Bit16Rle, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_RunLengthEncoded_16Bit<TPixel>(TestImageProvider<TPixel> provider)
[WithFile(Bit24PalBottomRight, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_WithPaletteBottomRightOrigin_24Bit<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage(TgaDecoder))
@ -152,8 +560,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga
}
[Theory]
[WithFile(Bit24Rle, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_RunLengthEncoded_24Bit<TPixel>(TestImageProvider<TPixel> provider)
[WithFile(Bit32PalTopLeft, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_WithPalette_32Bit<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage(TgaDecoder))
@ -164,8 +572,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga
}
[Theory]
[WithFile(Bit32Rle, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_RunLengthEncoded_32Bit<TPixel>(TestImageProvider<TPixel> provider)
[WithFile(Bit32PalBottomLeft, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_WithPalette_WithBottomLeftOrigin_32Bit<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage(TgaDecoder))
@ -176,8 +584,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga
}
[Theory]
[WithFile(Bit16Pal, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_WithPalette_16Bit<TPixel>(TestImageProvider<TPixel> provider)
[WithFile(Bit32PalBottomRight, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_WithPalette_WithBottomRightOrigin_32Bit<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage(TgaDecoder))
@ -188,8 +596,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga
}
[Theory]
[WithFile(Bit24Pal, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_WithPalette_24Bit<TPixel>(TestImageProvider<TPixel> provider)
[WithFile(Bit32PalTopRight, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_WithPalette_WithTopRightOrigin_32Bit<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage(TgaDecoder))
@ -228,9 +636,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga
}
[Theory]
[WithFile(Bit16, PixelTypes.Rgba32)]
[WithFile(Bit24, PixelTypes.Rgba32)]
[WithFile(Bit32, PixelTypes.Rgba32)]
[WithFile(Bit16BottomLeft, PixelTypes.Rgba32)]
[WithFile(Bit24BottomLeft, PixelTypes.Rgba32)]
[WithFile(Bit32BottomLeft, PixelTypes.Rgba32)]
public void TgaDecoder_DegenerateMemoryRequest_ShouldTranslateTo_ImageFormatException<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
@ -240,8 +648,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga
}
[Theory]
[WithFile(Bit24, PixelTypes.Rgba32)]
[WithFile(Bit32, PixelTypes.Rgba32)]
[WithFile(Bit24BottomLeft, PixelTypes.Rgba32)]
[WithFile(Bit32BottomLeft, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_WithLimitedAllocatorBufferCapacity<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{

32
tests/ImageSharp.Tests/Formats/Tga/TgaEncoderTests.cs

@ -25,10 +25,10 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga
public static readonly TheoryData<string, TgaBitsPerPixel> TgaBitsPerPixelFiles =
new TheoryData<string, TgaBitsPerPixel>
{
{ Grey, TgaBitsPerPixel.Pixel8 },
{ Bit32, TgaBitsPerPixel.Pixel32 },
{ Bit24, TgaBitsPerPixel.Pixel24 },
{ Bit16, TgaBitsPerPixel.Pixel16 },
{ Gray8BitBottomLeft, TgaBitsPerPixel.Pixel8 },
{ Bit16BottomLeft, TgaBitsPerPixel.Pixel16 },
{ Bit24BottomLeft, TgaBitsPerPixel.Pixel24 },
{ Bit32BottomLeft, TgaBitsPerPixel.Pixel32 },
};
[Theory]
@ -37,14 +37,14 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga
{
var options = new TgaEncoder();
TestFile testFile = TestFile.Create(imagePath);
var testFile = TestFile.Create(imagePath);
using (Image<Rgba32> input = testFile.CreateRgba32Image())
{
using (var memStream = new MemoryStream())
{
input.Save(memStream, options);
memStream.Position = 0;
using (Image<Rgba32> output = Image.Load<Rgba32>(memStream))
using (var output = Image.Load<Rgba32>(memStream))
{
TgaMetadata meta = output.Metadata.GetTgaMetadata();
Assert.Equal(bmpBitsPerPixel, meta.BitsPerPixel);
@ -79,52 +79,52 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga
}
[Theory]
[WithFile(Bit32, PixelTypes.Rgba32)]
[WithFile(Bit32BottomLeft, PixelTypes.Rgba32)]
public void TgaEncoder_Bit8_Works<TPixel>(TestImageProvider<TPixel> provider, TgaBitsPerPixel bitsPerPixel = TgaBitsPerPixel.Pixel8)
// Using tolerant comparer here. The results from magick differ slightly. Maybe a different ToGrey method is used. The image looks otherwise ok.
where TPixel : unmanaged, IPixel<TPixel> => TestTgaEncoderCore(provider, bitsPerPixel, TgaCompression.None, useExactComparer: false, compareTolerance: 0.03f);
[Theory]
[WithFile(Bit32, PixelTypes.Rgba32)]
[WithFile(Bit32BottomLeft, PixelTypes.Rgba32)]
public void TgaEncoder_Bit16_Works<TPixel>(TestImageProvider<TPixel> provider, TgaBitsPerPixel bitsPerPixel = TgaBitsPerPixel.Pixel16)
where TPixel : unmanaged, IPixel<TPixel> => TestTgaEncoderCore(provider, bitsPerPixel, TgaCompression.None, useExactComparer: false);
[Theory]
[WithFile(Bit32, PixelTypes.Rgba32)]
[WithFile(Bit32BottomLeft, PixelTypes.Rgba32)]
public void TgaEncoder_Bit24_Works<TPixel>(TestImageProvider<TPixel> provider, TgaBitsPerPixel bitsPerPixel = TgaBitsPerPixel.Pixel24)
where TPixel : unmanaged, IPixel<TPixel> => TestTgaEncoderCore(provider, bitsPerPixel, TgaCompression.None);
[Theory]
[WithFile(Bit32, PixelTypes.Rgba32)]
[WithFile(Bit32BottomLeft, PixelTypes.Rgba32)]
public void TgaEncoder_Bit32_Works<TPixel>(TestImageProvider<TPixel> provider, TgaBitsPerPixel bitsPerPixel = TgaBitsPerPixel.Pixel32)
where TPixel : unmanaged, IPixel<TPixel> => TestTgaEncoderCore(provider, bitsPerPixel, TgaCompression.None);
[Theory]
[WithFile(Bit32, PixelTypes.Rgba32)]
[WithFile(Bit32BottomLeft, PixelTypes.Rgba32)]
public void TgaEncoder_Bit8_WithRunLengthEncoding_Works<TPixel>(TestImageProvider<TPixel> provider, TgaBitsPerPixel bitsPerPixel = TgaBitsPerPixel.Pixel8)
// Using tolerant comparer here. The results from magick differ slightly. Maybe a different ToGrey method is used. The image looks otherwise ok.
where TPixel : unmanaged, IPixel<TPixel> => TestTgaEncoderCore(provider, bitsPerPixel, TgaCompression.RunLength, useExactComparer: false, compareTolerance: 0.03f);
[Theory]
[WithFile(Bit32, PixelTypes.Rgba32)]
[WithFile(Bit32BottomLeft, PixelTypes.Rgba32)]
public void TgaEncoder_Bit16_WithRunLengthEncoding_Works<TPixel>(TestImageProvider<TPixel> provider, TgaBitsPerPixel bitsPerPixel = TgaBitsPerPixel.Pixel16)
where TPixel : unmanaged, IPixel<TPixel> => TestTgaEncoderCore(provider, bitsPerPixel, TgaCompression.RunLength, useExactComparer: false);
[Theory]
[WithFile(Bit32, PixelTypes.Rgba32)]
[WithFile(Bit32BottomLeft, PixelTypes.Rgba32)]
public void TgaEncoder_Bit24_WithRunLengthEncoding_Works<TPixel>(TestImageProvider<TPixel> provider, TgaBitsPerPixel bitsPerPixel = TgaBitsPerPixel.Pixel24)
where TPixel : unmanaged, IPixel<TPixel> => TestTgaEncoderCore(provider, bitsPerPixel, TgaCompression.RunLength);
[Theory]
[WithFile(Bit32, PixelTypes.Rgba32)]
[WithFile(Bit32BottomLeft, PixelTypes.Rgba32)]
public void TgaEncoder_Bit32_WithRunLengthEncoding_Works<TPixel>(TestImageProvider<TPixel> provider, TgaBitsPerPixel bitsPerPixel = TgaBitsPerPixel.Pixel32)
where TPixel : unmanaged, IPixel<TPixel> => TestTgaEncoderCore(provider, bitsPerPixel, TgaCompression.RunLength);
[Theory]
[WithFile(Bit32, PixelTypes.Rgba32, TgaBitsPerPixel.Pixel32)]
[WithFile(Bit24, PixelTypes.Rgba32, TgaBitsPerPixel.Pixel24)]
[WithFile(Bit32BottomLeft, PixelTypes.Rgba32, TgaBitsPerPixel.Pixel32)]
[WithFile(Bit24BottomLeft, PixelTypes.Rgba32, TgaBitsPerPixel.Pixel24)]
public void TgaEncoder_WorksWithDiscontiguousBuffers<TPixel>(TestImageProvider<TPixel> provider, TgaBitsPerPixel bitsPerPixel)
where TPixel : unmanaged, IPixel<TPixel>
{

1
tests/ImageSharp.Tests/Formats/Tga/TgaTestUtils.cs

@ -44,6 +44,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga
{
using (var magickImage = new MagickImage(fileInfo))
{
magickImage.AutoOrient();
var result = new Image<TPixel>(configuration, magickImage.Width, magickImage.Height);
Span<TPixel> resultPixels = result.GetPixelSpan();

64
tests/ImageSharp.Tests/TestImages.cs

@ -375,21 +375,63 @@ namespace SixLabors.ImageSharp.Tests
public static class Tga
{
public const string Gray8BitTopLeft = "Tga/grayscale_UL.tga";
public const string Gray8BitTopRight = "Tga/grayscale_UR.tga";
public const string Gray8BitBottomLeft = "Tga/targa_8bit.tga";
public const string Gray8BitBottomRight = "Tga/grayscale_LR.tga";
public const string Gray8BitRleTopLeft = "Tga/grayscale_rle_UL.tga";
public const string Gray8BitRleTopRight = "Tga/grayscale_rle_UR.tga";
public const string Gray8BitRleBottomLeft = "Tga/targa_8bit_rle.tga";
public const string Gray8BitRleBottomRight = "Tga/grayscale_rle_LR.tga";
public const string Bit15 = "Tga/rgb15.tga";
public const string Bit15Rle = "Tga/rgb15rle.tga";
public const string Bit16 = "Tga/targa_16bit.tga";
public const string Bit16BottomLeft = "Tga/targa_16bit.tga";
public const string Bit16PalRle = "Tga/ccm8.tga";
public const string Bit24 = "Tga/targa_24bit.tga";
public const string Bit24TopLeft = "Tga/targa_24bit_pal_origin_topleft.tga";
public const string Bit16RleBottomLeft = "Tga/targa_16bit_rle.tga";
public const string Bit16PalBottomLeft = "Tga/targa_16bit_pal.tga";
public const string Gray16BitTopLeft = "Tga/grayscale_a_UL.tga";
public const string Gray16BitBottomLeft = "Tga/grayscale_a_LL.tga";
public const string Gray16BitBottomRight = "Tga/grayscale_a_LR.tga";
public const string Gray16BitTopRight = "Tga/grayscale_a_UR.tga";
public const string Gray16BitRleTopLeft = "Tga/grayscale_a_rle_UL.tga";
public const string Gray16BitRleBottomLeft = "Tga/grayscale_a_rle_LL.tga";
public const string Gray16BitRleBottomRight = "Tga/grayscale_a_rle_LR.tga";
public const string Gray16BitRleTopRight = "Tga/grayscale_a_rle_UR.tga";
public const string Bit24TopLeft = "Tga/rgb24_top_left.tga";
public const string Bit24BottomLeft = "Tga/targa_24bit.tga";
public const string Bit24BottomRight = "Tga/rgb_LR.tga";
public const string Bit24TopRight = "Tga/rgb_UR.tga";
public const string Bit24RleTopLeft = "Tga/targa_24bit_rle_origin_topleft.tga";
public const string Bit32 = "Tga/targa_32bit.tga";
public const string Grey = "Tga/targa_8bit.tga";
public const string GreyRle = "Tga/targa_8bit_rle.tga";
public const string Bit16Rle = "Tga/targa_16bit_rle.tga";
public const string Bit24Rle = "Tga/targa_24bit_rle.tga";
public const string Bit32Rle = "Tga/targa_32bit_rle.tga";
public const string Bit16Pal = "Tga/targa_16bit_pal.tga";
public const string Bit24Pal = "Tga/targa_24bit_pal.tga";
public const string Bit24RleBottomLeft = "Tga/targa_24bit_rle.tga";
public const string Bit24RleTopRight = "Tga/rgb_rle_UR.tga";
public const string Bit24RleBottomRight = "Tga/rgb_rle_LR.tga";
public const string Bit24PalTopLeft = "Tga/targa_24bit_pal_origin_topleft.tga";
public const string Bit24PalTopRight = "Tga/indexed_UR.tga";
public const string Bit24PalBottomLeft = "Tga/targa_24bit_pal.tga";
public const string Bit24PalBottomRight = "Tga/indexed_LR.tga";
public const string Bit32TopLeft = "Tga/rgb_a_UL.tga";
public const string Bit32BottomLeft = "Tga/targa_32bit.tga";
public const string Bit32TopRight = "Tga/rgb_a_UR.tga";
public const string Bit32BottomRight = "Tga/rgb_a_LR.tga";
public const string Bit32PalTopLeft = "Tga/indexed_a_UL.tga";
public const string Bit32PalBottomLeft = "Tga/indexed_a_LL.tga";
public const string Bit32PalBottomRight = "Tga/indexed_a_LR.tga";
public const string Bit32PalTopRight = "Tga/indexed_a_UR.tga";
public const string Bit32RleTopLeft = "Tga/rgb_a_rle_UL.tga";
public const string Bit32RleTopRight = "Tga/rgb_a_rle_UR.tga";
public const string Bit32RleBottomRight = "Tga/rgb_a_rle_LR.tga";
public const string Bit32RleBottomLeft = "Tga/targa_32bit_rle.tga";
public const string NoAlphaBits16Bit = "Tga/16bit_noalphabits.tga";
public const string NoAlphaBits16BitRle = "Tga/16bit_rle_noalphabits.tga";
public const string NoAlphaBits32Bit = "Tga/32bit_no_alphabits.tga";

2
tests/Images/External

@ -1 +1 @@
Subproject commit 985e050aa7ac11830ae7a178ca2283f8b6307e4c
Subproject commit fe694a3938bea3565071a96cb1c90c4cbc586ff9

BIN
tests/Images/Input/Tga/grayscale_LL.tga

Binary file not shown.

BIN
tests/Images/Input/Tga/grayscale_LR.tga

Binary file not shown.

BIN
tests/Images/Input/Tga/grayscale_UL.tga

Binary file not shown.

BIN
tests/Images/Input/Tga/grayscale_UR.tga

Binary file not shown.

BIN
tests/Images/Input/Tga/grayscale_a_LL.tga

Binary file not shown.

BIN
tests/Images/Input/Tga/grayscale_a_LR.tga

Binary file not shown.

BIN
tests/Images/Input/Tga/grayscale_a_UL.tga

Binary file not shown.

BIN
tests/Images/Input/Tga/grayscale_a_UR.tga

Binary file not shown.

BIN
tests/Images/Input/Tga/grayscale_a_rle_LL.tga

Binary file not shown.

BIN
tests/Images/Input/Tga/grayscale_a_rle_LR.tga

Binary file not shown.

BIN
tests/Images/Input/Tga/grayscale_a_rle_UL.tga

Binary file not shown.

BIN
tests/Images/Input/Tga/grayscale_a_rle_UR.tga

Binary file not shown.

BIN
tests/Images/Input/Tga/grayscale_rle_LR.tga

Binary file not shown.

BIN
tests/Images/Input/Tga/grayscale_rle_UL.tga

Binary file not shown.

BIN
tests/Images/Input/Tga/grayscale_rle_UR.tga

Binary file not shown.

BIN
tests/Images/Input/Tga/indexed_LR.tga

Binary file not shown.

BIN
tests/Images/Input/Tga/indexed_UL.tga

Binary file not shown.

BIN
tests/Images/Input/Tga/indexed_UR.tga

Binary file not shown.

BIN
tests/Images/Input/Tga/indexed_a_LL.tga

Binary file not shown.

BIN
tests/Images/Input/Tga/indexed_a_LR.tga

Binary file not shown.

BIN
tests/Images/Input/Tga/indexed_a_UL.tga

Binary file not shown.

BIN
tests/Images/Input/Tga/indexed_a_UR.tga

Binary file not shown.

BIN
tests/Images/Input/Tga/rgb24_top_left.tga

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
tests/Images/Input/Tga/rgb_LR.tga

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB

BIN
tests/Images/Input/Tga/rgb_UR.tga

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB

BIN
tests/Images/Input/Tga/rgb_a_LL.tga

Binary file not shown.

After

Width:  |  Height:  |  Size: 256 KiB

BIN
tests/Images/Input/Tga/rgb_a_LR.tga

Binary file not shown.

After

Width:  |  Height:  |  Size: 256 KiB

BIN
tests/Images/Input/Tga/rgb_a_UL.tga

Binary file not shown.

After

Width:  |  Height:  |  Size: 256 KiB

BIN
tests/Images/Input/Tga/rgb_a_UR.tga

Binary file not shown.

After

Width:  |  Height:  |  Size: 256 KiB

BIN
tests/Images/Input/Tga/rgb_a_rle_LR.tga

Binary file not shown.

BIN
tests/Images/Input/Tga/rgb_a_rle_UL.tga

Binary file not shown.

BIN
tests/Images/Input/Tga/rgb_a_rle_UR.tga

Binary file not shown.

BIN
tests/Images/Input/Tga/rgb_rle_LR.tga

Binary file not shown.

BIN
tests/Images/Input/Tga/rgb_rle_UR.tga

Binary file not shown.
Loading…
Cancel
Save