Как получить высоту и ширину изображения с помощью 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.

Ответ 1

Вот что-то очень простое и удобное.

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

Ответ 2

Это переписывание большого сообщения @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());
}

Я думаю, что мой репутатор недостаточно высок, чтобы мой вклад считался достойным ответа.

Ответ 3

Я нашел другой способ прочитать размер изображения (более общий). Вы можете использовать ImageIO класс совместно с ImageReaders. Вот пример кода:

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. Надеюсь, кто-то найдет это полезным.

Ответ 4

Я попытался проверить производительность, используя некоторые из перечисленных подходов. Трудно сделать строгий тест, так как на результат влияет множество факторов. Я подготовил две папки: одну с 330 файлами jpg и еще одну с 330 png файлами. В обоих случаях средний размер файла составлял 4 Мб. Затем я вызывал 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

Вы можете загружать двоичные данные jpeg в виде файла и самостоятельно анализировать заголовки jpeg. Тот, который вы ищете, это заголовок 0xFFC0 или 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.

Для получения дополнительной информации о заголовках проверьте запись в 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])));
}

}

Ответ 7

Простой способ:

BufferedImage readImage = null;

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

Ответ 9

Проблема с 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)"

Производительность была такой же, как при использовании Java-библиотеки SimpleImageInfo.

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

Ответ 10

Вы можете использовать Toolkit, нет необходимости в 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();

Ответ 11

Чтобы получить буферное изображение с ImageIO.read, это очень тяжелый метод, так как он создает полную несжатую копию изображения в памяти. Для png вы также можете использовать pngj и код:

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

Ответ 12

Вы можете получить ширину и высоту изображения с помощью объекта BufferedImage с помощью 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();
    }

Ответ 13

К сожалению, после того, как я попробовал все ответы сверху, я не заставил их работать после неустанного времени попыток. Поэтому я решил сделать настоящий взлом сам, и я работаю на меня. Я верю, что это сработало бы и для вас.

Я использую этот простой метод, чтобы получить ширину изображения, сгенерированного приложением, и еще не загружен для проверки:

Pls. обратите внимание: вам необходимо включить разрешения в манифесте для хранилища доступа.

/Я сделал его статическим и поместил в свой класс Global, чтобы я мог ссылаться на него или получать к нему доступ только из одного источника, и, если есть какие-либо изменения, все это должно быть сделано в одном месте. Просто поддержание СУХОЙ концепции в Java. (в любом случае):)/

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;

}

Ответ 14

Чтобы получить размер файла emf без EMF Image Reader, вы можете использовать код:

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