2011-01-12 4 views
99

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

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

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

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

+7

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

ответ

0

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

+0

К несчастью, я не знаю, какие будут изображения и будут ли они иметь данные EXIF. – dAnjou

+3

Сколько ваших изображений * У DO * есть эта информация? Возможно, если 90% из них будут иметь EXIF-данные, то медленность использования ImageMagick на других 10% будет приемлемой. –

+0

Почему этот ответ имеет downvotes? Это правильный ответ на вопрос, и вполне может быть именно то, что ищет OP или кто-то другой. –

25

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

php -r "print_r(getimagesize('http://www.google.com/images/logos/ps_logo2.png'));" 
+0

Это намного быстрее, чем «идентифицировать». Хороший подход. Благодарю. – souravb

1

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

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

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

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

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

+0

Этот инструмент работает так же быстро, как мне это нужно;). Я посмотрю, смогу ли я использовать его правильно. – dAnjou

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

  • exiv2 дает размеры JPEG и TIFF, даже если нет EXIF-заголовка. Неясно, читает ли он все данные для этого.

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

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

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

+2

Я провел несколько тестов с помощью команды идентификации ImageMagick, используя strace для записи вызовов open/read/mmap/close, чтобы узнать, сколько данных было прочитано с идентифицированного изображения. Это немного зависит от типа файла и размера файла, но я получал 20-60 КБ, прочитав «идентифицировать» для 5-335 МБ изображений (я также протестировал против «конвертировать», который показывал все прочитанные байты). Таким образом, похоже, что «идентификация» - хороший выбор здесь (поскольку он поддерживает все популярные форматы и читает только заголовок). – coderforlife

+1

думаю exiv2 тоже делает PNG. – chx

4

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

Usin г код 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

, пожалуйста, не отправляйте код на испанский. –

+0

Я вижу, что вы используете массивы для аргументов как хак для получения параметров 'ref' /' out' в Java - считается ли это лучшей практикой? – Dai

+0

Этот ответ очень старый, теперь я не хочу обновлять (я забыл много вещей, и у меня нет времени), но вы можете проверить код и отредактировать его. –

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 

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

6

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

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

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

Смежные вопросы