Skip to content
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

Add progressive JPEG encoder #2740

Open
wants to merge 11 commits into
base: main
Choose a base branch
from

Conversation

ardabada
Copy link

@ardabada ardabada commented May 21, 2024

Prerequisites

  • I have written a descriptive pull-request title
  • I have verified that there are no overlapping pull-requests open
  • I have verified that I am following the existing coding patterns and practice as demonstrated in the repository. These follow strict Stylecop rules 👮.
  • I have provided test coverage for my change (where applicable)

Description

This PR adds progressive JPEG encoder (see #10 and #449).
Implementation adapted from https://github.com/vstroebel/jpeg-encoder

No tests added yet. Restart interval also should be added.
Please take a look if it makes sense to you.

@CLAassistant
Copy link

CLAassistant commented May 21, 2024

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
2 out of 3 committers have signed the CLA.

✅ ardabada
✅ JimBobSquarePants
❌ Alexandr Ivanov


Alexandr Ivanov seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You have signed the CLA already but the status is still pending? Let us recheck it.

@JimBobSquarePants
Copy link
Member

Wow! Thanks @ardabada

Tests are failing just now due to a minor StyleCop issue (trailing space) would it be possible to fix that and add some additional unit tests to verify the encoded output?

@br3aker would you be able to help review this? It reuses most of the work you implemented.

@ardabada
Copy link
Author

Hi @JimBobSquarePants, I've added a test. The test suite seems quite complicated to me, and I need more time to understand how it works before I can write more complex, byte-level tests.

I've also split the WriteBlock method into two separate methods: WriteDc and WriteAcBlock. This change was necessary because the progressive encoder requires different values in the for loop when writing AC components. Additionally, I've updated the final if statement for writing the end of the block to check runLength > 0 instead of lastValuableIndex, since runLength is reset when encountering a non-zero coefficient. I hope this makes sense. CC @br3aker

I'd like to add a restart interval as well, but it seems to require more changes. WriteMarker is currently in JpegEncoderCore, and it should be called from HuffmanScanEncoder, which isn't an ideal solution. Therefore, I will postpone this for now.

@JimBobSquarePants
Copy link
Member

Hi @JimBobSquarePants, I've added a test. The test suite seems quite complicated to me, and I need more time to understand how it works before I can write more complex, byte-level tests.

I've also split the WriteBlock method into two separate methods: WriteDc and WriteAcBlock. This change was necessary because the progressive encoder requires different values in the for loop when writing AC components. Additionally, I've updated the final if statement for writing the end of the block to check runLength > 0 instead of lastValuableIndex, since runLength is reset when encountering a non-zero coefficient. I hope this makes sense. CC @br3aker

I'd like to add a restart interval as well, but it seems to require more changes. WriteMarker is currently in JpegEncoderCore, and it should be called from HuffmanScanEncoder, which isn't an ideal solution. Therefore, I will postpone this for now.

Thanks for the updates! I've no issue with duplicate WriteMarker calls for now if you find it easier to go that way..

I'll pull down your code ASAP and have a good read through. Maybe I can help write tests.

@JimBobSquarePants
Copy link
Member

Hi @ardabada apologies for the slow response. The code all looks great so far!

I think you can either

  1. Add a duplicate WriteMarkerHeader method to the HuffmanScanEncoder.
  2. Make WriteMarkerHeader static and internal passing the stream as a parameter.

I'm happy with whatever approach you take.

For tests I would keep it high level and simply encode/verify the output against expected results.

[WithFile(TestImages.Png.BikeGrayscale, nameof(LuminanceEncodingSetups), PixelTypes.L8)]
[WithFile(TestImages.Jpeg.Baseline.Cmyk, nameof(CmykEncodingSetups), PixelTypes.Rgb24)]
[WithFile(TestImages.Jpeg.Baseline.Ycck, nameof(YcckEncodingSetups), PixelTypes.Rgb24)]
public void EncodeProgressive_DefaultNumberOfScans<TPixel>(TestImageProvider<TPixel> provider, JpegEncodingColor colorType, int quality, float tolerance)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you can add an additional test setting the restart interval this would be good to merge! 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants