[java] 자바를 사용하여 이미지 높이와 너비를 얻는 방법은 무엇입니까?

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 버그로 의심됩니다.



답변

여기에 매우 간단하고 편리한 것이 있습니다.

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


답변

이것은 IOException을 발생시키고 조기 종료를 제공하는 @Kay의 훌륭한 게시물을 재 작성한 것입니다.

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

내 담당자가 내 의견이 답장으로 간주 될만큼 충분히 높지 않은 것 같습니다.


답변

이미지 크기를 읽는 다른 방법을 찾았습니다 (더 일반적인). ImageReaders와 협력하여 ImageIO 클래스를 사용할 수 있습니다. 다음은 샘플 코드입니다.

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

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 성능과 비교할 수 없습니다. 누군가 이것이 유용하다고 생각하기를 바랍니다.


답변

나열된 다양한 접근 방식 중 일부를 사용하여 성능을 테스트하려고했습니다. 많은 요인이 결과에 영향을 미치기 때문에 엄격한 테스트를하는 것은 어렵습니다. 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

일부 메서드는 크기를 얻기 위해 전체 파일을로드하는 반면 다른 메서드는 이미지에서 일부 헤더 정보를 읽어서 가져 오는 것이 분명합니다. 이 수치는 애플리케이션 성능이 중요 할 때 유용 할 수 있다고 생각합니다.

이 스레드에 기여 해주신 모든 분들께 감사드립니다. 매우 유용합니다.


답변

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.

헤더에 대한 자세한 내용은 wikipedia의 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])));
}

}


답변

간단한 방법 :

BufferedImage readImage = null;

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


답변

ImageIO.read의 문제는 정말 느리다는 것입니다. 당신이 할 일은 크기를 얻기 위해 이미지 헤더를 읽는 것입니다. ImageIO.getImageReader완벽한 후보입니다.

다음은 Groovy 예제이지만 Java에도 동일한 사항이 적용됩니다.

def stream = ImageIO.createImageInputStream(newByteArrayInputStream(inputStream))
def formatReader = ImageIO.getImageWritersByFormatName(format).next()
def reader = ImageIO.getImageReader(formatReader)
reader.setInput(stream, true)

println "width:reader.getWidth(0) -> height: reader.getHeight(0)"

성능은 SimpleImageInfo Java 라이브러리를 사용하는 것과 동일합니다.

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