IT

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

lottoking 2020. 8. 22. 10:02
반응형

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


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 항목을 확인하거나 여기에 위의 정보를 얻었습니다 .

나는 태양 포럼 의이 게시물 에서 얻은 아래 코드와 방법을 사용했습니다 .

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


툴킷을 사용할 수 있으며 ImageIO가 필요하지 않습니다.

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

이미지 로딩을 처리하고 싶지 않다면

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

ImageIO.read로 버퍼링 된 이미지를 얻는 것은 메모리에 이미지의 완전한 비 압축 사본을 생성하기 때문에 매우 무거운 방법입니다. png의 경우 pngj 및 코드를 사용할 수도 있습니다.

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

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

그래서 안타깝게도 위의 모든 답변을 시도한 후에도 지칠 줄 모르는 노력 끝에 그들을 작동시키지 못했습니다. 그래서 진짜 해킹을하기로 결심했고이 작업을 수행했습니다. 나는 그것이 당신에게도 완벽하게 작동 할 것이라고 믿습니다.

이 간단한 방법을 사용하여 앱에서 생성 한 이미지의 너비를 가져 오지만 나중에 확인을 위해 업로드하지 않습니다.

Pls. 참고 : 액세스 저장소에 대한 매니페스트의 권한을 활성화해야합니다.

/ 정적으로 만들고 Global 클래스에 넣어서 하나의 소스에서 참조하거나 액세스 할 수 있으며 수정이 있으면 모두 한곳에서 수행해야합니다. Java에서 DRY 개념을 유지하고 있습니다. (어쨌든) :) /

public static int getImageWidthOrHeight(String imgFilePath) {

            Log.d("img path : "+imgFilePath);

            // Decode image size
            BitmapFactory.Options o = new BitmapFactory.Options();
            o.inJustDecodeBounds = true;
            BitmapFactory.decodeFile(imgFilePath, o);

            int width_tmp = o.outWidth, height_tmp = o.outHeight;

            Log.d("Image width : ", Integer.toString(width_tmp) );

            //you can decide to rather return height_tmp to get the height.

            return width_tmp;

}


EMF Image Reader없이 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);
}

참고 URL : https://stackoverflow.com/questions/672916/how-to-get-image-height-and-width-using-java

반응형