2011-01-12 10 views
99

Poszukuję sposobu, aby uzyskać szybki, aby uzyskać wysokość i szerokość obrazu w pikselach. Powinien obsługiwać przynajmniej pliki JPG, PNG i TIFF, ale im więcej, tym lepiej. Podkreślam: fast, ponieważ moje zdjęcia są dość duże (do 250 MB) i tak długo trwa uzyskanie rozmiaru dzięki ImageMagick's identify, ponieważ oczywiście najpierw odczytuje obrazy jako całość.Szybki sposób uzyskiwania wymiarów obrazu (bez formatowania)

Korzystnie, patrzę na sposób, który działa dobrze w Ruby, lub nawet w Rails 3.

Znam materiał teoretyczny (różne formaty obrazu, ich nagłówków i ich różnice, i tak dalej). Rzeczywiście, proszę o jakąś bibliotekę, która może rozwiązać mój problem w dość ogólny sposób.

Właśnie znalazłem http://imagesize.rubyforge.org, który wygląda obiecująco, chociaż rozwój wydaje się być martwy.

+7

Nie wydaje się to być prawdą w przypadku nowych wersji programu ImageMagick. Korzystanie z ImageMagick 6.5.4-7 Potwierdziłem, że identyfikacja (przynajmniej dla TIF i PNG) odczytuje tylko nagłówek (do 60 KB) i działa bardzo szybko, nawet dla obrazów 335 MB. – coderforlife

Odpowiedz

0

Jeśli na obrazach znajdują się informacje EXIF, można po prostu odczytać nagłówek EXIF.

+0

Niestety nie wiem, jakie obrazy będą i czy mają dane EXIF. – dAnjou

+3

Ile twoich zdjęć * DO * ma te informacje? Być może, jeśli 90% z nich ma dane EXIF, wówczas spowolnienie korzystania z ImageMagick na pozostałych 10% będzie do zaakceptowania. –

+0

Dlaczego ta odpowiedź ma negatywne opinie? Jest to poprawna odpowiedź na pytanie i może być dokładnie tym, czego szuka OP lub ktoś inny. –

25

I nie, czy masz zainstalowane php, ale ta funkcja PHP jest dość poręczny

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

Jest to znacznie szybsze niż "identyfikacja". Dobre podejscie. Dzięki. – souravb

1

To wymiary pikseli chcesz (szerokość i wysokość), zakładam?

Wydaje mi się, że większość formatów plików zawiera informacje nagłówkowe definiujące wymiary, dzięki czemu oprogramowanie odczytujące plik może wiedzieć, ile miejsca musi zarezerwować, zanim zacznie czytać plik. Niektóre formaty plików typu "raw" mogą być po prostu bajtami bajtów z bajtem "końca linii" na końcu każdego poziomego rzędu pikseli (w takim przypadku program musi przeczytać pierwszą linię i podzielić rozmiar strumienia bajtów przez długość linii, aby uzyskać wysokość).

Nie sądzę, że możesz zrobić to w sposób "ogólny", ponieważ musisz zrozumieć format pliku (lub użyć biblioteki oczywiście), aby wiedzieć, jak ją przeczytać. Prawdopodobnie możesz znaleźć kod, który w większości przypadków da przybliżoną ocenę wymiarów bez czytania całego pliku, ale myślę, że niektóre typy plików mogą wymagać przeczytania całego pliku, aby mieć pewność, jakie to naprawdę wymiary. Spodziewam się, że większość internetowych formatów graficznych ma nagłówek z takimi informacjami, aby przeglądarka mogła utworzyć wymiary w polu przed załadowaniem całego obrazu.

Przypuszczam, że dobra biblioteka miałaby kilka metod, aby uzyskać wymiary plików, które obsługuje, i że te metody zostałyby wdrożone tak wydajnie, jak to tylko możliwe.

Aktualizacja: imageinfo wydaje się, że robi to, co chcesz. (Nie zostało przetestowane go)

+0

To narzędzie działa tak szybko, jak tego potrzebuję;). Zobaczę, czy mogę go właściwie użyć. – dAnjou

146
  • file komenda wymiary dla kilku formatów graficznych (np PNG, GIF i JPEG, ale nie PPM), a nie tylko czytać nagłówek.

  • exiv2 podaje wymiary JPEG i TIFF, nawet jeśli nie ma tam żadnego nagłówka EXIF. Nie jest jednak jasne, czy odczytuje to całe dane.

  • head -n1 poda wymiary formatów PPM, PGM.

  • Komenda identify (z ImageMagick) drukuje wiele informacji o obrazie dla wielu różnych obrazów.Wydaje się, że powstrzymuje się od czytania nagłówka (patrz komentarze).

Chyba trzeba napisać własny skrypt, który łączy/analizuje te wyjścia ...

+2

Zrobiłem kilka testów za pomocą polecenia identyfikacji ImageMagick, używając strace do rejestrowania wywołań open/read/mmap/close, aby zobaczyć, ile danych zostało odczytanych ze zidentyfikowanego obrazu. To zależy od rodzaju pliku i rozmiaru pliku, ale otrzymywałem od 20 do 60 KB odczytu przez "identyfikację" dla obrazów o wielkości 5-335 MB (testowałem również pod kątem "convert", który pokazywał odczyt wszystkich bajtów). Wygląda więc na to, że "identyfikacja" jest tu dobrym wyborem (ponieważ obsługuje wszystkie popularne formaty i odczytuje tylko nagłówek). – coderforlife

+1

Myślę, że exiv2 również robi PNG. – chx

4

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

tu przez dwa formatuje PNG i JPG.

Mój kod pochodzi z klasy zaprojektowanej do mojego użytku, możesz edytować zgodnie ze swoimi potrzebami.

Proszę sprawdzić te funkcje/metody przy użyciu 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); 
    } 

pomocą kodu 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 

Teraz te funkcje/metody przy użyciu 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 g kod 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

proszę unikać umieszczania kodu w języku hiszpańskim. –

+0

Widzę, że używasz tablic dla argumentów jako hack, aby uzyskać parametry 'ref' /' out' w Javie - czy jest to uważane za najlepszą praktykę? – Dai

+0

Ta odpowiedź jest bardzo stara, teraz nie chcę aktualizować (zapomniałem dużo rzeczy i nie mam czasu), ale możesz sprawdzić kod i go edytować. –

0

-ping jest opcja, że ​​wydaje się, że wprowadzenie w tym celu.

Jednak jak z ImageMagick 6.7.7 Nie obserwujemy spowolnienie nawet dla każdych dużych plików, np .:

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 

można tworzyć obraz przykład wprowadzania dla których jest jeszcze wolny?

6

Możesz użyć funkcji ImageMagick's identify. Oto jak to zrobić w bash (nota 0 $ jest ścieżka obrazka):

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

I to ukrywa także ewentualne komunikaty o błędach. Nowoczesne implementacje identify odczytują tylko nagłówek, a nie cały obraz, więc jest szybki. Nie wiem, jak to się ma do innych metod.

Powiązane problemy