当前位置:  开发笔记 > 编程语言 > 正文

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

如何解决《如何使用java获取图像的高度和宽度?》经验,为你挑选了6个好方法。

除了使用ImageIO.read获取图像高度和宽度之外还有其他方法吗?

因为我遇到了锁定线程的问题.

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)

此错误仅发生在Sun应用服务器上,因此我怀疑它是Sun错误.



1> Apurv..:

这是非常简单和方便的东西.

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


从我正在阅读的所有内容中,它将整个图像读入内存.这对于获得宽度和高度来说是极端的.
坏方法:你需要将整个图像栅格加载到内存中,这会导致OOM具有非常大的图像
这是一个很长的路上最好的答案,并且在你的帖子发布后17天,你被别人发布的相同答案骗了.这应该是最好的答案而不是底部.
这是做到这一点的最糟糕的方式,我不明白为什么这个被如此重视.它将整个映像加载到堆中,这很慢并且消耗了大量不需要的内存.
这个问题特别要求使用其他方式*而不是使用ImageIO.read.你的答案是"使用ImageIO.read".为什么这被认为是一个好的答案?
这个问题最近改变了。理想情况下,此人应该问一个新问题。

2> Andrew Taylo..:

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

我想我的代表不够高,我的输入被认为是值得回复的.


另外,你不应该在返回之前在流上调用`.close()`吗?否则你打开流

3> 小智..:

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

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

请注意,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;
}

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


天啊,这是"基本上非常快"!我认为你有资格获得"低估年度奖".无论是在CPU时间还是在内存使用方面,都将`ImageIO.read()`彻底打败了.

4> mp31415..:

我尝试使用列出的各种方法测试性能.由于许多因素会影响结果,因此很难进行严格的测试.我准备了两个文件夹,一个包含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

很明显,有些方法会加载整个文件以获取尺寸,而其他方法只需从图像中读取一些标题信息即可.我认为当应用程序性能至关重要时,这些数字可能很有用.

谢谢大家对这个主题的贡献 - 非常有帮助.



5> joinJpegs..:

您可以将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.

有关标题的更多信息,请查看维基百科的jpeg条目,或者我在此处获得了上述信息.

我使用了类似于下面代码的方法,我在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> 小智..:

简单方法:

BufferedImage readImage = null;

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


这只需要知道宽度和高度,就需要在内存中读取整个图像.是的,它很简单,但对于许多图像或大图像都会表现不佳......
推荐阅读
小白也坚强_177
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有