bioformats
bioformats copied to clipboard
TIFF: Incorrect PhotometricInterpretation on converted TIFF
Issue was raised on forum thread https://forum.image.sc/t/issues-with-ndpi-wsi-conversion-to-ome-tiff-concerning-kheops-qupath-ome-types/69862/8 and could be reproduced with the provided sample file and bftools 6.10.0
The sample file provided in thread is using PhotometricInterpretation of YCbCr, yet when saved to TIFF it is RGB (For OME-TIFF the PhotometricInterpretation metadata is included in the global metadata still). Looking at the TiffSaver code (https://github.com/ome/bioformats/blob/4463f22b7e098e684105eda19e0df1a4fc0f3697/components/formats-bsd/src/loci/formats/tiff/TiffSaver.java#L987-L994) there appears to be a limited number of PhotometricInterpretation values supported in the writing. @melissalinkert would you know the reasoning behind this?
The output from tiffinfo:
TIFF Directory at offset 0x483a4b5 (75736245)
Image Width: 16864 Image Length: 6976
Tile Width: 1024 Tile Length: 1024
Resolution: 11093, 11093 pixels/cm
Bits/Sample: 8
Sample Format: unsigned integer
Compression Scheme: JPEG
Photometric Interpretation: RGB color
Samples/Pixel: 3
Planar Configuration: single image plane
ImageDescription: ImageJ=
The showinf output lists the PhotometricInterpretation in the global metadata:
YCbCrSubSampling: chroma image dimensions = luma image dimensions
PhotometricInterpretation: YCbCr
Here's the relevant section from the TIFF Technical Note #2:
What data is being compressed?
In lossy JPEG compression, it is customary to convert color source data to YCbCr and then downsample it before JPEG compression. This gives 2:1 data compression with hardly any visible image degradation, and it permits additional space savings within the JPEG compression step proper. However, these steps are not considered part of the ISO JPEG standard. The ISO standard is "color blind": it accepts data in any color space.
For TIFF purposes, the JPEG compression tag is considered to represent the ISO JPEG compression standard only. The ISO standard is applied to the same data that would be stored in the TIFF file if no compression were used. Therefore, if color conversion or downsampling are used, they must be reflected in the regular TIFF fields; these steps are not considered to be implicit in the JPEG compression tag value. PhotometricInterpretation and related fields shall describe the color space actually stored in the file. With the TIFF 6.0 field definitions, downsampling is permissible only for YCbCr data, and it must correspond to the YCbCrSubSampling field. (Note that the default value for this field is not 1,1; so the default for YCbCr is to apply downsampling!) It is likely that future versions of TIFF will provide additional PhotometricInterpretation values and a more general way of defining subsampling, so as to allow more flexibility in JPEG-compressed files. But that issue is not addressed in this Tech Note.
Implementors should note that many popular JPEG codecs (compressor/decompressors) provide automatic color conversion and downsampling, so that the application may supply full-size RGB data which is nonetheless converted to downsampled YCbCr. This is an implementation convenience which does not excuse the TIFF control layer from its responsibility to know what is really going on. The PhotometricInterpretation and subsampling fields written to the file must describe what is actually in the file.
A JPEG-compressed TIFF file will typically have PhotometricInterpretation = YCbCr and YCbCrSubSampling = [2,1] or [2,2], unless the source data was grayscale or CMYK.
Hello, I think tiffsaver is not setting the JPEGCOLOURMODE
pseudo tag, or I can't find it in this file:
https://github.com/ome/bioformats/blob/4463f22b7e098e684105eda19e0df1a4fc0f3697/components/formats-bsd/src/loci/formats/tiff/TiffSaver.java
This is not a real tag, but instead an instruction to the JPEG writer inside libtiff that it should enable the JPEG RGB -> YCbCr transform and chrominance subsampling.
I would suggest:
- detect RGB images (they must have exactly three bands and be 8 bit)
- force photometric interpretation
PHOTOMETRIC_YCBCR
- call
TIFFSetField( tif, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB );
- write RGB pixels to libtiff
And you'll get a correctly tagged and small jpeg-in-tiff file.
You can also write RGB with no transform to YCbCr and no chroma subsampling (you get effectively YYY), but files are 3x larger and there's little improvement in quality except at very high Q.
Do you have any more info on the JPEGCOLOURMODE tag? I can't find any details on it, the TiffSaver here isn't using libtiff for the writing so it may not be necessary in this case. There is also one of our open PR's which includes changes to resolve the issue with the photometric interpretation.
Hi @dgault,
Here's the bit of the libvips saver that does this:
https://github.com/libvips/libvips/blob/master/libvips/foreign/vips2tiff.c#L770-L781
It's documented in the "pseudo tags" section:
http://www.simplesystems.org/libtiff/functions/libtiff.html#pseudo-tags
If you set it to RGB, libtiff will convert your RGB pixels to YCbCr and do chroma subsampling for you.
TiffSaver here isn't using libtiff for the writing
Oh, sorry, I missed this. You're right, if this isn't libtiff there's probably some other mechanism to control the JPEG compressor's RGB->YCbCR converter, you'd need to read their docs. Maybe all you need to do is set PHOTOMETRICINTERPRETATION
?
Sorry for the noise.