Warum liest ImageIO keine BMP-Datei, bis sie in MS Paint erneut gespeichert wird?

8

Ich habe eine Bitmap-Datei, test3.bmp , die ich mit jedem Bildbetrachter anzeigen und bearbeiten kann, mit dem ich getestet habe.

Das heißt, ich kann es nicht in meine Java-Anwendung einlesen. Wenn ich das BMP in MS Paint bearbeite, es speichere, die Änderung rückgängig mache und es speichere ( test3_resaved.bmp ), habe ich das gleiche Bild, aber mit einer anderen Dateigröße. Die verschiedenen Dateigrößen betreffen mich nicht ... was bedeutet, dass meine Anwendung die neu gespeicherte Datei lesen kann.

Könnte mir jemand erklären, warum ein Bild mit meinem Code funktioniert, aber das andere nicht?

Bilddateien:

Hier ist eine minimale Testanwendung:

%Vor%     
Thomas Eding 22.11.2011, 00:41
quelle

3 Antworten

10

(erweitert auf meine Kommentare)

Das Problem läuft darauf hinaus: Leute glauben typischerweise, dass das "Format" durch den folgenden Befehl gegeben ist:

%Vor%

werden von Java unterstützt.

Aber so sollte es nicht gelesen / verstanden werden, denn so funktioniert es einfach nicht.

Falsch: "ImageIO kann jede Datei lesen, die mit einem dieser Formate codiert ist"

Richtig: "ImageIO kann kein Bild lesen, das mit einem Format codiert wurde, das nicht dieses Format hat"

Aber was sagt das über Formate, die in dieser Liste erscheinen? Nun ... Es wird schwierig.

Zum Beispiel gibt diese Liste normalerweise sowohl "PNG" als auch "BMP" (und andere Formate) zurück. Aber es gibt nicht "eine" PNG oder "eine" BMP. Ich kann morgen mit einem "gültigen" PNG (Sub) -Format kommen, das vollkommen in Ordnung wäre, aber dass kein einziger PNG-Decoder da draußen dekodieren würde (es müsste validiert und akzeptiert werden: aber sobald es akzeptiert würde, würde es "brechen") "alle vorhandenen PNG-Decoder da draußen). Glücklicherweise ist das Problem für die PNG-Bilder nicht allzu schlimm.

Das BMP-Format ist sehr kompliziert. Sie können eine Komprimierung haben oder nicht (was die unterschiedliche Dateigröße erklärt, die Sie gesehen haben). Sie können verschiedene Header (unterschiedlicher Länge) haben, die möglicherweise auch die unterschiedliche Dateigröße erklären, die Sie gesehen haben. Verdammt, BMP ist eigentlich so komplex, dass ich denke, dass man PNG-kodierte Pixel in eine BMP-Shell einbetten kann.

Es gibt grundsätzlich zwei problematische Arten von BMP-Dateien:

  • BMP-Varianten, die nach der Erstellung des Java-Dekoders erstellt wurden
  • BMP-Varianten, die so unklar sind, dass die Java ImageIO-Implementierer sie nicht als unterstützungswürdig erachten

Der "Fehler" besteht darin zu denken, dass es ein PNG- oder ein BMP-Format gibt. Beide Formate (und auch andere Bildformate) sind tatsächlich "erweiterbar". Immer wenn eine neue Variante herauskommt, hat sie das Potenzial, irgendeinen Decoder da draußen zu knacken.

Was in Ihrem Fall passiert, ist folgendes:

  1. Sie lesen Ihre ursprüngliche BMP-Datei von MS Paint und MS Paint kann diese Datei lesen, da es sich um ein BMP-Format handelt, das MS Paint versteht.

  2. das gleiche BMP-Format ist fremd in der Java-Version, die Sie verwenden (es gibt Hoffnung, dass es in einer anderen Java-Version unterstützt wird, aber ich würde nicht darauf zählen).

  3. Wenn Sie diese Datei aus MS Paint erneut speichern, speichern Sie in einem BMP-Format, das definitiv nicht ist, das gleiche wie das ursprüngliche Format (die variierende Dateigröße ist ziemlich groß erzählen)

  4. Dieses andere Format wird von Ihrer Java-Version unterstützt.

Nun, um Ihr Problem tatsächlich zu lösen: Nach meiner Erfahrung sind Bildbibliotheken wie ImageMagick in der Lage viel mehr Bilder zu lesen als die standardmäßige Java ImageIO API, so dass ich mir entweder andere Bildbibliotheken ansehen würde oder Wrapper um ImageMagick .

Diese Bibliotheken werden normalerweise aktualisiert, um neuere Varianten und neuere Formate viel schneller zu unterstützen als Java. Zum Beispiel das erstaunliche WebP Format von Google (bis zu 28% bis 34% besser als PNG bei verlustfreien + durchscheinenden Bildern) wird bereits von einigen Bildbearbeitungsbibliotheken unterstützt, aber ich halte nicht den Atem an Es kommt zu einem ImageIO.read (someWebPpicture) ...

Eine andere Option wäre die Verwendung von PNG: Obwohl theoretisch PNG erweitert werden kann, ist es weniger wahrscheinlich, dass Sie "nicht unterstützte" PNGs in freier Wildbahn finden. Mit BMPs ist es nur allzu üblich.

    
TacticalCoder 22.11.2011, 01:42
quelle
0

Es gibt hier einen Beispielcode Ссылка , mit dem unterstützte Bildformate aufgelistet werden dein JDK.

BMP wird vom erweiterten Bild-Toolkit unterstützt Ссылка Sun.

Wenn Sie JDK 6 verwenden, können Sie definitiv PNG (das ist portabler), können Sie Ihre Bilder konvertieren? IIRC MS Paint speichert ein Png.

    
Bill 22.11.2011 01:21
quelle
0

Ich habe die beiden Bilder mit meinem eigenen Java BMP-Decoder getestet. Es speichert auch einige Informationen des Bildes. Ich fand, dass das Original ein 32-Bit-BMP ist und das wiedergespeicherte ein 24-Bit-BMP ist. Ich nehme also an, dass der imageio bmp reader 32 Bit bmp nicht korrekt verarbeiten kann.

Update: Um meine lange Zeit zu raten, habe ich das Bild nochmal getestet und immer noch problematisch. Das Problem ist, dass kein Bild angezeigt wird und der Grund dafür ist, dass Java ImageIO das Bild als vollständig transparent ansieht. Folgendes ist ein Speicherauszug von Java ImageIO erstellt BufferedImage:

%Vor%

Wir können hier sehen, dass es 4 Bänder gibt, die RGBA darstellen, wie Java ImageIO es interpretierte. Die Wahrheit ist das vierte Band oder das vierte Byte ist nicht für Alpha-Kanal für ein 32-Bit-Windows-BMP-Bild. Es ist einfach Müll oder um es doppelt ausgerichtet zu machen.

Ein Windows 3.x BMP-Decoder und noch viel mehr von hier Ссылка

    
dragon66 15.03.2012 15:06
quelle

Tags und Links