且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

使用Java ImageIO读取和写入一些TIFF图像时,输出TIFF中的粉红色背景色

更新时间:2023-11-10 14:14:52

好的,通过检查示例文件,我认为我已经找到了问题所在.而且不在您的代码中*.

Okay, by inspecting the sample files, I think I have found the problem. And it's not in your code*.

使用JPEG压缩读写TIFF时,TIFF插件会将嵌入式JPEG流的解码/编码委托给JPEG插件.从理论上讲,这很简单,因为JPEG不包含颜色信息,而TIFF容器在262/PhotometricInterpretation标签中包含正确的颜色信息.

When reading and writing TIFF with JPEG compression, the TIFF plugin will delegate decoding/encoding of the embedded JPEG stream to the JPEG plugin. In theory, this is simple, because the JPEG contains no color information, and the TIFF container contains the correct color information in the 262/PhotometricInterpretation tag.

在现实生活中,这要复杂得多,因为有时TIFF标签丢失或不正确(尤其是与值为6259/Compression标签(旧JPEG")结合使用),或者是JPEG编码器/解码器我将对颜色空间做出自己的假设(基于独立JPEG的约定,通常是JFIF或Exif),我相信就是这种情况.与JRE捆绑在一起的JPEG插件使用

In real life, this is much more complex, because sometimes the TIFF tag is missing or incorrect (especially in combination with 259/Compression tag with value 6 ("Old JPEG"). Or the JPEG encoder/decoder will make its own assumptions about color space (based on conventions for standalone JPEGs, typically JFIF or Exif), which is what I believe is the case here. The JPEG plugin bundled with the JRE uses the conventions documented here, and color space is inferred from the component ids in the SOFn marker.

对于您的文件,我们可以看到组件ID有所不同.

For your files, we can see that the component ids differ.

肖像文件:

SOF0[ffc0, precision: 8, lines: 3520, samples/line: 2496, 
     components: [id: 1, sub: 1/1, sel: 0, id: 2, sub: 1/1, sel: 1, id: 3, sub: 1/1, sel: 1]]

风景文件:

SOF0[ffc0, precision: 8, lines: 2496, samples/line: 3520, 
    components: [id: 0, sub: 1/1, sel: 0, id: 1, sub: 1/1, sel: 1, id: 2, sub: 1/1, sel: 1]]

人像文件中的组件ID是普通的1、2和3,而风景文件的ID是0、1和2.两个文件都没有子采样(即1:1).

The component ids in the portrait file are the normal 1, 2, and 3, while the landscape has ids 0, 1, and 2. Both files has no subsampling (ie. 1:1).

根据惯例:

如果对于3通道图像,这些值是1-3,则假定图像为YCbCr [...]

否则,假定3通道二次采样图像为YCbCr,假定3通道非二次采样图像为RGB .

Otherwise, 3-channel subsampled images are assumed to be YCbCr, 3-channel non-subsampled images are assumed to be RGB.

因此,风景图像将被视为已在RGB中(并且错误地未从YCbCr转换而来),从而导致粉红色.即使TIFF容器中的所有其他内容都清楚地表明它是YCbCr.

Because of this, the landscape image will be treated as already in RGB (and, incorrectly, not converted from YCbCr), resulting in the pinkish tint. Even though everything else in the TIFF container clearly indicates that it's YCbCr.

为解决此问题(以及许多其他问题),我创建了我自己的JPEG插件可以用作JRE插件的替代品.它遵循IJG的libJPEG中的约定(简单得多),从而与其他应用程序具有更好的色彩空间一致性.结合使用来自同一项目的TIFF插件,可以正确读取两个输入(白色背景).我尚未使用JRE TIFF插件对其进行测试,但从理论上讲,它也应该/也可以工作.不幸的是,TwelveMonkeys TIFF插件还没有(还) 具有您使用(平铺)的写入功能,并且对其写入的元数据有一些限制.

To fix this issue (and many other issues), I have created my own JPEG plugin that can be used as a drop-in replacement for the JRE plugin. It follows (the much simpler) conventions found in IJG's libJPEG, resulting in better color space consistency with other applications. In combination with the TIFF plugin from the same project, both your inputs are read correctly (white background). I have not tested it with the JRE TIFF plugin, but in theory, it should/could also work. Unfortunately, the TwelveMonkeys TIFF plugin does not (yet) have the write capabilities you use (tiling) and has some limitations about what meta data it writes.

PS:由于您似乎主要处理的是在重新编码时质量下降的JPEG,因此您可能希望查看合并的TIFF,而不对图像数据进行解码.您可以在 TIFFUtilities ,由Oliver Schmidtmer编写.

PS: As you seem to deal mainly with JPEGs that degrade in quality when re-encoding, you might want to look at merging TIFFs without decoding the image data. You can find an example of that in TIFFUtilities, written by Oliver Schmidtmer.

*)从技术上来说,可以在代码中解决问题,但是正确处理所有情况是很复杂的.如果您想自己实现此功能,或者只是好奇,建议您查看

*) It is technically possible to work around the problem in your code, but it's kind of complex to handle all the cases correctly. If you want to implement this yourself, or are just curious I suggest you have a look at the source code for the TwelveMonkeys ImageIO JPEG plugin.