Para que se visualice correctamente las imágenes CMYK deben contener color space information como perfil ICC. Así que la mejor manera es utilizar ese perfil ICC que puede ser fácilmente extraída con Sanselan:
ICC_Profile iccProfile = Sanselan.getICCProfile(new File("filename.jpg"));
ColorSpace cs = new ICC_ColorSpace(iccProfile);
En caso de que no existe un perfil ICC adjunto a la imagen, usaría Adobe profiles como predeterminado.
Ahora el problema es que no se puede simplemente cargar un archivo JPEG con espacio de color personalizado usando ImageIO, ya que no generará una excepción quejándose de que no admite espacio de color o algo así. Hense tendrá que trabajar con rasters:
JPEGImageDecoder decoder = JPEGCodec.createJPEGDecoder(new ByteArrayInputStream(data));
Raster srcRaster = decoder.decodeAsRaster();
BufferedImage result = new BufferedImage(srcRaster.getWidth(), srcRaster.getHeight(), BufferedImage.TYPE_INT_RGB);
WritableRaster resultRaster = result.getRaster();
ColorConvertOp cmykToRgb = new ColorConvertOp(cs, result.getColorModel().getColorSpace(), null);
cmykToRgb.filter(srcRaster, resultRaster);
continuación, puede utilizar result
siempre que se necesite y tendrá colores convertidos.
En la práctica, he encontrado algunas imágenes (tomadas con cámara y procesadas con Photoshop) que de alguna manera habían invertido los valores de color, por lo que la imagen resultante siempre se invertía e incluso después de invertirlas eran demasiado brillantes. Aunque todavía no tengo ni idea de cómo averiguar en qué momento de usarlo (cuando necesito para invertir los valores de píxeles), tengo un algoritmo que corrige estos valores y convertir píxel de color por píxel:
JPEGImageDecoder decoder = JPEGCodec.createJPEGDecoder(new ByteArrayInputStream(data));
Raster srcRaster = decoder.decodeAsRaster();
BufferedImage ret = new BufferedImage(srcRaster.getWidth(), srcRaster.getHeight(), BufferedImage.TYPE_INT_RGB);
WritableRaster resultRaster = ret.getRaster();
for (int x = srcRaster.getMinX(); x < srcRaster.getWidth(); ++x)
for (int y = srcRaster.getMinY(); y < srcRaster.getHeight(); ++y) {
float[] p = srcRaster.getPixel(x, y, (float[])null);
for (int i = 0; i < p.length; ++i)
p[i] = 1 - p[i]/255f;
p = cs.toRGB(p);
for (int i = 0; i < p.length; ++i)
p[i] = p[i] * 255f;
resultRaster.setPixel(x, y, p);
}
estoy Bastante seguro de que RasterOp o ColorConvertOp podrían usarse para hacer la conversación más eficiente, pero esto fue suficiente para mí.
En serio, no hay necesidad de utilizar estos algoritmos de conversión de CMYK a RGB simplificados, ya que puede utilizar el Perfil ICC que está incrustado en la imagen o está disponible de forma gratuita desde Adobe. La imagen resultante se verá mejor si no perfecta (con perfil incrustado).
Todo el mundo siempre quiere una respuesta rápida, es inútil especificar – Eric
¿Cómo funcionó esta solución para usted? Veo que trataste de hacerlo sin el ICC_Colorspace, ¿pudiste mantenerlo? – TacB0sS