34 Stimmen

JPEG-Bild mit falschen Farben

Ich habe eine Methode, die Bilder liest, sie konvertiert (Größe, Format) und zurückschreibt. Das hat immer sehr gut funktioniert, aber jetzt bin ich auf einige JPEG-Bilder gestoßen (von einer Presseagentur), die offensichtlich einige Metadaten (IPTC) enthalten. Bei der Konvertierung dieser Bilder sind die Farben völlig falsch. Meine erste Vermutung war, dass es sich um CMYK-Bilder handelt, aber das ist nicht der Fall.

Das Problem muss beim Lesen liegen, denn egal, ob ich das Bild in ein kleineres JPEG oder ein PNG konvertiere, es sieht immer gleich aus.

Am Anfang habe ich ImageIO.read() um das Bild zu lesen. Ich erhalte jetzt die aktuelle ImageReader vía ImageIO.getImageReadersByMIMEType() und versucht, dem Leser mitzuteilen, dass er Metadaten ignorieren soll, indem er die ignoreMetadata Parameter von ImageReader#setInput(Object input, boolean seekForwardOnly, boolean ignoreMetadata) hatte aber keinen Erfolg.

Dann habe ich eine Version des Bildes ohne die Metadaten erstellt (mit Fireworks). Dieses Bild wurde korrekt konvertiert.

Der einzige Unterschied, den ich feststellen konnte, ist, dass bei dem nicht funktionierenden Bild der Wert der Variablen des Lesers colorSpaceCode es 2 , während beim Arbeitsbild der Wert 3 . Außerdem gibt es eine outColorSpaceCode das ist 2 für beide Bilder.

Da die Quelle: Kommentar des Lesers sagt nur Wird durch den nativen Code-Callback setImageData gesetzt. Ein geänderter IJG+NIFTY-Farbraum-Code Ich stecke jetzt wirklich fest. Jede Hilfe wäre also sehr willkommen.

Sie können das Originalbild (~3 MB) über folgende Adresse abrufen aquí und klicken Sie auf Herunterladen. Das linke Bild unten zeigt, was ich vom Originalbild erhalte, das rechte zeigt, wie es aussehen sollte.

wrong colors correct colors (after removing metadata)

10voto

Ridcully Punkte 23073

Ich habe jetzt eine Lösung gefunden, die funktioniert, zumindest, wenn das resultierende Bild auch ein JPEG ist: Zuerst lese ich das Bild (aus dem Byte-Array imageData), und vor allem lese ich auch die Metadaten.

InputStream is = new BufferedInputStream(new ByteArrayInputStream(imageData));
Image src = null;
Iterator<ImageReader> 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);

Jetzt würde ich etwas konvertieren (d.h. verkleinern) ... und schließlich würde ich das Ergebnis als JPEG-Bild zurückschreiben. Hier ist es sehr wichtig, die Metadaten, die wir vom Originalbild erhalten haben, an das neue Bild zu übergeben IIOImage .

Iterator<ImageWriter> 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();

Wenn ich ein PNG-Bild schreibe, erhalte ich leider immer noch die falschen Farben (auch wenn ich die Metadaten weitergebe), aber damit kann ich leben.

4voto

ludovic Punkte 41

Ich hatte ein ähnliches Problem, das ich verwenden musste:

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

anstelle von

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

4voto

wbudic Punkte 65

Ich hatte ähnliche Probleme, die BufferedImage zurückgegeben wird, ist eine Wiedergabe, die darauf basiert, ob es transparente Pixel gibt, was bei den meisten Dateien des Typs png/gif der Fall sein wird. Bei der Konvertierung in jpeg sollte dieses Flag jedoch auf false gesetzt werden. Sie müssen möglicherweise eine Methode schreiben, bei der die Konvertierung ordnungsgemäß durchgeführt wird, d.h.:

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

Andernfalls wird dieser "maritime" Unterton zum gespeicherten Ergebnis. :)


4voto

James Fiala Punkte 301

Ich war in dieses Problem laufen, und ich fand tatsächlich eine Drittanbieter-Bibliothek, die dies für mich behandelt. https://github.com/haraldk/TwelveMonkeys

Alles, was ich tun musste, war, dies in meine Maven-Abhängigkeiten aufzunehmen, und die JPEGs, die in seltsamen Farben erschienen, wurden normal eingelesen. Ich musste nicht einmal eine Zeile des Codes ändern.

3voto

Kasun Punkte 31

Ich hatte ein ähnliches Problem, als ich versuchte, ein Bild aus einem Byte-Array in Base64 zu konvertieren. Es scheint, dass das Problem durch Bilder mit einem Alphakanal verursacht wird. Beim Speichern eines Bildes mit Alphakanal wird auch der Alphakanal gespeichert und einige externe Programme, die zum Lesen des Bildes verwendet werden, interpretieren die 4 Kanäle als CMYK.

Ich habe einen einfachen Workaround gefunden, indem ich den Alphakanal des BufferedImage entfernt habe. Dies kann dumm sein, aber es sicher für mich gearbeitet.

//Read the image from a byte array
BufferedImage bImage = ImageIO.read(new ByteArrayInputStream(byteArray));

//Get the height and width of the image
int width = bImage.getWidth();
int height = bImage.getHeight();

//Get the pixels of the image to an int array 
int [] pixels=bImage.getRGB(0, 0,width,height,null,0,width);

//Create a new buffered image without an alpha channel. (TYPE_INT_RGB)
BufferedImage copy = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);

//Set the pixels of the original image to the new image
copy.setRGB(0, 0,width,height,pixels,0,width);

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X