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 support for decoding 6, 12, 30, 42 bits per pixel tiff's #1647

Merged
merged 12 commits into from Jun 3, 2021

Conversation

brianpopow
Copy link
Collaborator

@brianpopow brianpopow commented Jun 1, 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 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 support for decoding:

  • 12 bit (4 bits per channel, RGB chunky) TIFF images.
  • 6 bit (2 bits per channel, RGB chunky) TIFF images.
  • 30 bit (10 bits per channel, RGB chunky) TIFF images.
  • 42 bit (14 bits per channel, RGB chunky) TIFF images.

/cc @IldarKhayrutdinov

@@ -274,6 +278,7 @@ public void Process(TiffEncoderCore encoder)
Value = (ushort)encoder.PhotometricInterpretation
};

this.collector.AddOrReplace(planarConfig);
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

note that I have explicitly added the chunky planar configuration, otherwise it could have accidentally be possible that it would be set to planar, if the decoded images was planar.

Copy link
Member

Choose a reason for hiding this comment

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

I don't really understand this change. Could you please explain to me what the issue is with pulling the value from the decoder if present?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

There are two possible values of the PlanarConfiguration:

  • Chunky: The data is stored as RGBRGBRGB. This is the default mode.
  • Planar: This is more uncommon. The data is stored as:
    RRR
    GGG
    BBB

The Tiff Encoder does always encodes the data as Chunky, but does not make this explicitly by storing a value for the PlanarConfiguration. The value is omitted and because decoders will assume Chunky this will work.

Now in the case of when we decode an actual 'Planar' Tiff and the reencode this TIFF again, the PlanarConfiguration would carry over to the encoded image, because its present in the EXIF profile. This would change the interpretation of the data and make the encoded image invalid. Therefore i thought it would be a good idea to make it explicit and always set it to Chunky.

@codecov
Copy link

codecov bot commented Jun 1, 2021

Codecov Report

Merging #1647 (036b95b) into master (3764b1c) will increase coverage by 0.05%.
The diff coverage is 74.69%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #1647      +/-   ##
==========================================
+ Coverage   84.15%   84.20%   +0.05%     
==========================================
  Files         812      813       +1     
  Lines       35634    35710      +76     
  Branches     4147     4154       +7     
==========================================
+ Hits        29987    30070      +83     
+ Misses       4831     4824       -7     
  Partials      816      816              
Flag Coverage Δ
unittests 84.20% <74.69%> (+0.05%) ⬆️

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

Impacted Files Coverage Δ
...metricInterpretation/RgbPlanarTiffColor{TPixel}.cs 100.00% <ø> (ø)
src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs 87.61% <ø> (+20.95%) ⬆️
...eSharp/Formats/Tiff/TiffBitsPerSampleExtensions.cs 18.91% <18.18%> (+1.27%) ⬆️
...mageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs 61.46% <83.33%> (+7.70%) ⬆️
...ImageSharp/Formats/Tiff/Constants/TiffConstants.cs 100.00% <100.00%> (ø)
...otometricInterpretation/Rgb444TiffColor{TPixel}.cs 100.00% <100.00%> (ø)
...cInterpretation/TiffColorDecoderFactory{TPixel}.cs 61.11% <100.00%> (+11.11%) ⬆️
src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs 94.77% <100.00%> (+0.07%) ⬆️
...eSharp/Formats/Tiff/TiffEncoderEntriesCollector.cs 85.61% <100.00%> (+0.40%) ⬆️
... and 3 more

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 3764b1c...036b95b. Read the comment docs.

Copy link
Contributor

@IldarKhayrutdinov IldarKhayrutdinov left a comment

Choose a reason for hiding this comment

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

SamplesPerPixel tag can have arbitrary value and can have different bits per component for each component corresponding to a pixel.

We don't need to support different different bits per component other than 565 (and 555), but we can support the same arbitrary bit values: {2,2,2}, {3,3,3}...

@@ -179,7 +180,18 @@ private static void ParseColorType(this TiffDecoderCore options, ExifProfile exi

if (options.PlanarConfiguration == TiffPlanarConfiguration.Chunky)
{
options.ColorType = options.BitsPerSample == TiffBitsPerSample.Bit24 ? TiffColorType.Rgb888 : TiffColorType.Rgb;
Copy link
Contributor

Choose a reason for hiding this comment

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

@brianpopow TiffColorType.Rgb - it seems that we have stopped supporting custom RGB (not in this PR, but even earlier).

@IldarKhayrutdinov
Copy link
Contributor

IldarKhayrutdinov commented Jun 2, 2021

The patch is workaround support for RGB {2,2,2} using RgbTiffColor:
custom_rgb.zip

Test images:
tiger-rgb-float-strip-contig-16.tif
tiger-rgb-strip-contig-03.tif
tiger-rgb-strip-contig-02.tif

@brianpopow
Copy link
Collaborator Author

brianpopow commented Jun 2, 2021

The patch is workaround support for RGB {2,2,2} using RgbTiffColor:
custom_rgb.zip

Test images:
tiger-rgb-float-strip-contig-16.tif
tiger-rgb-strip-contig-03.tif
tiger-rgb-strip-contig-02.tif

yeah you are right, we can do it this way, but I think this should be another PR. Feel free to open another PR with it.

edit: @IldarKhayrutdinov good spot, that we can actually use the magick decoder for 2 and 4 bit!

@brianpopow
Copy link
Collaborator Author

@dlemstra could you please double check, if the usage of ImageMagick for 4 bit and 2 bit is correct here: bc723d3

@IldarKhayrutdinov
Copy link
Contributor

we can do it this way, but I think this should be another PR. Feel free to open another PR with it.

yeah, this PR nothing breaks, it should be another PR

brianpopow and others added 2 commits June 2, 2021 20:25
@JimBobSquarePants
Copy link
Member

SamplesPerPixel tag can have arbitrary value and can have different bits per component for each component corresponding to a pixel.

We don't need to support different different bits per component other than 565 (and 555), but we can support the same >arbitrary bit values: {2,2,2}, {3,3,3}...

@IldarKhayrutdinov So what does this mean in regards to this PR?

@brianpopow
Copy link
Collaborator Author

SamplesPerPixel tag can have arbitrary value and can have different bits per component for each component corresponding to a pixel.
We don't need to support different different bits per component other than 565 (and 555), but we can support the same >arbitrary bit values: {2,2,2}, {3,3,3}...

@IldarKhayrutdinov So what does this mean in regards to this PR?

Now that I thought about it again, I think Ildar meant we can use RgbTiffColor{TPixel} for all bit values which have the same values for all channels. So we dont actually need Rgb444TiffColor{TPixel}.cs and can use RgbTiffColor{TPixel}. I think i misunderstood that when I first read it. Is that correct @IldarKhayrutdinov? I will convert this to WIP and check it again.

@brianpopow brianpopow changed the title Add support for decoding 12 bits per pixel tiff's WIP: Add support for decoding 12 bits per pixel tiff's Jun 2, 2021
@IldarKhayrutdinov
Copy link
Contributor

IldarKhayrutdinov commented Jun 3, 2021

SamplesPerPixel tag can have arbitrary value and can have different bits per component for each component corresponding to a pixel.
We don't need to support different different bits per component other than 565 (and 555), but we can support the same >arbitrary bit values: {2,2,2}, {3,3,3}...

@IldarKhayrutdinov So what does this mean in regards to this PR?

@JimBobSquarePants
This PR doesn't change anything, but only adds support for 4-bit RGB, so can separate different SamplesPerPixel problem into new PR (this will require api change). It seems like once upon a time support was conceived and it was supposed to work (but were no tests), but at some point it stopped being supported, I missed this moment.

In principle, this is not a bug, but we must support it, since it is worth a little effort for us.
Do it in this PR or in the new PR, you decide ☺️

@IldarKhayrutdinov
Copy link
Contributor

IldarKhayrutdinov commented Jun 3, 2021

Now that I thought about it again, I think Ildar meant we can use RgbTiffColor{TPixel} for all bit values which have the same values for all channels. So we dont actually need Rgb444TiffColor{TPixel}.cs and can use RgbTiffColor{TPixel}. I think i misunderstood that when I first read it. Is that correct @IldarKhayrutdinov? I will convert this to WIP and check it again.

@brianpopow Rgb444TiffColor{TPixel} is needed because RgbTiffColor{TPixel} is slow, also worth adding most relevant 555/565. Non-standard cases are rare, for them can use RgbTiffColor{TPixel}.

By the way, RgbTiffColor{TPixel} is can to decode any arbitrary SamplesPerPixel for 1-16 (can expand to 32) bits per sample: {2,2,2}, {3,3,3}, {5,6,5}, {7,6,5}..

@brianpopow brianpopow changed the title WIP: Add support for decoding 12 bits per pixel tiff's Add support for decoding 6, 12, 30, 42 bits per pixel tiff's Jun 3, 2021
@brianpopow
Copy link
Collaborator Author

In principle, this is not a bug, but we must support it, since it is worth a little effort for us.
Do it in this PR or in the new PR, you decide ☺️

@IldarKhayrutdinov thanks for the clarification.
I have added support for 6, 10 and 14 bit per channel and use RgbTiffColor{TPixel} for that. Note that I decided to not add 3 bits per channel support, since I think its not really a valid option. 9 bit per pixel would be completely unaligned at the byte border and I did not see those in the tiff-testsuite either. Also 565 should be a separate PR since i think its worth to implement its own TiffColorDecoder.

case TiffColorType.Rgb222:
DebugGuard.IsTrue(
bitsPerSample.Length == 3
&& bitsPerSample[0] == 2
Copy link
Member

Choose a reason for hiding this comment

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

You can use the indexer check skipping trick discussed the other day here I reckon.

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.

Very cool! Love how well structured this all is. 👍

@brianpopow brianpopow merged commit 4d7e829 into master Jun 3, 2021
@brianpopow brianpopow deleted the bp/tiff12bit branch June 3, 2021 15:45
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

4 participants