【问题标题】:ImageIO.write converting color space RGB to CMYK for a JPG imageImageIO.write 将色彩空间 RGB 转换为 JPG 图像的 CMYK
【发布时间】:2020-05-04 06:25:59
【问题描述】:

我正在从客户端发送jpg 图像。图片以blob的形式发送。这是发送canvas图像的javascript代码

canvas.toBlob((blob) => {
    this.setState({preview: blob},
        () => {
            console.log(blob.size);
            let data = new FormData();
            // const test = URL.createObjectURL(blob);
            // console.log(test);
            const file = new File([blob], "File name", {type: "image/png"});
            data.append("file", file);
            console.log(this.state.preview);
            axios({
                method: "POST",
                data: data,
                url: "/media",
                headers: {
                    'Content-Type': 'multipart/form-data'
                }
            }).then().catch()
            // axios.post("http://localhost:8085/api/media", data).then(r => {}).catch()
        }
    );
}, "image/jpg", 0)

选择的文件是jpg文件,由于某些原因被转换为canvas,然后以blob的形式发送到服务器。

这是用java编写的服务器图像处理代码:

public void uploadMedia(MultipartFile mediaFile) {

  try{
    BufferedImage image = ImageIO.read(mediaFile.getInputStream());

    System.out.println(image.getColorModel().getColorSpace().getType() == ColorSpace.TYPE_RGB); //TRUE

    ImageIO.write(image, "jpg", new File("/Users/puspender/Desktop/Test/image.jpg"));  //BLACK IMAGE with CMYK color space
    ImageIO.write(image, "png", new File("/Users/puspender/Desktop/Test/image.png"));

  }catch(Exception e){}      

}

如果我为ImageIO.write 选择png 格式,则图像会成功保存,但如果格式为jpg,则会保存黑色图像,并且该黑色图像的color space 会更改为CMYK。即使原始文件是RGB,我也在控制台上打印了它,然后再保存文件。

仅当在客户端上裁剪图像(或其他内容)然后从中创建canvas 并将canvas 中的blob 作为有效负载发送时,才会出现此问题。使用<input type="file />选择文件时不会出现问题

更新:按照 Mike 的要求,我阅读并重新生成了由 ImageIo 生成的黑色 jpg。结果是一样的,都是黑色的图像。

File file = new File("/location/generated_black.jpg");
BufferedImage image = ImageIO.read(file);
ImageIO.write(image, "jpg", new File("/location/from-java-main-400x400.jpg"));

我还用原始文件测试了上面的代码,当时ImageIo 正确处理了它。

我注意到一件重要的事情:黑色图像实际上不是黑色,它只是由于色彩空间的变化而受到干扰的颜色。当我将它上传到 AWS S3 时,我注意到了这一点。这是图片(CMYK 原文件如下:

我设法正常工作。 this thread 上的一位出色的个人推荐了 this solution,它甚至运作良好。

但很少有问题保持不变:

  1. 为什么这只发生在blob javascript 发送的数据和 不是前面提到的普通文件选择器
  2. 为什么只在将图像格式设置为 jpg 而不是 png?以及为什么将color space 更改为jpgImageIo

【问题讨论】:

  • 问题:您为什么使用toBlob() 而不是canvas.toDataURL('image/jpeg'),然后将这些数据发送到您的服务器进行解包?
  • 因为toDataURL生成的字符串不被服务器的MultipartFile识别,请求被认为没有对应的处理程序
  • 以前我只是这样做并且得到400错误。
  • 这听起来像是你应该能够在没有客户端/服务器的情况下进行测试:如果你创建一个带有静态 main 的Test.java,它只是读取你保存时获得的 png 文件画布到文件,然后你尝试将 ImageIO.write 为 jpg,会发生什么? (基本上,这应该很容易变成minimal reproducible example,尤其是如果这也出错了,您可以直接将该 png 添加到您的帖子中,这样人们就可以同时拥有代码和资产来重现您所看到的内容)
  • @mike toDataURL 比原始二进制文件更慢/更大。

标签: javascript java image-processing imgscalr


【解决方案1】:

RGB 和 CMYK 不是颜色空间,而是颜色编码模型。

在这两种状态下都没有足够的信息来提供有意义的解决方案。

按照 ISO 22028-1 标准在词汇表中的定义,RGB 颜色空间规定它必须包括以下定义: 1. 原色 2. 传递函数 3.白点

对于 CMYK,必须明确标识纸张类型、油墨成分和光源等变量的响应。

忽略这些方面中的任何一个都意味着由此产生的颜色转换完全没有意义,并且对任何人都没有任何好处。

【讨论】: