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

Grayscale Jpeg encoding #1586

Merged
merged 7 commits into from
Mar 30, 2021

Conversation

ynse01
Copy link
Contributor

@ynse01 ynse01 commented Mar 28, 2021

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 matches 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

Implemented Grayscale JPEG encoding, as requested in issue #808 (first bullet).

This means, that for L8 or L16 pixel types, by default the JpegEncoder creates Grayscale, 1-component jpegs. This can also be forced upon other pixel type, by setting the ColorType property in the JpegEncoderOptions.

Grayscale Jpeg encoding performs better and results in a smaller file size.

Extended the JpegEncoderTests to cover Grayscale encoding and L8 pixel types also.

@CLAassistant
Copy link

CLAassistant commented Mar 28, 2021

CLA assistant check
All committers have signed the CLA.

@codecov
Copy link

codecov bot commented Mar 28, 2021

Codecov Report

Merging #1586 (4d0fb40) into master (08b0320) will increase coverage by 0.04%.
The diff coverage is 98.27%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #1586      +/-   ##
==========================================
+ Coverage   83.65%   83.69%   +0.04%     
==========================================
  Files         746      747       +1     
  Lines       32991    33055      +64     
  Branches     3680     3692      +12     
==========================================
+ Hits        27597    27665      +68     
+ Misses       4680     4676       -4     
  Partials      714      714              
Flag Coverage Δ
unittests 83.69% <98.27%> (+0.04%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted Files Coverage Δ
src/ImageSharp/Formats/Jpeg/JpegEncoder.cs 89.47% <83.33%> (-10.53%) ⬇️
...nents/Encoder/LuminanceForwardConverter{TPixel}.cs 100.00% <100.00%> (ø)
src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs 92.63% <100.00%> (+0.01%) ⬆️
src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs 96.42% <100.00%> (+1.56%) ⬆️
src/ImageSharp/Formats/Jpeg/JpegMetadata.cs 100.00% <100.00%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 08b0320...4d0fb40. Read the comment docs.

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.

Great addition, thank you very much! A few remarks, otherwise looks good.

Can anyone in @SixLabors/core check if the [WithFile(TestImages.Png.BikeGrayscale, nameof(BitsPerPixel_Quality), PixelTypes.L8)] case works for them and produces output locally? I have some troubles with ImageMagic on my PC.

src/ImageSharp/Formats/Jpeg/JpegSubsample.cs Outdated Show resolved Hide resolved
src/ImageSharp/Formats/Jpeg/JpegEncoder.cs Outdated Show resolved Hide resolved
tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs Outdated Show resolved Hide resolved
@brianpopow
Copy link
Collaborator

Can anyone in @SixLabors/core check if the [WithFile(TestImages.Png.BikeGrayscale, nameof(BitsPerPixel_Quality), PixelTypes.L8)] case works for them and produces output locally? I have some troubles with ImageMagic on my PC.

I have tested it (on windows), it works fine, it produces a gray image of the bike testimage. @antonfirsov what problem do you see on your pc?

@antonfirsov
Copy link
Member

@brianpopow don't mind it, must be local to my environment (+ want the PR review to stay on topic). Will report back on Slack if it will keep bothering me 😄 Thanks for checking!

{
if (this.ColorType == null)
{
bool isGrayscale = typeof(TPixel) == typeof(L8) || typeof(TPixel) == typeof(L16);
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 be storing the JpegColorType in the JpegMetadata class upon decode and querying both places with the encoder options taking precedence.

La16 and La32 should trigger grayscale also.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added La16 and La32 to JpegEncoder and added test cases for both.

Copy link
Member

Choose a reason for hiding this comment

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

Unresolving the conversation, since I think @JimBobSquarePants also asked for a decoder extension here, will try to explain what he likely meant in more detailed manner:

  • Define an optional JpegColorType? property in JpegMetadata
  • Detect JpegColorType in JpegDecoderCore and store it into the image's JpegMetadata.
  • In the encoder, also trigger the grayscale path in case if JpegMetadata.JpegColorType is set to JpegColorType.GrayScale

@ynse01 let us know if you feel comfortable and confident adding this. If not, I recommend to not block the PR on this, and open a tracking issue for the addition.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I gave it a try. Please indicate if this is what you guys expect.

@ynse01
Copy link
Contributor Author

ynse01 commented Mar 30, 2021

Thank you for the great feedback.

I have refactored my solution such, that the JpegSubsample.Grayscale option is no longer needed. I realized that it would have been hard to explain to users what it did.
Adopted the JpegEncoderTests accordingly.

Please have another look.

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.

This all looks fantastic. Thanks so much for taking your time to contribute, we really appreciate it!

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.

5 participants