如何使用java获取图像的高度和宽度?

时间:2022-11-19 13:34:23

Is there any other way besides using ImageIO.read to get image height and width?

除了使用ImageIO还有其他方法吗?读取以获取图像的高度和宽度?

Because I encounter an issue that locks up the 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 <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)

This error only occurs on a Sun app server and therefore I suspect that it is a Sun bug.

这个错误只发生在Sun应用服务器上,因此我怀疑它是Sun bug。

12 个解决方案

#1


236  

Here is something very simple and handy.

这里有一些非常简单和方便的东西。

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

#2


45  

This is a rewrite of the great post by @Kay, which throws IOException and provides an early exit:

这是对@Kay的文章的重写,它抛出IOException并提供了一个早期退出:

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

I guess my rep is not high enough for my input to be considered worthy as a reply.

我想我的代表还不够高,不足以让我的投入被认为有价值。

#3


39  

I have found another way to read an image size (more generic). You can use ImageIO class in cooperation with ImageReaders. Here is the sample code:

我找到了另一种读取图像大小(更通用)的方法。您可以使用ImageIO类与imagereader合作。下面是示例代码:

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

Note that getFileSuffix is method that returns extension of path without "." so e.g.: png, jpg etc. Example implementation is:

注意getFileSuffix是返回路径扩展而不带“.”的方法,例如:png、jpg等。

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

This solution is very quick as only image size is read from the file and not the whole image. I tested it and there is no comparison to ImageIO.read performance. I hope someone will find this useful.

这个解决方案非常快速,因为只有图像大小从文件中读取,而不是整个图像。我测试了它,没有与ImageIO进行比较。读性能。我希望有人会觉得这有用。

#4


29  

I tried to test performance using some of the various approaches listed. It's hard to make a rigorous test as many factors affect the result. I prepared two folders, one with 330 jpg files and another one with 330 png files. The average file size was 4Mb in both cases. Then I called getDimension for each file. Each implementation of getDimension method and each image type was tested separately (separate run). Here is the execution times that I got (first number for jpg, second number for png):

我尝试使用列出的一些方法来测试性能。由于影响结果的因素很多,很难进行严格的测试。我准备了两个文件夹,一个是330个jpg文件,另一个是330个png文件。在这两种情况下,平均文件大小为4Mb。然后我为每个文件调用getDimension。getDimension方法的每个实现和每个图像类型都分别进行测试(单独运行)。这是我得到的执行时间(jpg的第一个数字,png的第二个数字):

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

It's obvious that some methods load the whole file in order to get dimensions while others get by just reading some header information from the image. I think these numbers may be useful when application performance is critical.

显然,有些方法加载整个文件是为了获取维度,而另一些方法则只是从图像中读取一些头信息。我认为当应用程序性能非常重要时,这些数字可能是有用的。

Thank you everyone for the contribution to this thread - very helpful.

谢谢大家对这篇文章的贡献——非常有帮助。

#5


11  

You can load jpeg binary data as a file and parse the jpeg headers yourself. The one you are looking for is the 0xFFC0 or Start of Frame header:

您可以将jpeg二进制数据作为文件加载并自己解析jpeg头。您要查找的是0xFFC0或帧头的开始:

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.

For more info about the headers check out wikipedia's jpeg entry or I got the above info here.

有关标题的更多信息,请查看*的jpeg条目,或者我在这里得到上面的信息。

I used a method similar to the code below which I got from this post at the sun forums:

我使用了一种类似于下面代码的方法,这是我在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])));
}

}

}

#6


10  

I found this free class, work perfectly:

我找到了这个免费的课程,效果很好:

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

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

#7


8  

Simple way:

简单的方法:

BufferedImage readImage = null;

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

#8


3  

Try using the ImageInfo freely available class, I've used it for the same purpose:

尝试使用免费提供的ImageInfo类,我已经将它用于相同的目的:

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

http://linux.softpedia.com/get/multimedia/graphics/imageinfo - 19792. shtml

#9


3  

You could use the Toolkit, no need for ImageIO

您可以使用工具包,不需要ImageIO

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

If you don't want to handle the loading of the image do

如果您不想处理图像的加载,请执行

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

#10


1  

To get a Buffered Image with ImageIO.read is a very heavy method, as it's creating a complete uncompressed copy of the image in memory. For png's you may also use pngj and the code:

用ImageIO得到一个缓冲的图像。read是一个非常重的方法,因为它正在内存中创建一个完整的未压缩的映像副本。对于png,你也可以使用pngj和代码:

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

#11


1  

You can get width and height of image with BufferedImage object using java.

您可以通过使用java的BufferedImage对象获得图像的宽度和高度。

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

#12


-2  

To get size of emf file without EMF Image Reader you can use code:

要获得没有emf图像阅读器的emf文件的大小,可以使用代码:

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

#1


236  

Here is something very simple and handy.

这里有一些非常简单和方便的东西。

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

#2


45  

This is a rewrite of the great post by @Kay, which throws IOException and provides an early exit:

这是对@Kay的文章的重写,它抛出IOException并提供了一个早期退出:

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

I guess my rep is not high enough for my input to be considered worthy as a reply.

我想我的代表还不够高,不足以让我的投入被认为有价值。

#3


39  

I have found another way to read an image size (more generic). You can use ImageIO class in cooperation with ImageReaders. Here is the sample code:

我找到了另一种读取图像大小(更通用)的方法。您可以使用ImageIO类与imagereader合作。下面是示例代码:

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

Note that getFileSuffix is method that returns extension of path without "." so e.g.: png, jpg etc. Example implementation is:

注意getFileSuffix是返回路径扩展而不带“.”的方法,例如:png、jpg等。

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

This solution is very quick as only image size is read from the file and not the whole image. I tested it and there is no comparison to ImageIO.read performance. I hope someone will find this useful.

这个解决方案非常快速,因为只有图像大小从文件中读取,而不是整个图像。我测试了它,没有与ImageIO进行比较。读性能。我希望有人会觉得这有用。

#4


29  

I tried to test performance using some of the various approaches listed. It's hard to make a rigorous test as many factors affect the result. I prepared two folders, one with 330 jpg files and another one with 330 png files. The average file size was 4Mb in both cases. Then I called getDimension for each file. Each implementation of getDimension method and each image type was tested separately (separate run). Here is the execution times that I got (first number for jpg, second number for png):

我尝试使用列出的一些方法来测试性能。由于影响结果的因素很多,很难进行严格的测试。我准备了两个文件夹,一个是330个jpg文件,另一个是330个png文件。在这两种情况下,平均文件大小为4Mb。然后我为每个文件调用getDimension。getDimension方法的每个实现和每个图像类型都分别进行测试(单独运行)。这是我得到的执行时间(jpg的第一个数字,png的第二个数字):

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

It's obvious that some methods load the whole file in order to get dimensions while others get by just reading some header information from the image. I think these numbers may be useful when application performance is critical.

显然,有些方法加载整个文件是为了获取维度,而另一些方法则只是从图像中读取一些头信息。我认为当应用程序性能非常重要时,这些数字可能是有用的。

Thank you everyone for the contribution to this thread - very helpful.

谢谢大家对这篇文章的贡献——非常有帮助。

#5


11  

You can load jpeg binary data as a file and parse the jpeg headers yourself. The one you are looking for is the 0xFFC0 or Start of Frame header:

您可以将jpeg二进制数据作为文件加载并自己解析jpeg头。您要查找的是0xFFC0或帧头的开始:

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.

For more info about the headers check out wikipedia's jpeg entry or I got the above info here.

有关标题的更多信息,请查看*的jpeg条目,或者我在这里得到上面的信息。

I used a method similar to the code below which I got from this post at the sun forums:

我使用了一种类似于下面代码的方法,这是我在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])));
}

}

}

#6


10  

I found this free class, work perfectly:

我找到了这个免费的课程,效果很好:

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

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

#7


8  

Simple way:

简单的方法:

BufferedImage readImage = null;

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

#8


3  

Try using the ImageInfo freely available class, I've used it for the same purpose:

尝试使用免费提供的ImageInfo类,我已经将它用于相同的目的:

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

http://linux.softpedia.com/get/multimedia/graphics/imageinfo - 19792. shtml

#9


3  

You could use the Toolkit, no need for ImageIO

您可以使用工具包,不需要ImageIO

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

If you don't want to handle the loading of the image do

如果您不想处理图像的加载,请执行

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

#10


1  

To get a Buffered Image with ImageIO.read is a very heavy method, as it's creating a complete uncompressed copy of the image in memory. For png's you may also use pngj and the code:

用ImageIO得到一个缓冲的图像。read是一个非常重的方法,因为它正在内存中创建一个完整的未压缩的映像副本。对于png,你也可以使用pngj和代码:

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

#11


1  

You can get width and height of image with BufferedImage object using java.

您可以通过使用java的BufferedImage对象获得图像的宽度和高度。

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

#12


-2  

To get size of emf file without EMF Image Reader you can use code:

要获得没有emf图像阅读器的emf文件的大小,可以使用代码:

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