Быстрый способ получить размеры изображения (не размер файла)

138

Я ищу быстрый способ получить высоту и ширину изображения в пикселях. Он должен обрабатывать как минимум JPG, PNG и TIFF, но чем больше, тем лучше. Я подчеркиваю быстро, потому что мои изображения довольно большие (до 250 МБ), и требуется слишком много времени, чтобы получить размер с ImageMagick, identifyпотому что он, очевидно, сначала читает изображения в целом.

Предпочтительно, я ищу способ, который хорошо работает в Ruby или даже в Rails 3.

Я знаю теоретические вещи (различные форматы изображений, их заголовки и различия и т. Д.). Действительно, я прошу какую-то библиотеку, которая может решить мою проблему довольно общим способом.

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

Danjou
источник
8
Похоже, что это не так для новых версий ImageMagick. Используя ImageMagick 6.5.4-7, я подтвердил, что идентификатор (по крайней мере, для TIF и PNG) только читает заголовок (до 60 КБ) и работает очень быстро, даже для изображений 335 МБ.
coderforlife

Ответы:

195
  • Команда fileпечатает размеры для нескольких форматов изображений (например, PNG, GIF, JPEG; последние версии также PPM, WEBP) и читает только заголовок.

  • identifyКоманда (от ImageMagick) печатает много информации изображений для широкого спектра изображений. Кажется, что ограничивается чтением заголовка (см. Комментарии). У этого также есть унифицированный вывод, которого, к fileсожалению, не хватает.

  • exiv2дает вам размеры для многих форматов, включая JPEG, TIFF, PNG, GIF, WEBP, даже если заголовок EXIF ​​отсутствует. Неясно, читает ли он все данные для этого все же. Смотрите man-страницу exiv2 для всех поддерживаемых форматов изображений.

  • head -n1 даст вам размеры для форматов PPM, PGM.

Для форматов, популярных в Интернете, оба exiv2и identifyсделают свою работу. В зависимости от варианта использования вам может потребоваться написать собственный скрипт, который объединяет / анализирует выходные данные нескольких инструментов.

ypnos
источник
3
Я провел несколько тестов с командой ImageMagick identifier, используя strace для записи вызовов open / read / mmap / close, чтобы увидеть, сколько данных было прочитано с идентифицированного изображения. Это немного зависит от типа файла и размера файла, но я получал 20-60 КБ, считанные по «идентификатору» для изображений 5–335 МБ (я также проверял «конвертировать», который показывал все читаемые байты). Таким образом, похоже, что «идентификация» является хорошим выбором здесь (поскольку она поддерживает все популярные форматы и читает только заголовок).
coderforlife
1
Я думаю, что exiv2 также делает PNG.
CHX
Любые способы легко анализировать вывод файловых команд? Идентифицировать - это здорово, но, к сожалению, он не работает с файлами WebP
Брайан Лейшман,
Идентифицировать делает работу с WebP, и ImageMagick имеет поддержку WebP в течение многих лет. Может быть, вы могли бы получить обновление?
ypnos
32

Я не уверен, что у вас установлен php, но эта функция PHP очень удобна

 php -r "print_r(getimagesize('http://www.google.com/images/logos/ps_logo2.png'));"
ajreal
источник
1
Это намного быстрее, чем «идентифицировать». Хороший подход. Спасибо.
souravb
19

Вы можете использовать функцию идентификации ImageMagick . Вот как вы это делаете в bash (примечание: $ 0 - это путь к изображению):

width=$(identify -format "%w" "$0")> /dev/null
height=$(identify -format "%h" "$0")> /dev/null

И это также скрывает любые потенциальные сообщения об ошибках. Современные реализации identifyчитают только заголовок, а не все изображение, поэтому это быстро. Не уверен, как это по сравнению с другими методами, хотя.

Джеймс Л.
источник
2
Я считаю, что так гораздо эффективнее:read width height < <(identify -format "%w %h" "${1}")
Cromax
5

https://joseluisbz.wordpress.com/2013/08/06/obtainment-size-or-dimension-of-images/ (BMP, PNG, GIF, JPG, TIF или WMF)

Здесь для двух форматов PNG и JPG.

Мой код из класса, предназначенного для моего использования, вы можете редактировать в соответствии с вашими потребностями.

Пожалуйста, проверьте эти функции / метод, используя PHP :

  public function ByteStreamImageString($ByteStream,&$Formato,&$Alto,&$Ancho) {
    $Alto = 0;
    $Ancho = 0;
    $Formato = -1;
    $this->HexImageString = "Error";
    if (ord($ByteStream[0])==137 && ord($ByteStream[1])==80 && ord($ByteStream[2])==78){
      $Formato = 1; //PNG
      $Alto = $this->Byte2PosInt($ByteStream[22],$ByteStream[23]);
      $Ancho = $this->Byte2PosInt($ByteStream[18],$ByteStream[19]);
    }
    if (ord($ByteStream[0])==255 && ord($ByteStream[1])==216
        && ord($ByteStream[2])==255 && ord($ByteStream[3])==224){
      $Formato = 2; //JPG
      $PosJPG = 2;
      while ($PosJPG<strlen($ByteStream)){
        if (sprintf("%02X%02X", ord($ByteStream[$PosJPG+0]),ord($ByteStream[$PosJPG+1]))=="FFC0"){
          $Alto = $this->Byte2PosInt($ByteStream[$PosJPG+5],$ByteStream[$PosJPG+6]);
          $Ancho = $this->Byte2PosInt($ByteStream[$PosJPG+7],$ByteStream[$PosJPG+8]);
        }
        $PosJPG = $PosJPG+2+$this->Byte2PosInt($ByteStream[$PosJPG+2],$ByteStream[$PosJPG+3]);
      }
    }
    if ($Formato > 0){
      $this->HexImageString = "";
      $Salto = 0;
      for ($i=0;$i < strlen($ByteStream); $i++){
        $Salto++;
        $this->HexImageString .= sprintf("%02x", ord($ByteStream[$i]));
        if ($Salto==64){
          $this->HexImageString .= "\n";
          $Salto = 0;
        }
      }
    }
  }


  private function Byte2PosInt($Byte08,$Byte00) {
    return ((ord($Byte08) & 0xFF) << 8)|((ord($Byte00) & 0xFF) << 0);
  }

Используя код PHP:

      $iFormato = NULL;//Format PNG or JPG
      $iAlto = NULL; //High
      $iAncho = NULL;//Wide
      ByteStreamImageString($ImageJPG,$iFormato,$iAlto,$iAncho);//The Dimensions will stored in  iFormato,iAlto,iAncho

Теперь эти функции / метод с использованием JAVA :

  private void ByteStreamImageString(byte[] ByteStream,int[] Frmt,int[] High,int[] Wide) {
    High[0] = 0;
    Wide[0] = 0;
    Frmt[0] = -1;
    this.HexImageString = "Error";
    if ((int)(ByteStream[0]&0xFF)==137 && (int)(ByteStream[1]&0xFF)==80 &&(int)(ByteStream[2]&0xFF)==78){
      Frmt[0] = 1; //PNG
      High[0] = this.Byte2PosInt(ByteStream[22],ByteStream[23]);
      Wide[0] = this.Byte2PosInt(ByteStream[18],ByteStream[19]);
    }
    if ((int)(ByteStream[0]&0xFF)==255 && (int)(ByteStream[1]&0xFF)==216
        &&(int)(ByteStream[2]&0xFF)==255 && (int)(ByteStream[3]&0xFF)==224){
      Frmt[0] = 2; //JPG
      int PosJPG = 2;
      while (PosJPG<ByteStream.length){
        if (String.format("%02X%02X", ByteStream[PosJPG+0],ByteStream[PosJPG+1]).equals("FFC0")){
          High[0] = this.Byte2PosInt(ByteStream[PosJPG+5],ByteStream[PosJPG+6]);
          Wide[0] = this.Byte2PosInt(ByteStream[PosJPG+7],ByteStream[PosJPG+8]);
        }
        PosJPG = PosJPG+2+this.Byte2PosInt(ByteStream[PosJPG+2],ByteStream[PosJPG+3]);
      }
    }
    if (Frmt[0] > 0){
      this.HexImageString = "";
      int Salto = 0;
      for (int i=0;i < ByteStream.length; i++){
        Salto++;
        this.HexImageString += String.format("%02x", ByteStream[i]);
        if (Salto==64){
          this.HexImageString += "\n";
          Salto = 0;
        }
      }
    }
  }


  private Integer Byte2PosInt(byte Byte08, byte Byte00) {
    return new Integer (((Byte08 & 0xFF) << 8)|((Byte00 & 0xFF) << 0));
  }

Используя код Java:

        int[] iFormato = new int[1]; //Format PNG or JPG
        int[] iAlto = new int[1]; //High
        int[] iAncho = new int[1]; //Wide
        ByteStreamImageString(ImageJPG,iFormato,iAlto,iAncho); //The Dimensions will stored in  iFormato[0],iAlto[0],iAncho[0]
joseluisbz
источник
Я вижу, вы используете массивы для аргументов в качестве хака для получения ref/ outпараметров в Java - это считается наилучшей практикой?
Дай
Этот ответ очень старый, теперь я не хочу его обновлять (я многое забываю и у меня нет времени), но вы можете проверить код и отредактировать его.
Joseluisbz
joseluisbz.wordpress.com/2013/07/26/… (объяснение для WMF)
joseluisbz
Для этого примера я рекомендую реализовать новый класс с 3 полями, Format, High и Width, возвращая экземпляр этого класса.
joseluisbz
1

Я полагаю, вам нужны размеры в пикселях (ширина и высота)?

Я думаю, что большинство форматов файлов имеют некоторую информацию заголовка, определяющую размеры, так что программа, читающая файл, может знать, сколько места она должна зарезервировать, прежде чем начать чтение файла. Некоторые форматы файлов «необработанного» типа могут быть просто потоком байтов с некоторым байтом «конца строки» в конце каждой горизонтальной строки пикселей (в этом случае программное обеспечение должно прочитать первую строку и разделить размер потока байтов). по длине линии, чтобы получить высоту).

Я не думаю, что вы можете сделать это каким-либо «общим» способом, так как вам нужно понимать формат файла (или использовать библиотеку, конечно), чтобы знать, как его читать. Вы, вероятно, можете найти некоторый код, который в большинстве случаев даст приблизительную оценку измерений без чтения всего файла, но я думаю, что некоторые типы файлов могут потребовать, чтобы вы прочитали весь файл, чтобы быть уверенным, какие измерения у него действительно есть. Я ожидаю, что большинство веб-ориентированных графических форматов имеют заголовок с такой информацией, чтобы браузер мог создавать размеры блоков до загрузки всего изображения.

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

Обновление : imageinfo, кажется, делает то, что вы хотите. (Еще не проверял)

Штейн Г. Стриндхауг
источник
Этот инструмент работает так быстро, как мне нужно;). Я посмотрю, смогу ли я использовать это правильно.
Анжу
0

Если у вас есть информация EXIF ​​на изображениях, вы можете просто прочитать заголовок EXIF.

Георгий
источник
К сожалению, я не знаю, какие будут изображения и есть ли у них данные EXIF.
Анжу
3
Сколько ваших изображений DO иметь эту информацию? Возможно, если 90% из них имеют данные EXIF, то медлительность использования ImageMagick для остальных 10% будет приемлемой.
Энди Лестер
Почему этот ответ имеет отрицательные голоса? Это правильный ответ на вопрос и вполне может быть именно тем, что ищет ОП или кто-то еще.
Уилл Шеппард
0

-ping - это вариант, который, похоже, для этой цели введен.

Однако с ImageMagick 6.7.7 я не наблюдаю замедления даже для каждого большого файла, например:

head -c 100000000 /dev/urandom > f.gray
# I don't recommend that you run this command as it eats a lot of memory.
convert -depth 8 -size 20000x10000 f.gray f.png
identify f.png

Можете ли вы привести пример входного изображения, для которого оно все еще медленное?

Сиро Сантилли 郝海东 冠状 病 六四 事件 法轮功
источник
0

tldr: файл "imagename" подойдет

работает с webp, все форматы jpg (jpeg, jpg200, ..),

Пример вывода выглядит как

Данные изображения JPEG, стандарт JFIF 1.02, формат изображения, плотность 1x1, длина сегмента 16, базовая линия, точность 8, 650x400, кадры 3

загрузить вывод файла в список Python и использовать 4-е поле в списке.

К вашему сведению, было оптимизировано около 18000+ изображений для сокращения сетевого трафика.

MJ-ек
источник