-
-
Notifications
You must be signed in to change notification settings - Fork 855
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix run-length encode compression implementation mistake in tga encoder #2172
Conversation
@l1nxy thanks for providing a fix for this. Some questions I have:
|
ImageMagick thinks the old cross multiple scan line format and new format which do not cross multiple scan lines all of those are correct, and I was find this microsoft/DirectXTex#251. |
I will close this pr and make a new one, which should add a new option to control which RLE compression is selected. |
Mhm, I dont think this is a good idea. Why would someone want to have an option to write a invalid tga? If its against the spec, we should not do it. |
But the legacy format is used widely, ImageMagick and Many picture viewers can detect the legacy format. |
I think its ok, if we can decode such image, but I dont think we should encode such tga which do not follow the spec. Can we actually decode such images? You have not provided a test image yet. edit: Also note you can add commits to this PR without the need to re-open a new one. |
OK, thank you very much. i will provide some test pic later. and test the encoder. |
Just to confirm. We should aim to be able to decode both old and new specification. |
Yes, that is what I would suggest. |
There is the test_pic.zip. And I wrote another demo that used ImageSharp to read this TGA file and save it directly to another TGA file which named Repeat this procedure using modified code, It can be read by DirectxTex correctly. The TGA decoder can read these three files, so the decoder implementation is correct, But there is a wired thing is the image size generated by ImageSharp bigger than the file generated by ImageMagick. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would like two unit tests to be added to make sure it works now as it should. (I would do it by myself, but for some weird reason gitlfs does not let me push to this PR)
- One test for decoding the legacy format (even though we can decode it already, a test to make sure would be nice).
Add the following toTgaDecoderTests.cs
[Theory]
[WithFile(Github_RLE_legacy, PixelTypes.Rgba32)]
public void TgaDecoder_CanDecode_LegacyFormat<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage(TgaDecoder))
{
image.DebugSave(provider);
ImageComparingUtils.CompareWithReferenceDecoder(provider, image);
}
}
and the Github_RLE_legacy
to TestImages.cs
.
- Make sure the encoded bytes now matches the expected size. Add to
TgaEncoderTests.cs
// Run length encoded pixels should not exceed row boundaries.
// https://github.com/SixLabors/ImageSharp/pull/2172
[Theory]
[MemberData(nameof(TgaBitsPerPixelFiles))]
public void TgaEncoder_RunLengthDoesNotCrossRowBoundaries(string imagePath, TgaBitsPerPixel bmpBitsPerPixel)
{
var options = new TgaEncoder() { Compression = TgaCompression.RunLength };
var testFile = TestFile.Create(imagePath);
using (Image<Rgba32> input = testFile.CreateRgba32Image())
{
using (var memStream = new MemoryStream())
{
input.Save(memStream, options);
// TODO assert the current encoded bytes match.
}
}
}
bool firstRow = true; | ||
TPixel startPixel = pixels[xStart, yStart]; | ||
for (int y = yStart; y < pixels.Height; y++) | ||
TPixel startPixel = pixels[xStart, yPos]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of using the indexer, you could use DangerousGetRowSpan
, which should be faster. Like this:
Span<TPixel> pixelRow = pixels.DangerousGetRowSpan(yPos).Slice(xStart);
There's a whole heap of issues related to GitHub, Git LFS and forks. Looks like they're finally on to figuring out a cause though which is ace. I use a workaround for pushing to forks when there is no LFS files to be added but that won't help in this case. |
I had some more time looking into this. The size difference currently fort the given testimage is:
The reason for that is, that we always write Run-Length Packets. If consecutive pixels are not the same, this will add an additional byte overhead to each pixel data. This will add up alot, if there are not many pixels equal. (note: the test image looks good for RLE, but it has transparency). So to fix this, we need to change this to not always write RLE packets. |
I will go ahead and merge this. Code itself looks good, just tests are missing. I will do a follow up PR to add tests and fix the image size issue, since I do not know how to work around the git lfs issues |
It's still using the indexer to access pixels which will be slow. Best make sure your follow up fixes that. |
Prerequisites
Description
According to the Tga format spec page 24:
It should not cross multiple lines when using Run-length encode compression. Some libraries can not fix the rle mistake when importing images saved by ImageSharp, and will throw an exception.