diff --git a/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs b/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs index a4e9bdcd75..816a472fb2 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 f932f994dc..840bb55f20 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 e475a7712f..892568803e 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 0000000000..147cc91011 --- /dev/null +++ b/tests/Images/Input/Tga/indexed_a_rle_LL.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2be79621e93dfdbd3ec9bea5085675719429cb264b1f9bbafa4ab2c9da28f677 +size 31665 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 0000000000..6859107d0d --- /dev/null +++ b/tests/Images/Input/Tga/indexed_a_rle_LR.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:419d28012037d85794d6839fc8bdaa4b830daf8d078b536a655dc65370c15a38 +size 31776 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 0000000000..be44253d20 --- /dev/null +++ b/tests/Images/Input/Tga/indexed_a_rle_UL.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:892b19c5e4da9ba4b96d3458d2ee35e1f64ca65e8f8f8b6eebb284e83a6bceab +size 31765 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 0000000000..b308ff7347 --- /dev/null +++ b/tests/Images/Input/Tga/indexed_a_rle_UR.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:42586d5d45bb922671755d019fe8d5f76c10ab856fcf6521fb7d114fba118c71 +size 31666 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 0000000000..6576d515a0 --- /dev/null +++ b/tests/Images/Input/Tga/indexed_rle_LL.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e3dbf4ae9566e00d2165d74f3c17208853954b4c1f1cbc4ebc321fe3adb29676 +size 30549 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 0000000000..2c14e37644 --- /dev/null +++ b/tests/Images/Input/Tga/indexed_rle_LR.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:32461dcf64ec2f6ccf6e17a7209c769a5594b8c94a31de7cc693d6abe6ba2081 +size 30610 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 0000000000..0a06b3a865 --- /dev/null +++ b/tests/Images/Input/Tga/indexed_rle_UL.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:841f05e9f8ecdade8c992b830b9bf5893494f41accb0f0fec30f4692866c1675 +size 30640 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 0000000000..1e68e545e7 --- /dev/null +++ b/tests/Images/Input/Tga/indexed_rle_UR.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a709594fd475dbe042c16671959bfbc0031e64db8e74375f01c29685d2e384ec +size 30500