2011-11-22 7 views
8

Tengo un archivo de mapa de bits, test3.bmp, que puedo ver y editar con cada visor de imágenes con el que haya probado.¿Por qué ImageIO no lee un archivo BMP hasta que se vuelve a guardar en MS Paint?

Dicho esto, no puedo leerlo en mi aplicación Java. Si edito el BMP en MS Paint, lo guardo, deshago el cambio y lo guardo (test3_resaved.bmp), tengo la misma imagen, pero con un tamaño de archivo diferente. Los diferentes tamaños de archivo no me conciernen ... lo que hace, es que mi aplicación puede leer el archivo re-guardado.

¿Alguien podría aclararme por qué una imagen funciona con mi código pero la otra no?

Los archivos de imágenes:

Aquí es una aplicación de prueba mínima:

package Test; 

import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.image.BufferedImage; 
import java.io.File; 
import java.io.IOException; 

import javax.swing.ImageIcon; 
import javax.swing.JFrame; 

@SuppressWarnings("serial") 
public class Test extends JFrame { 
    private ImageIcon imageIcon; 

    public Test(String filename) throws IOException { 
     super(); 
     BufferedImage image = javax.imageio.ImageIO.read(new File(filename)); 
     imageIcon = new ImageIcon(image); 
     setVisible(true); 
     setDefaultCloseOperation(DISPOSE_ON_CLOSE); 
     repaint(); 
    } 

    public void paint(Graphics g) { 
     Graphics2D g2d = (Graphics2D) g; 
     setSize(imageIcon.getIconWidth(), imageIcon.getIconHeight()); 
     if (imageIcon != null) 
      g2d.drawImage(imageIcon.getImage(), 0, 0, this); 
    } 


    /** 
    * @param args 
    */ 
    public static void main(String[] args) { 
     try { 
      if (args.length > 0) 
       new Test(args[0]); 
      else 
       System.out.println("usage - specify image filename on command line"); 
     } 
     catch (Throwable t) { 
      t.printStackTrace(); 
     } 
    } 

} 
+2

hay un montón ** ** de diferentes tipos de archivos BMP. Probablemente, su * MS Paint * puede leer el formato original pero está usando otros encabezados/codificación BMP al guardar el archivo nuevamente. Sé con certeza que Java definitivamente no puede leer todos los diversos archivos BMP (pocos lectores de BMP pueden). Simplemente sucede que Java admite ese tipo particular de BMP que MS Paint produce. Por qué BMP? Si quieres sin pérdida, ¿sería PNG una opción? – TacticalCoder

+0

mismo problema aquí que "Roman B" ... Los enlaces para el archivo BMP no pueden funcionar. Podría hexdump los encabezados (el comienzo) de ambos archivos y agregar el resultado a su pregunta, pero a mí de todos modos el problema es precisamente lo que describí arriba: -/ – TacticalCoder

Respuesta

10

(ampliando mis comentarios)

El problema se reduce a esto: las personas suelen creer que el "formato" dado por el comando siguiente:

ImageIO.getReaderFileSuffixes(); 

están soportados por Java.

Pero esa no es la forma en que debe leerse y entenderse porque simplemente no es así como funciona.

incorrecto: "ImageIO puede leer cualquier archivo codificado con uno de estos formatos"

correcta: "ImageIO no puede leer la imagen codificada, con un formato que no es una de ellas formato"

Pero ahora, ¿qué dice eso de los formatos que aparecen en esa lista? Bueno ... Se pone complicado.

Por ejemplo, esa lista generalmente devuelve "PNG" y "BMP" (y otros formatos). Pero no hay "uno" PNG ni "uno" BMP. Puedo venir mañana con un formato PNG (sub) "válido" que estaría perfectamente bien, pero que ningún decodificador PNG podría decodificar (tendría que ser validado y aceptado: pero una vez que sea aceptado, se "romperá"). "todos los decodificadores PNG existentes por ahí). Afortunadamente, para las imágenes PNG el problema no es tan malo.

El formato BMP es muy complicado. Puede tener compresión o no (lo que puede explicar el tamaño variable del archivo que ha visto). Puede tener varios encabezados (de diferente duración, lo que también puede explicar el tamaño variable del archivo que ha visto). Diablos, BMP es realmente tan complejo que creo que puedes incrustar píxeles codificados PNG dentro de un "shell" BMP.

Hay básicamente dos tipos problemáticos de archivos BMP:

  • variantes BMP que aparecieron después de que el decodificador Java fue creado
  • variantes BMP que son lo suficientemente oscura para que los ejecutores de Java ImageIO no lo consideraban digno de apoyo

El "error" consiste en pensar que hay un formato PNG o uno BMP. Ambos formatos (y otros formatos de imagen también) son en realidad "extensibles". Cada vez que sale una nueva variante tiene el potencial de romper el cualquier decodificador.

Entonces, ¿qué está sucediendo en su caso es la siguiente:

  1. que está leyendo el archivo original BMP desde MS Paint y MS Paint es capaz de leer ese archivo, ya que pasa a ser un formato BMP que la EM Paint entiende.

  2. ese mismo formato BMP es ajeno a la versión de Java que está utilizando (existe la esperanza de que sea compatible con otra versión de Java, pero no contaría con ella).

  3. cuando se vuelva a guardar el archivo de MS Paint, que está ahorrando en un formato BMP que es, sin duda no el mismo que el formato original (variando el tamaño del archivo de ser bastante un decir)

  4. que otro formato es compatible con su versión de Java.

Ahora para realmente resolver su problema: en mi experiencia bibliotecas de imágenes, como ImageMagick son capaces de leer mucho más imágenes que el valor por defecto de Java API ImageIO por lo que le daría un vistazo a cualquiera de otras bibliotecas de imágenes o envolturas alrededor de ImageMagick.

Estas bibliotecas también suelen actualizarse para admitir nuevas variantes y formatos más nuevos mucho más rápido que Java. Por ejemplo, el increíble formato WebP de Google (hasta 28% a 34% mejor que PNG en imágenes sin pérdidas + translúcidas) ya es compatible con algunas bibliotecas de manipulación de imágenes, pero no estoy conteniendo la respiración cuando se trata de hacer una ImageIO.read (someWebPpicture) ...

Otra opción sería utilizar PNG: aunque en teoría el PNG puede ser extendido que es menos probable encontrar PNG "no admitidos" en la naturaleza. Con BMPs es muy común.

+0

Normalmente olvido mencionar que los formatos de imagen (y la mayoría de los sonidos) son 'formatos de contenedor' a menos que surja algo que subraye las diferencias entre las codificaciones. +1 para su explicación completa. –

0

Aquí hay un código de ejemplo http://www.java2s.com/Code/Java/2D-Graphics-GUI/ListAllreaderandwriterformatssupportedbyImageIO.htm que enumerará los formatos de imagen admitidos por su JDK.

BMP es compatible con el kit de herramientas de imágenes avanzadas http://www.oracle.com/technetwork/java/release-jai-imageio-1-0-01-140367.html, pero sé que también tiene elementos que ahora también son compatibles con el JDK base. Entonces, si es compatible con ambos, entonces tal vez el soporte de JAI sea más completo. Sin embargo, parece poco probable, ya que no tiene mucho sentido. OTOH, es era Dom.

Si está utilizando JDK 6, definitivamente puede hacer PNG (que es más portátil), ¿puede convertir sus imágenes? IIRC MS Paint guardará un png.

+1

"formatos" de imagen que se alega son compatibles con el lector * ImageIO * (s) son altamente engañosas, como se explica en mi respuesta larga:) Si BMP fue realmente compatible, el OP podría abrir su imagen con * ImageIO * del mismo modo que puede abrirlo desde MS Paint. Este no es el caso. – TacticalCoder

0

Probé las dos imágenes usando mi propio decodificador Java BMP. También descarga información de la imagen. Encontré que el original es un bmp de 32 bits y el uno re-salvado es uno de 24 bits. Así que supongo que imageio bmp reader no puede manejar 32 bit bmp correctamente.

Actualización: Para confirmar mi hipótesis hace mucho tiempo, probé la imagen de nuevo y sigue siendo problemática. El problema es que no se muestra ninguna imagen y la razón es que Java ImageIO cree que la imagen es completamente transparente. El siguiente es un volcado de Java creado ImageIO BufferedImage:

DirectColorModel: rmask=ff0000 gmask=ff00 bmask=ff amask=ff000000 
IntegerInterleavedRaster: width = 494 height = 516 #Bands = 4 xOff = 0 yOff = 0 
dataOffset[0] 0 
[email protected] 

Podemos ver aquí hay 4 bandas que representan RGBA como Java ImageIO lo interpretó. La verdad es que la cuarta banda o el cuarto byte no es para el canal alfa de una imagen BMP de Windows de 32 bits. Es simplemente basura o para hacer que sea de doble palabra alineada.

Un Windows 3.x BMP decodificador y mucho más de aquí https://github.com/dragon66/icafe

Cuestiones relacionadas