Come ottenere l’altezza e la larghezza dell’immagine usando java?

C’è altro modo oltre all’utilizzo di ImageIO.read per ottenere altezza e larghezza dell’immagine?

Perché ho riscontrato un problema che blocca il thread.

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  (a com.sun.media.imageioimpl.plugins.jpeg.CLibJPEGImageReader) at com.sun.media.imageioimpl.plugins.clib.CLibImageReader.getImage(CLibImageReader.java:320) - locked  (a com.sun.media.imageioimpl.plugins.jpeg.CLibJPEGImageReader) at com.sun.media.imageioimpl.plugins.clib.CLibImageReader.read(CLibImageReader.java:384) - locked  (a com.sun.media.imageioimpl.plugins.jpeg.CLibJPEGImageReader) at javax.imageio.ImageIO.read(ImageIO.java:1400) at javax.imageio.ImageIO.read(ImageIO.java:1322) 

Questo errore si verifica solo su un server Sun App e quindi sospetto che si tratti di un bug di Sun.

Ecco qualcosa di molto semplice e maneggevole.

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

Questa è una riscrittura del grande post di @Kay, che genera IOException e fornisce un’uscita anticipata:

 /** * 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 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()); } 

Immagino che il mio rappresentante non sia abbastanza alto da poter considerare il mio intervento come degno di risposta.

Ho trovato un altro modo per leggere una dimensione dell’immagine (più generica). È ansible utilizzare la class ImageIO in collaborazione con ImageReaders. Ecco il codice di esempio:

 private Dimension getImageDim(final String path) { Dimension result = null; String suffix = this.getFileSuffix(path); Iterator 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; } 

Nota che getFileSuffix è un metodo che restituisce l’estensione del percorso senza “.” quindi ad esempio: png, jpg ecc. L’implementazione di esempio è:

 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; } 

Questa soluzione è molto veloce in quanto viene letta solo la dimensione dell’immagine dal file e non l’intera immagine. L’ho provato e non c’è paragone con le prestazioni di ImageIO.read. Spero che qualcuno lo troverà utile.

Ho provato a testare le prestazioni utilizzando alcuni dei vari approcci elencati. È difficile fare un test rigoroso in quanto molti fattori influenzano il risultato. Ho preparato due cartelle, una con 330 file jpg e un’altra con 330 file png. In entrambi i casi la dimensione media del file era di 4 Mb. Quindi ho chiamato getDimension per ogni file. Ogni implementazione del metodo getDimension e ogni tipo di immagine è stata testata separatamente (esecuzione separata). Ecco i tempi di esecuzione che ho ottenuto (primo numero per jpg, secondo numero per png):

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

È ovvio che alcuni metodi caricano l’intero file per ottenere dimensioni mentre altri ottengono solo leggendo alcune informazioni di intestazione dall’immagine. Penso che questi numeri possano essere utili quando le prestazioni dell’applicazione sono critiche.

Grazie a tutti per il contributo a questa discussione – molto utile.

È ansible caricare i dati binari jpeg come file e analizzare autonomamente le intestazioni jpeg. Quello che stai cercando è l’0xFFC0 o l’intestazione 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. 

Per maggiori informazioni sulle intestazioni controlla la voce jpeg di wikipedia o ho ottenuto le informazioni qui sopra.

Ho usato un metodo simile al codice qui sotto che ho ottenuto da questo post nei forum di Sun:

 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]))); } 

}

Ho trovato questa class gratuita, funziona perfettamente:

http://jaimonmathew.wordpress.com/2011/01/29/simpleimageinfo/

Modo semplice:

 BufferedImage readImage = null; try { readImage = ImageIO.read(new File(your path); int h = readImage.getHeight(); int w = readImage.getWidth(); } catch (Exception e) { readImage = null; } 

Prova ad usare la class ImageInfo disponibile gratuitamente, l’ho usata per lo stesso scopo:

http://linux.softpedia.com/get/Multimedia/Graphics/ImageInfo-19792.shtml

Potresti usare il Toolkit, senza bisogno di ImageIO

 Image image = Toolkit.getDefaultToolkit().getImage(file.getAbsolutePath()); int width = image.getWidth(null); int height = image.getHeight(null); 

Se non vuoi gestire il caricamento dell’immagine fallo

 ImageIcon imageIcon = new ImageIcon(file.getAbsolutePath()); int height = imageIcon.getIconHeight(); int width = imageIcon.getIconWidth(); 

Per ottenere un’immagine con buffer con ImageIO.read è un metodo molto pesante, in quanto sta creando una copia non compressa completa dell’immagine in memoria. Per png puoi anche usare pngj e il codice:

 if (png) PngReader pngr = new PngReader(file); width = pngr.imgInfo.cols; height = pngr.imgInfo.rows; pngr.close(); } 

Puoi ottenere larghezza e altezza dell’immagine con l’object BufferedImage usando java.

 public void setWidthAndHeightImage(FileUploadEvent event){ byte[] imageTest = event.getFile().getContents(); baiStream = new ByteArrayInputStream(imageTest ); BufferedImage bi = ImageIO.read(baiStream); //get width and height of image int imageWidth = bi.getWidth(); int imageHeight = bi.getHeight(); } 

Il problema con ImageIO.read è che è molto lento. Tutto quello che devi fare è leggere l’intestazione dell’immagine per ottenere la dimensione. ImageIO.getImageReader è un candidato perfetto.

Ecco l’esempio di Groovy, ma la stessa cosa vale per Java

 def stream = ImageIO.createImageInputStream(new ByteArrayInputStream(inputStream)) def reader = ImageIO.getImageReader(getReaderByFormat(format)) reader.setInput(stream, true) println "width:reader.getWidth(0) -> height: reader.getHeight(0)" 

Le prestazioni erano le stesse dell’utilizzo della libreria java di SimpleImageInfo.

https://github.com/cbeust/personal/blob/master/src/main/java/com/beust/SimpleImageInfo.java

Per ottenere la dimensione del file emf senza EMF Image Reader puoi usare il codice:

 Dimension getImageDimForEmf(final String path) throws IOException { ImageInputStream inputStream = new FileImageInputStream(new File(path)); inputStream.setByteOrder(ByteOrder.LITTLE_ENDIAN); // Skip magic number and file size inputStream.skipBytes(6*4); int left = inputStream.readInt(); int top = inputStream.readInt(); int right = inputStream.readInt(); int bottom = inputStream.readInt(); // Skip other headers inputStream.skipBytes(30); int deviceSizeInPixelX = inputStream.readInt(); int deviceSizeInPixelY = inputStream.readInt(); int deviceSizeInMlmX = inputStream.readInt(); int deviceSizeInMlmY = inputStream.readInt(); int widthInPixel = (int) Math.round(0.5 + ((right - left + 1.0) * deviceSizeInPixelX / deviceSizeInMlmX) / 100.0); int heightInPixel = (int) Math.round(0.5 + ((bottom-top + 1.0) * deviceSizeInPixelY / deviceSizeInMlmY) / 100.0); inputStream.close(); return new Dimension(widthInPixel, heightInPixel); }