diff --git a/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs b/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs index a4e9bdcd7..816a472fb 100644 --- a/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs +++ b/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs @@ -252,14 +252,14 @@ namespace SixLabors.ImageSharp.Formats.Tga { for (int x = width - 1; x >= 0; x--) { - this.ReadPalettedBgr16Pixel(palette, colorMapPixelSizeInBytes, x, color, pixelRow); + this.ReadPalettedBgra16Pixel(palette, colorMapPixelSizeInBytes, x, color, pixelRow); } } else { for (int x = 0; x < width; x++) { - this.ReadPalettedBgr16Pixel(palette, colorMapPixelSizeInBytes, x, color, pixelRow); + this.ReadPalettedBgra16Pixel(palette, colorMapPixelSizeInBytes, x, color, pixelRow); } } @@ -321,7 +321,6 @@ namespace SixLabors.ImageSharp.Formats.Tga using (IMemoryOwner buffer = this.memoryAllocator.Allocate(width * height * bytesPerPixel, AllocationOptions.Clean)) { TPixel color = default; - var alphaBits = this.tgaMetadata.AlphaChannelBits; Span bufferSpan = buffer.GetSpan(); this.UncompressRle(width, height, bufferSpan, bytesPerPixel: 1); @@ -339,30 +338,13 @@ namespace SixLabors.ImageSharp.Formats.Tga color.FromL8(Unsafe.As(ref palette[bufferSpan[idx] * colorMapPixelSizeInBytes])); break; case 2: - - Bgra5551 bgra = Unsafe.As(ref palette[bufferSpan[idx] * 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); + this.ReadPalettedBgra16Pixel(palette, bufferSpan[idx], colorMapPixelSizeInBytes, ref color); break; case 3: color.FromBgr24(Unsafe.As(ref palette[bufferSpan[idx] * colorMapPixelSizeInBytes])); break; case 4: - if (this.hasAlpha) - { - color.FromBgra32(Unsafe.As(ref palette[bufferSpan[idx] * colorMapPixelSizeInBytes])); - } - else - { - var alpha = alphaBits == 0 ? byte.MaxValue : bufferSpan[idx + 3]; - color.FromBgra32(new Bgra32(bufferSpan[idx + 2], bufferSpan[idx + 1], bufferSpan[idx], (byte)alpha)); - } - + color.FromBgra32(Unsafe.As(ref palette[bufferSpan[idx] * colorMapPixelSizeInBytes])); break; } @@ -737,20 +719,29 @@ namespace SixLabors.ImageSharp.Formats.Tga PixelOperations.Instance.FromBgra32Bytes(this.configuration, row.GetSpan(), pixelSpan, width); } - private void ReadPalettedBgr16Pixel(byte[] palette, int colorMapPixelSizeInBytes, int x, TPixel color, Span pixelRow) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void ReadPalettedBgra16Pixel(byte[] palette, int colorMapPixelSizeInBytes, int x, TPixel color, Span pixelRow) where TPixel : unmanaged, IPixel { int colorIndex = this.currentStream.ReadByte(); + this.ReadPalettedBgra16Pixel(palette, colorIndex, colorMapPixelSizeInBytes, ref color); + pixelRow[x] = color; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void ReadPalettedBgra16Pixel(byte[] palette, int index, int colorMapPixelSizeInBytes, ref TPixel color) + where TPixel : unmanaged, IPixel + { Bgra5551 bgra = default; - bgra.FromBgra5551(Unsafe.As(ref palette[colorIndex * colorMapPixelSizeInBytes])); + bgra.FromBgra5551(Unsafe.As(ref palette[index * colorMapPixelSizeInBytes])); + if (!this.hasAlpha) { - // Set alpha value to 1, to treat it as opaque for Bgra5551. + // Set alpha value to 1, to treat it as opaque. bgra.PackedValue = (ushort)(bgra.PackedValue | 0x8000); } color.FromBgra5551(bgra); - pixelRow[x] = color; } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs index f932f994d..840bb55f2 100644 --- a/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs @@ -6,6 +6,7 @@ using Microsoft.DotNet.RemoteExecutor; using SixLabors.ImageSharp.Formats.Tga; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Tests.TestUtilities; using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; using Xunit; @@ -499,6 +500,54 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga } } + [Theory] + [WithFile(Bit32PalRleTopLeft, PixelTypes.Rgba32)] + public void TgaDecoder_CanDecode_RLE_Paletted_WithTopLeftOrigin_32Bit(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using (Image image = provider.GetImage(TgaDecoder)) + { + image.DebugSave(provider); + TgaTestUtils.CompareWithReferenceDecoder(provider, image); + } + } + + [Theory] + [WithFile(Bit32PalRleBottomLeft, PixelTypes.Rgba32)] + public void TgaDecoder_CanDecode_RLE_Paletted_WithBottomLeftOrigin_32Bit(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using (Image image = provider.GetImage(TgaDecoder)) + { + image.DebugSave(provider); + TgaTestUtils.CompareWithReferenceDecoder(provider, image); + } + } + + [Theory] + [WithFile(Bit32PalRleTopRight, PixelTypes.Rgba32)] + public void TgaDecoder_CanDecode_RLE_WithTopRightOrigin_32Bit(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using (Image image = provider.GetImage(TgaDecoder)) + { + image.DebugSave(provider); + TgaTestUtils.CompareWithReferenceDecoder(provider, image); + } + } + + [Theory] + [WithFile(Bit32PalRleBottomRight, PixelTypes.Rgba32)] + public void TgaDecoder_CanDecode_RLE_Paletted_WithBottomRightOrigin_32Bit(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using (Image image = provider.GetImage(TgaDecoder)) + { + image.DebugSave(provider); + TgaTestUtils.CompareWithReferenceDecoder(provider, image); + } + } + [Theory] [WithFile(Bit16PalBottomLeft, PixelTypes.Rgba32)] public void TgaDecoder_CanDecode_WithPaletteBottomLeftOrigin_16Bit(TestImageProvider provider) @@ -559,6 +608,54 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga } } + [Theory] + [WithFile(Bit24PalRleTopLeft, PixelTypes.Rgba32)] + public void TgaDecoder_CanDecode_RLE_WithPaletteTopLeftOrigin_24Bit(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using (Image image = provider.GetImage(TgaDecoder)) + { + image.DebugSave(provider); + TgaTestUtils.CompareWithReferenceDecoder(provider, image); + } + } + + [Theory] + [WithFile(Bit24PalRleTopRight, PixelTypes.Rgba32)] + public void TgaDecoder_CanDecode_RLE_WithPaletteTopRightOrigin_24Bit(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using (Image image = provider.GetImage(TgaDecoder)) + { + image.DebugSave(provider); + TgaTestUtils.CompareWithReferenceDecoder(provider, image); + } + } + + [Theory] + [WithFile(Bit24PalRleBottomLeft, PixelTypes.Rgba32)] + public void TgaDecoder_CanDecode_RLE_WithPaletteBottomLeftOrigin_24Bit(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using (Image image = provider.GetImage(TgaDecoder)) + { + image.DebugSave(provider); + TgaTestUtils.CompareWithReferenceDecoder(provider, image); + } + } + + [Theory] + [WithFile(Bit24PalRleBottomRight, PixelTypes.Rgba32)] + public void TgaDecoder_CanDecode_RLE_WithPaletteBottomRightOrigin_24Bit(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using (Image image = provider.GetImage(TgaDecoder)) + { + image.DebugSave(provider); + TgaTestUtils.CompareWithReferenceDecoder(provider, image); + } + } + [Theory] [WithFile(Bit32PalTopLeft, PixelTypes.Rgba32)] public void TgaDecoder_CanDecode_WithPalette_32Bit(TestImageProvider provider) diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index e475a7712..892568803 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -420,6 +420,11 @@ namespace SixLabors.ImageSharp.Tests public const string Bit24PalBottomLeft = "Tga/targa_24bit_pal.tga"; public const string Bit24PalBottomRight = "Tga/indexed_LR.tga"; + public const string Bit24PalRleTopLeft = "Tga/indexed_rle_UL.tga"; + public const string Bit24PalRleBottomLeft = "Tga/indexed_rle_LL.tga"; + public const string Bit24PalRleTopRight = "Tga/indexed_rle_UR.tga"; + public const string Bit24PalRleBottomRight = "Tga/indexed_rle_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"; @@ -435,6 +440,11 @@ namespace SixLabors.ImageSharp.Tests public const string Bit32RleBottomRight = "Tga/rgb_a_rle_LR.tga"; public const string Bit32RleBottomLeft = "Tga/targa_32bit_rle.tga"; + public const string Bit32PalRleTopLeft = "Tga/indexed_a_rle_UL.tga"; + public const string Bit32PalRleBottomLeft = "Tga/indexed_a_rle_LL.tga"; + public const string Bit32PalRleTopRight = "Tga/indexed_a_rle_UR.tga"; + public const string Bit32PalRleBottomRight = "Tga/indexed_a_rle_LR.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"; diff --git a/tests/Images/Input/Tga/indexed_a_rle_LL.tga b/tests/Images/Input/Tga/indexed_a_rle_LL.tga new file mode 100644 index 000000000..519e9322d Binary files /dev/null and b/tests/Images/Input/Tga/indexed_a_rle_LL.tga differ diff --git a/tests/Images/Input/Tga/indexed_a_rle_LR.tga b/tests/Images/Input/Tga/indexed_a_rle_LR.tga new file mode 100644 index 000000000..ed2176686 Binary files /dev/null and b/tests/Images/Input/Tga/indexed_a_rle_LR.tga differ diff --git a/tests/Images/Input/Tga/indexed_a_rle_UL.tga b/tests/Images/Input/Tga/indexed_a_rle_UL.tga new file mode 100644 index 000000000..755528010 Binary files /dev/null and b/tests/Images/Input/Tga/indexed_a_rle_UL.tga differ diff --git a/tests/Images/Input/Tga/indexed_a_rle_UR.tga b/tests/Images/Input/Tga/indexed_a_rle_UR.tga new file mode 100644 index 000000000..3d0cee361 Binary files /dev/null and b/tests/Images/Input/Tga/indexed_a_rle_UR.tga differ diff --git a/tests/Images/Input/Tga/indexed_rle_LL.tga b/tests/Images/Input/Tga/indexed_rle_LL.tga new file mode 100644 index 000000000..414e151a3 Binary files /dev/null and b/tests/Images/Input/Tga/indexed_rle_LL.tga differ diff --git a/tests/Images/Input/Tga/indexed_rle_LR.tga b/tests/Images/Input/Tga/indexed_rle_LR.tga new file mode 100644 index 000000000..0fafa56d3 Binary files /dev/null and b/tests/Images/Input/Tga/indexed_rle_LR.tga differ diff --git a/tests/Images/Input/Tga/indexed_rle_UL.tga b/tests/Images/Input/Tga/indexed_rle_UL.tga new file mode 100644 index 000000000..da7153daf Binary files /dev/null and b/tests/Images/Input/Tga/indexed_rle_UL.tga differ diff --git a/tests/Images/Input/Tga/indexed_rle_UR.tga b/tests/Images/Input/Tga/indexed_rle_UR.tga new file mode 100644 index 000000000..f1a52640f Binary files /dev/null and b/tests/Images/Input/Tga/indexed_rle_UR.tga differ