119 votes

Comment obtenir la hauteur et la largeur d'une image en utilisant java ?

Y a-t-il un autre moyen que d'utiliser ImageIO.read pour obtenir la hauteur et la largeur de l'image ?

Parce que je rencontre un problème qui bloque le fil de discussion.

at com.sun.medialib.codec.jpeg.Decoder.njpeg_decode(Native Method)      
at com.sun.medialib.codec.jpeg.Decoder.decode(Decoder.java:87)      
at com.sun.media.imageioimpl.plugins.jpeg.CLibJPEGImageReader.decode(CLibJPEGImageReader.java:73)     
 - locked <0xd96fb668> (a com.sun.media.imageioimpl.plugins.jpeg.CLibJPEGImageReader)      
at com.sun.media.imageioimpl.plugins.clib.CLibImageReader.getImage(CLibImageReader.java:320)    
 - locked <0xd96fb668> (a com.sun.media.imageioimpl.plugins.jpeg.CLibJPEGImageReader)     
 at com.sun.media.imageioimpl.plugins.clib.CLibImageReader.read(CLibImageReader.java:384)   
 - locked <0xd96fb668> (a com.sun.media.imageioimpl.plugins.jpeg.CLibJPEGImageReader)      
at javax.imageio.ImageIO.read(ImageIO.java:1400)      
at javax.imageio.ImageIO.read(ImageIO.java:1322)

Cette erreur ne se produit que sur un serveur d'applications Sun et je soupçonne donc qu'il s'agit d'un bogue Sun.

315voto

Apurv Points 1333

Voici quelque chose de très simple et pratique.

BufferedImage bimg = ImageIO.read(new File(filename));
int width          = bimg.getWidth();
int height         = bimg.getHeight();

82voto

Andrew Taylor Points 323

Il s'agit d'une réécriture de l'excellent article de @Kay, qui lève l'exception IOException et fournit une sortie précoce :

/**
 * Gets image dimensions for given file 
 * @param imgFile image file
 * @return dimensions of image
 * @throws IOException if the file is not a known image
 */
public static Dimension getImageDimension(File imgFile) throws IOException {
  int pos = imgFile.getName().lastIndexOf(".");
  if (pos == -1)
    throw new IOException("No extension for file: " + imgFile.getAbsolutePath());
  String suffix = imgFile.getName().substring(pos + 1);
  Iterator<ImageReader> iter = ImageIO.getImageReadersBySuffix(suffix);
  while(iter.hasNext()) {
    ImageReader reader = iter.next();
    try {
      ImageInputStream stream = new FileImageInputStream(imgFile);
      reader.setInput(stream);
      int width = reader.getWidth(reader.getMinIndex());
      int height = reader.getHeight(reader.getMinIndex());
      return new Dimension(width, height);
    } catch (IOException e) {
      log.warn("Error reading: " + imgFile.getAbsolutePath(), e);
    } finally {
      reader.dispose();
    }
  }

  throw new IOException("Not a known image file: " + imgFile.getAbsolutePath());
}

Je suppose que ma réputation n'est pas assez élevée pour que ma contribution soit considérée comme digne d'une réponse.

56voto

user194715 Points 656

J'ai essayé de tester les performances en utilisant certaines des différentes approches énumérées. Il est difficile de faire un test rigoureux car de nombreux facteurs affectent le résultat. J'ai préparé deux dossiers, un avec 330 fichiers jpg et un autre avec 330 fichiers png. La taille moyenne des fichiers était de 4Mb dans les deux cas. J'ai ensuite appelé getDimension pour chaque fichier. Chaque implémentation de la méthode getDimension et chaque type d'image ont été testés séparément (run séparé). Voici les temps d'exécution que j'ai obtenus (premier chiffre pour jpg, deuxième chiffre pour png) :

1(Apurv) - 101454ms, 84611ms
2(joinJpegs) - 471ms, N/A
3(Andrew Taylor) - 707ms, 68ms
4(Karussell, ImageIcon) - 106655ms, 100898ms
5(user350756) - 2649ms, 68ms

Il est évident que certaines méthodes chargent le fichier entier afin d'obtenir les dimensions, tandis que d'autres se contentent de lire les informations d'en-tête de l'image. Je pense que ces chiffres peuvent être utiles lorsque les performances de l'application sont critiques.

Merci à tous pour votre contribution à ce fil de discussion - très utile.

53voto

user350756 Points 199

J'ai trouvé une autre façon de lire la taille d'une image (plus générique). Vous pouvez utiliser la classe ImageIO en coopération avec les ImageReaders. Voici l'exemple de code :

private Dimension getImageDim(final String path) {
    Dimension result = null;
    String suffix = this.getFileSuffix(path);
    Iterator<ImageReader> iter = ImageIO.getImageReadersBySuffix(suffix);
    if (iter.hasNext()) {
        ImageReader reader = iter.next();
        try {
            ImageInputStream stream = new FileImageInputStream(new File(path));
            reader.setInput(stream);
            int width = reader.getWidth(reader.getMinIndex());
            int height = reader.getHeight(reader.getMinIndex());
            result = new Dimension(width, height);
        } catch (IOException e) {
            log(e.getMessage());
        } finally {
            reader.dispose();
        }
    } else {
        log("No reader found for given format: " + suffix));
    }
    return result;
}

Notez que getFileSuffix est une méthode qui renvoie l'extension du chemin sans ".", par exemple : png, jpg etc. Exemple d'implémentation :

private String getFileSuffix(final String path) {
    String result = null;
    if (path != null) {
        result = "";
        if (path.lastIndexOf('.') != -1) {
            result = path.substring(path.lastIndexOf('.'));
            if (result.startsWith(".")) {
                result = result.substring(1);
            }
        }
    }
    return result;
}

Cette solution est très rapide car seule la taille de l'image est lue dans le fichier et non l'image entière. Je l'ai testé et il n'y a aucune comparaison avec les performances de ImageIO.read. J'espère que quelqu'un trouvera cette solution utile.

18voto

joinJpegs Points 487

Vous pouvez charger des données binaires jpeg dans un fichier et analyser vous-même les en-têtes jpeg. Celui que vous recherchez est le 0xFFC0 ou l'en-tête Start of Frame :

Start of frame marker (FFC0)

* the first two bytes, the length, after the marker indicate the number of bytes, including the two length bytes, that this header contains
* P -- one byte: sample precision in bits (usually 8, for baseline JPEG)
* Y -- two bytes
* X -- two bytes
* Nf -- one byte: the number of components in the image
      o 3 for color baseline JPEG images
      o 1 for grayscale baseline JPEG images

* Nf times:
      o Component ID -- one byte
      o H and V sampling factors -- one byte: H is first four bits and V is second four bits
      o Quantization table number-- one byte

The H and V sampling factors dictate the final size of the component they are associated with. For instance, the color space defaults to YCbCr and the H and V sampling factors for each component, Y, Cb, and Cr, default to 2, 1, and 1, respectively (2 for both H and V of the Y component, etc.) in the Jpeg-6a library by the Independent Jpeg Group. While this does mean that the Y component will be twice the size of the other two components--giving it a higher resolution, the lower resolution components are quartered in size during compression in order to achieve this difference. Thus, the Cb and Cr components must be quadrupled in size during decompression.

Pour plus d'informations sur les en-têtes, consultez l'entrée jpeg de wikipedia ou j'ai obtenu les informations ci-dessus. aquí .

J'ai utilisé une méthode similaire au code ci-dessous que j'ai obtenu à partir de ce poste aux forums du soleil :

import java.awt.Dimension;
import java.io.*;

public class JPEGDim {

public static Dimension getJPEGDimension(File f) throws IOException {
    FileInputStream fis = new FileInputStream(f);

    // check for SOI marker
    if (fis.read() != 255 || fis.read() != 216)
        throw new RuntimeException("SOI (Start Of Image) marker 0xff 0xd8 missing");

    Dimension d = null;

    while (fis.read() == 255) {
        int marker = fis.read();
        int len = fis.read() << 8 | fis.read();

        if (marker == 192) {
            fis.skip(1);

            int height = fis.read() << 8 | fis.read();
            int width = fis.read() << 8 | fis.read();

            d = new Dimension(width, height);
            break;
        }

        fis.skip(len - 2);
    }

    fis.close();

    return d;
}

public static void main(String[] args) throws IOException {
    System.out.println(getJPEGDimension(new File(args[0])));
}

}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X