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

Jpeg 12 bit support #784

Merged
merged 8 commits into from
Dec 30, 2018
Merged

Jpeg 12 bit support #784

merged 8 commits into from
Dec 30, 2018

Conversation

feliwir
Copy link
Contributor

@feliwir feliwir commented Dec 6, 2018

Description

  • Adds 12-bit jpeg support as implemented in libjpeg and libjpeg-turbo
  • Adds a 12-bit jpeg testfile
  • Make jpeg decoder bitdepth invariant

@CLAassistant
Copy link

CLAassistant commented Dec 6, 2018

CLA assistant check
All committers have signed the CLA.

Copy link
Member

@JimBobSquarePants JimBobSquarePants left a comment

Choose a reason for hiding this comment

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

Great effort here, really appreciated!

A couple of minor changes required plus you're failing the Stylecop checks so if you can get those fixed we're rocking.

src/ImageSharp/Common/Tuples/Vector4Pair.cs Outdated Show resolved Hide resolved
src/ImageSharp/Common/Tuples/Vector4Pair.cs Outdated Show resolved Hide resolved
{
Vector4 CMin4 = new Vector4(0F);
Copy link
Member

Choose a reason for hiding this comment

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

These values are being calculated more than once in the same partial struct.

Copy link
Member

Choose a reason for hiding this comment

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

What we can do is to refactor the normalization logic into it's own stateful type (preferably a struct), where minimum/maximum/half values are nonstatic members initialized in the constructor.

private float MaximumValue { get; }

/// <summary>
/// Gets the maximum value of a sample
Copy link
Member

Choose a reason for hiding this comment

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

Repeated description

@feliwir feliwir changed the title [WIP] Jpeg 12 bit support Jpeg 12 bit support Dec 10, 2018
@JimBobSquarePants
Copy link
Member

It occurs to me that this adds decoding support not encoding so the image data will be lost. We should get the work done to allow supporting encoding also.

Copy link
Member

@antonfirsov antonfirsov left a comment

Choose a reason for hiding this comment

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

@feliwir good job, and thanks again for this improvement!

Just a quick initial web review, will clone the code later this week. Still left a few imrovement requests in comments.

Question:

  • Is it possible to have 12 bit precision jpegs for colorspaces other than YCbCr? (eg. CMYK, YCCK, RGB)
  • If yes, can we get some test images for these cases. adding them to our test suite?

{
Vector4 CMin4 = new Vector4(0F);
Copy link
Member

Choose a reason for hiding this comment

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

What we can do is to refactor the normalization logic into it's own stateful type (preferably a struct), where minimum/maximum/half values are nonstatic members initialized in the constructor.

@@ -10,8 +10,8 @@ internal abstract partial class JpegColorConverter
{
internal class FromCmyk : JpegColorConverter
{
public FromCmyk()
: base(JpegColorSpace.Cmyk)
public FromCmyk(int precision)
Copy link
Member

Choose a reason for hiding this comment

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

I prefer to have more type safety in the codebase. (-1, 17 and 222 are invalid values for precision ;) ). I suggest an enum having the following form, so you can easily cast it to int when necessary.

enum JpegPrecision
{
   EightBits = 8,
   TwelveBits = 12
}

Copy link
Member

Choose a reason for hiding this comment

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

Hmmm... Read section 4.7 here. Lossless jpeg supports additional precision so we should bear that in mind when naming our enum. https://www.w3.org/Graphics/JPEG/itu-t81.pdf

For DCT-based processes, two alternative sample precisions are specified: either 8 bits or 12 bits per sample. Applications which use samples with other precisions can use either 8-bit or 12-bit precision by shifting their source image samples appropriately. The baseline process uses only 8-bit precision. DCT-based implementations which handle 12-bit source image samples are likely to need greater computational resources than those which handle only 8-bit source images. Consequently in this Specification separate normative requirements are defined for 8-bit and 12-bit DCT-based processes.

For lossless processes the sample precision is specified to be from 2 to 16 bits

Copy link
Member

Choose a reason for hiding this comment

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

Oops. The options I see:

  1. Keep the type as is (int), and introduce some DebugGuard checks in the code
  2. Introduce an enum defining all entries for 2-16
  3. Since we do not support lossless jpeg, define only EightBits and TwelveBits for now, and YAGNI out the rest, letting our future selves to find out how to manage the lossless case.

I'm pretty much for option 3.

@@ -44,7 +44,7 @@ public JpegColorConverterTests(ITestOutputHelper output)
public void ConvertFromYCbCrBasic(int inputBufferLength, int resultBufferLength, int seed)
{
ValidateRgbToYCbCrConversion(
new JpegColorConverter.FromYCbCrBasic(),
new JpegColorConverter.FromYCbCrBasic(8),
Copy link
Member

Choose a reason for hiding this comment

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

We should add tests for 12 bit precision case.

@JimBobSquarePants
Copy link
Member

JimBobSquarePants commented Dec 13, 2018

@antonfirsov

Is it possible to have 12 bit precision jpegs for colorspaces other than YCbCr? (eg. CMYK, YCCK, RGB)

Yes, when 12bit support was added to the jpeg specification it covered all color spaces. On that note we cannot preserve that color data when saving the jpeg. We'll need to add the equivalent colorspace transformation code to the encoder with any additional requirements.

@antonfirsov
Copy link
Member

@JimBobSquarePants then we should find or generate 12 bit test jpegs for all the colorspaces, the feature is only partially tested otherwise!
We can decode the reference output with the ImageMagick reference decoder. The encoder could be implemented/tested separately.

@JimBobSquarePants
Copy link
Member

@antonfirsov Just spent the last 20 mins scouring the internet for an official source of test images and I've come up with nothing. libjpeg-turbo's repo contains 1 12bit file that doesn't appear to be supported by anything I have on my machine. https://github.com/libjpeg-turbo/libjpeg-turbo/tree/master/testimages

@antonfirsov
Copy link
Member

Ok, this means that those aren't real use cases on pure statistical basis, so we can leave them untested.

Standard meets reality.

@JimBobSquarePants
Copy link
Member

@feliwir @antonfirsov I had some time so I updated everything in the branch, removed some of the Linq stuff from the color converter and merged the reference image.

We're getting very close to having this ready to merge 🎉

Question though. Shall we had encoding 12bit jpegs to this PR or open a new Issue/PR. We'll need to create optimized color conversion methods to handle this.

@feliwir
Copy link
Contributor Author

feliwir commented Dec 22, 2018

We could add encoding, but not sure if i could help with that too much :D

@JimBobSquarePants
Copy link
Member

@antonfirsov When you have a chance can you please conduct a final review?

@antonfirsov
Copy link
Member

I the improvement opportunities I mentioned are still there (introducing an enum for 8bit/12bit, test cases for 12 bit color conversion), but let's just merge this as-is, and do the improvements later!

@JimBobSquarePants JimBobSquarePants merged commit db0fc0d into SixLabors:master Dec 30, 2018
@JimBobSquarePants
Copy link
Member

Merged. Thanks @feliwir !

antonfirsov pushed a commit to antonfirsov/ImageSharp that referenced this pull request Nov 11, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants