我正在编写一个用于确定JPEG图像色彩空间的代码。我找到了两个可以帮助我实现这个的参考资料。一个在oracle.com上,另一个是来自ijg.com的C源代码,其中#34;负责原始JPEG标准的参考实现"。
然而他们确实有所不同。例如。在IJG中,当没有Adobe标记并且有4个通道时它被假定为CMYK,但在oracle中它是YCCA。此外,IJG的实现并未考虑子采样,而对于4通道子采样,它在oracle规范中是YCCK,依此类推。
ColorSpace类中还有很多缺失,当我实现oracle的逻辑时,我需要指定3个额外的颜色空间,如YCCK,YCCA,RGBA。
另一点是我发现JPEG不支持alpha通道here中的透明度的信息,为什么oracle会在JPEG metadat规范的上下文中讨论YCCA和RGBA?
结果当用IJG的逻辑检查图像时,它告诉我它是CMYK(在ubuntu上用ImageMagick检查图像,它也说它是CMYK),用oracle的逻辑它是YCCA。谁相信?为什么oracle不依赖于原始的JPEG规范?或者还有其他我不知道的东西?
答案 0 :(得分:5)
在我对旧的JPEG标签发表评论之后,我终于找到了答案。
在ISO/IEC 10918-6:2013 (E)上,第6.1节:
假设只使用一个分量编码的图像是灰度数据,其中0为黑色,255为白色。
假设使用三个分量编码的图像是编码为YCbCr的RGB数据,除非图像 包含6.5.3中指定的APP14标记段,在这种情况下,会考虑颜色编码 根据APP14标记段的应用数据,RGB或YCbCr。关系 RGB和YCbCr之间的定义如Rec。中所述。 ITU-T T.871 | ISO / IEC 10918-5。
使用四个组件编码的图像被假定为 CMYK ,其中(0,0,0,0)表示白色,除非 图像包含6.5.3中指定的APP14标记段,在这种情况下颜色编码是 根据APP14标记段的应用数据,考虑 CMYK 或 YCCK 。该 CMYK 与 YCCK 之间的关系定义如第7条所述。
且APP14标志为" Adobe\0
",AP12具有转换标志:
应支持变换标志值0,1和2,并解释如下:
0 - CMYK用于使用四个组件编码的图像,其中所有四个CMYK值都是 补充; RGB用于使用三个组件编码的图像;即,APP14标记没有 指定应用于图像数据的变换。
1 - 使用YCbCr颜色编码用三个分量编码的图像。
2 - 使用YCCK颜色编码用四个分量编码的图像。
所以,它取决于:它应该是CMYK,但如果APP14和AP12具有正确的值,它可能是YCCK。
答案 1 :(得分:1)
我一直在努力了解您所引用的Oracle文档。
根据我的经验,从写JPEG plugin for Java ImageIO开始,正确的做法就是遵循IJG的实施。这就是大多数软件所做的事情,因此它会在您的用户中产生最少的混淆(即“为什么我的图像在您的软件和软件X中看起来不同?”)。在许多情况下,Sun / Oracle算法不同意“世界其他地方”。
我最终实现了一个稍微不同的算法,该算法考虑了“额外的”Java颜色空间,但在其他方面与IJG实现非常接近:
// Adapted from libjpeg jdapimin.c:
// Guess the input colorspace
// (Wish JPEG committee had provided a real way to specify this...)
switch (startOfFrame.componentsInFrame()) {
case 1:
return JPEGColorSpace.Gray;
case 2:
return JPEGColorSpace.GrayA; // Java special case: Gray + Alpha
case 3:
if (jfif != null) {
return JPEGColorSpace.YCbCr; // JFIF implies YCbCr
}
else if (adobeDCT != null) {
switch (adobeDCT.transform) {
case AdobeDCT.Unknown:
return JPEGColorSpace.RGB;
case AdobeDCT.YCC:
return JPEGColorSpace.YCbCr;
default:
// TODO: Warning!
return JPEGColorSpace.YCbCr; // assume it's YCbCr
}
}
else {
// Saw no special markers, try to guess from the component IDs
int cid0 = startOfFrame.components[0].id;
int cid1 = startOfFrame.components[1].id;
int cid2 = startOfFrame.components[2].id;
if (cid0 == 1 && cid1 == 2 && cid2 == 3) {
return JPEGColorSpace.YCbCr; // assume JFIF w/out marker
}
else if (cid0 == 'R' && cid1 == 'G' && cid2 == 'B') {
return JPEGColorSpace.RGB; // ASCII 'R', 'G', 'B'
}
else if (cid0 == 'Y' && cid1 == 'C' && cid2 == 'c') {
return JPEGColorSpace.PhotoYCC; // Java special case: YCc
}
else {
// TODO: Warning!
return JPEGColorSpace.YCbCr; // assume it's YCbCr
}
}
case 4:
if (adobeDCT != null) {
switch (adobeDCT.transform) {
case AdobeDCT.Unknown:
return JPEGColorSpace.CMYK;
case AdobeDCT.YCCK:
return JPEGColorSpace.YCCK;
default:
// TODO: Warning!
return JPEGColorSpace.YCCK; // assume it's YCCK
}
}
else {
// Saw no special markers, try to guess from the component IDs
int cid0 = startOfFrame.components[0].id;
int cid1 = startOfFrame.components[1].id;
int cid2 = startOfFrame.components[2].id;
int cid3 = startOfFrame.components[3].id;
if (cid0 == 1 && cid1 == 2 && cid2 == 3 && cid3 == 4) {
return JPEGColorSpace.YCbCrA; // Java special case: YCbCrA
}
else if (cid0 == 'R' && cid1 == 'G' && cid2 == 'B' && cid3 == 'A') {
return JPEGColorSpace.RGBA; // Java special case: RGBA
}
else if (cid0 == 'Y' && cid1 == 'C' && cid2 == 'c' && cid3 == 'A') {
return JPEGColorSpace.PhotoYCCA; // Java special case: YCcA
}
else {
// TODO: Warning!
// No special markers, assume straight CMYK.
return JPEGColorSpace.CMYK;
}
}
default:
throw new IIOException("Cannot determine source color space");
}