Швидкий спосіб отримання розмірів зображення (не розмір файлів)


138

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

Переважно, я шукаю спосіб, який добре працює в Ruby, або навіть у Rails 3.

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

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


8
Мабуть, це не відповідає дійсності нових версій ImageMagick. Використовуючи ImageMagick 6.5.4-7, я підтвердив, що ідентифікація (принаймні для TIF і PNG) зчитує лише заголовок (до 60 КБ) і працює дуже швидко, навіть для 335 МБ зображень.
coderforlife

Відповіді:


195
  • The fileКоманда друкує розміри для кількох форматів зображень (наприклад , PNG, GIF, JPEG, останні версії і PPM, WebP), і не тільки для читання заголовка.

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

  • exiv2надає розміри для багатьох форматів, включаючи JPEG, TIFF, PNG, GIF, WEBP, навіть якщо немає заголовка EXIF. Незрозуміло, чи читає він цілі дані для цього. Перегляньте сторінку exiv2 для всіх підтримуваних форматів зображень.

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

Для популярних форматів в Інтернеті, так exiv2і identifyбуде робити цю роботу. Залежно від випадку використання, можливо, вам доведеться написати свій власний сценарій, який поєднує / аналізує результати декількох інструментів.


3
Я зробив кілька тестів з командою ImageMagick identification, використовуючи strace для запису відкритих / читати / 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'));"

1
Це набагато швидше, ніж "ідентифікувати". Хороший підхід. Дякую.
суравб

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/obthing-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]

Я бачу, ви використовуєте масиви для аргументів як хак для отримання ref/ outпараметрів у Java - це вважається найкращою практикою?
Дай

Ця відповідь дуже стара, зараз я не бажаю оновлювати (я забув багато речей і не маю часу), але ви можете перевірити код і відредагувати його.
joseluisbz

joseluisbz.wordpress.com/2013/07/26/… (пояснення для WMF)
joseluisbz

Для цього прикладу я рекомендую реалізувати новий клас із 3 полями, Формат, Висока та Ширина, повертаючи екземпляр цього класу.
joseluisbz

1

Я вважаю, що це розміри пікселів (ширина та висота)?

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

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

Я б здогадувався, що в хорошій бібліотеці є деякі методи для отримання розмірів файлів, якими вони обробляються, і щоб ці методи були реалізовані максимально ефективно.

Оновлення : іміджева інформація здається, що вона робить те, що ви хочете. (Не перевіряли)


Цей інструмент працює так швидко, як мені потрібно;). Я побачу, чи можу я ним правильно користуватися.
dAnjou

0

Якщо у вас є інформація EXIF ​​на зображеннях, ви можете просто прочитати заголовок EXIF.


На жаль, я не знаю, які зображення будуть і чи мають вони EXIF ​​дані.
dAnjou

3
Скільки ваших зображень DO мати цю інформацію? Можливо, якщо 90% з них мають дані EXIF, то повільність використання ImageMagick на інших 10% буде прийнятною.
Енді Лестер

Чому ця відповідь має зворотний зв'язок? Це правильна відповідь на питання і цілком може бути саме те, що шукає ОП або хтось інший.
Буде Шеппард

0

-пінг - це варіант, який, здається, запровадив для цієї мети.

Однак, що стосується 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, співвідношення сторін, щільність 1х1, довжина сегмента 16, базова лінія, точність 8, 650x400, кадри 3

завантажте вихідний файл у список python та використовуйте 4-е поле у ​​списку.

FYI, оптимізував близько 18000+ зображень, щоб зменшити мережевий трафік.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.