Быстрый способ получить размеры изображения (не размер файла) - PullRequest
127 голосов
/ 12 января 2011

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

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

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

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

Ответы [ 8 ]

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

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

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

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

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

31 голосов
/ 12 января 2011

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

 php -r "print_r(getimagesize('http://www.google.com/images/logos/ps_logo2.png'));"
14 голосов
/ 12 октября 2017

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

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

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

5 голосов
/ 17 июля 2013

https://joseluisbz.wordpress.com/2013/08/06/obtaining-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]
1 голос
/ 12 января 2011

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

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

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

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

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

0 голосов
/ 14 января 2019

tldr: файл "imagename" будет делать

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

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

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

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

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

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 голосов
/ 12 января 2011

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...