确定JPEG的色彩空间

时间:2018-06-11 12:41:21

标签: image jpeg color-space

我正在编写一个用于确定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规范?或者还有其他我不知道的东西?

2 个答案:

答案 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");
}