Image JPEG avec de mauvaises couleurs

J’ai une méthode qui lit les images, les convertit (taille, format) et les réécrit. Cela a toujours très bien fonctionné, mais je suis tombé sur des images JPEG (d’une agence de presse) qui contiennent évidemment des métadonnées (IPTC). Lors de la conversion de ces images, les couleurs sont toutes fausses. Ma première supposition était que ce sont des images CMJN, mais elles ne le sont pas.

Le problème doit venir de la lecture, car peu importe que je convertisse l’image en JPEG ou PNG plus petit, elle est toujours identique.

Au début, j’ai utilisé ImageIO.read() pour lire l’image. J’ai maintenant le ImageReader réel via ImageIO.getImageReadersByMIMEType() et ImageIO.getImageReadersByMIMEType() essayé de dire au lecteur d’ignorer les métadonnées en définissant le paramètre ignoreMetadata d’ ImageReader#setInput(Object input, boolean seekForwardOnly, boolean ignoreMetadata) mais sans succès.

J’ai ensuite créé une version de l’image sans les métadonnées (à l’aide de Fireworks). Cette image est convertie correctement.

La seule différence que je pourrais trouver est que, avec l’image qui ne fonctionne pas, la valeur de la variable colorSpaceCode du lecteur est 2 , la plus élevée étant l’image de travail, la valeur est 3 . Il y a aussi un outColorSpaceCode qui est 2 pour les deux images.

En tant que commentaire source du lecteur, seul le rappel de code natif SetImageData est défini par Set by. Un code d’espace colorimésortingque IJG + NIFTY modifié Je suis vraiment bloqué maintenant. Donc, toute aide serait très appréciée.

Vous pouvez obtenir une image originale (~ 3 Mo) en cliquant ici et en téléchargeant. L’image de gauche ci-dessous montre ce que je reçois de l’image d’origine, la droite montre à quoi elle devrait ressembler.

mauvaises couleurscouleurs correctes (après suppression des métadonnées)

J’ai trouvé une solution maintenant, qui fonctionne, du moins si mon image résultante est également une image JPEG: d’abord, je lis l’image (à partir du tableau d’octets imageData), et plus important encore, je lis aussi les métadonnées.

 InputStream is = new BufferedInputStream(new ByteArrayInputStream(imageData)); Image src = null; Iterator it = ImageIO.getImageReadersByMIMEType("image/jpeg"); ImageReader reader = it.next(); ImageInputStream iis = ImageIO.createImageInputStream(is); reader.setInput(iis, false, false); src = reader.read(0); IIOMetadata imageMetadata = reader.getImageMetadata(0); 

Maintenant, je ferais de la conversion (c’est-à-dire une taille réduite) et enfin je rédigerais le résultat en tant qu’image JPEG. Ici, il est très important de transmettre les métadonnées de l’image originale au nouvel IIOImage .

 Iterator iter = ImageIO.getImageWritersByMIMEType("image/jpeg"); ImageWriter writer = iter.next(); ImageWriteParam iwp = writer.getDefaultWriteParam(); iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); iwp.setCompressionQuality(jpegQuality); ImageOutputStream imgOut = new MemoryCacheImageOutputStream(out); writer.setOutput(imgOut); IIOImage image = new IIOImage(destImage, null, imageMetadata); writer.write(null, image, iwp); writer.dispose(); 

Malheureusement, si j’écrivais une image PNG, j’obtiens toujours les mauvaises couleurs (même si je passe les métadonnées), mais je peux vivre avec cela.

J’ai eu des problèmes similaires, le BufferedImage renvoyé est un rendu basé sur la présence d’un pixel transparent, qui sera défini sur true pour la plupart des fichiers de type png / gif. Mais lors de la conversion en JPEG, cet indicateur devrait être défini sur false. Vous devez éventuellement écrire une méthode où la conversion est correctement gérée. c’est à dire:

 public static BufferedImage toBufferedImage(Image image) { ... } 

Sinon, cette nuance “marunish” devient le résultat enregistré. 🙂


J’ai eu un problème similaire. Je devais utiliser:

 Image image = java.awt.Toolkit.getDefaultToolkit().getImage(path); 

au lieu de

 Image image = javax.imageio.ImageIO.read(new File(path)); 

Je rencontrais ce problème et j’ai en fait trouvé une bibliothèque tierce qui s’en occupait pour moi. https://github.com/haraldk/TwelveMonkeys

Littéralement, tout ce que j’avais à faire était d’inclure ceci dans mes dépendances de Maven et les jpegs qui sortaient dans des couleurs étranges commençaient à être lus normalement. Je n’ai même pas eu à changer de ligne de code.

Voici un algorithme pour transformer la “mauvaise” image en une bonne image, cependant, je n’ai trouvé aucun moyen de détecter automatiquement si une image sera mal rendue, elle est donc toujours inutile.

Si quelqu’un trouve un moyen de détecter si une image sera rendue mauvaise (autre que l’œil), veuillez nous en informer. (comme, où puis-je obtenir cette valeur appelée colorSpaceCode ?!)

  private static void fixBadJPEG(BufferedImage img) { int[] ary = new int[img.getWidth() * img.getHeight()]; img.getRGB(0, 0, img.getWidth(), img.getHeight(), ary, 0, img.getWidth()); for (int i = ary.length - 1; i >= 0; i--) { int y = ary[i] >> 16 & 0xFF; // Y int b = (ary[i] >> 8 & 0xFF) - 128; // Pb int r = (ary[i] & 0xFF) - 128; // Pr int g = (y << 8) + -88 * b + -183 * r >> 8; // b = (y << 8) + 454 * b >> 8; r = (y << 8) + 359 * r >> 8; if (r > 255) r = 255; else if (r < 0) r = 0; if (g > 255) g = 255; else if (g < 0) g = 0; if (b > 255) b = 255; else if (b < 0) b = 0; ary[i] = 0xFF000000 | (r << 8 | g) << 8 | b; } img.setRGB(0, 0, img.getWidth(), img.getHeight(), ary, 0, img.getWidth()); } 

Semble bien ici:

Résultat de TestImage

 import java.awt.image.BufferedImage; import java.net.URL; import java.io.File; import javax.imageio.ImageIO; import javax.swing.*; class TestImage { public static void main(Ssortingng[] args) throws Exception { URL url = new URL("http://i.stack.imgur.com/6vy74.jpg"); BufferedImage origImg = ImageIO.read(url); JOptionPane.showMessageDialog(null,new JLabel(new ImageIcon(origImg))); File newFile = new File("new.png"); ImageIO.write(origImg, "png", newFile); BufferedImage newImg = ImageIO.read(newFile); JOptionPane.showMessageDialog(null,new JLabel( "New", new ImageIcon(newImg), SwingConstants.LEFT)); } }