Per essere visualizzate correttamente le immagini CMYK dovrebbero contenere color space information come profilo ICC. Quindi il modo migliore è quello di utilizzare tale profilo ICC che può essere facilmente estratto con Sanselan:
ICC_Profile iccProfile = Sanselan.getICCProfile(new File("filename.jpg"));
ColorSpace cs = new ICC_ColorSpace(iccProfile);
Nel caso in cui non v'è alcun profilo ICC allegato all'immagine, vorrei utilizzare Adobe profiles come predefinito.
Ora il problema è che non è possibile caricare file JPEG con spazio colore personalizzato utilizzando ImageIO in quanto potrebbe non generare un'eccezione lamentandosi del fatto che non supporta lo spazio colore o lo sthing del genere. Hense si dovrà lavorare con raster:
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);
È quindi possibile utilizzare result
ovunque ne abbiate bisogno e avrà i colori convertiti.
In pratica, tuttavia, mi sono imbattuto in alcune immagini (scattate con la fotocamera e elaborate con Photoshop) che avevano in qualche modo invertito i valori dei colori, quindi l'immagine risultante era sempre invertita e anche dopo averli invertiti ancora una volta erano troppo luminosi. Anche se non ho ancora idea di come per sapere quando esattamente per usarlo (quando ho bisogno di invertire i valori dei pixel), ho un algoritmo che consente di correggere questi valori e convertire pixel di colore per pixel:
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);
}
Sono abbastanza sicuro che RasterOp o ColorConvertOp potessero essere usati per rendere la conversazione più efficiente, ma questo era abbastanza per me.
Seriamente, non è necessario utilizzare questi algoritmi di conversione CMYK-RGB semplificati poiché è possibile utilizzare il profilo ICC incorporato nell'immagine o disponibile gratuitamente da Adobe. L'immagine risultante sembrerà migliore se non perfetta (con profilo incorporato).
Tutti vogliono sempre una risposta veloce, è inutile specificare – Eric
Come ha funzionato questa soluzione? Vedo che hai provato ad andare in giro senza ICC_Colorspace, sei riuscito a continuare così? – TacB0sS