Görüntü boyutları almanın hızlı yolu (dosya boyutu değil)


138

Bir görüntünün yüksekliğini ve genişliğini piksel olarak almanın hızlı bir yolunu arıyorum . En azından JPG, PNG ve TIFF'yi ele almalı, ancak daha iyi. Hızlı bir şekilde vurgularım çünkü görüntülerim oldukça büyük (250 MB'a kadar) ve ImageMagick'lerle boyut elde etmek çok uzun sürüyor identifyçünkü açıkça bir bütün olarak görüntüleri okuyor.

Tercihen Ruby'de, hatta Rails 3'te iyi çalışan bir yol arıyorum.

Teori öğelerini biliyorum (çeşitli görüntü formatları, başlıkları ve farklılıkları vb.). Gerçekten, sorunumu oldukça genel bir şekilde çözebilecek bir tür kütüphane istiyorum.

Gelişimin ölü gibi görünse de ümit verici görünen imgelem buldum .


8
Bu, ImageMagick'in yeni sürümleri için doğru görünmüyor. ImageMagick 6.5.4-7 kullanarak Tanımlamanın (en azından TIF ve PNG için) yalnızca başlığı okuduğunu (60KB'a kadar) ve 335MB görüntüler için bile çok hızlı çalıştığını doğruladım.
coderforlife

Yanıtlar:


195
  • fileKomut birkaç görüntü formatları için boyutları (örn PNG, GIF, JPEG; son sürümlerini de PPM, WEBP) yazdırır ve sadece başlığını okumak gelmez.

  • identifyKomut (Imagemagick itibaren) görüntülerin çok çeşitli görüntü çok sayıda bilgi yazdırır. Başlık bölümünü okumak için kendini kısıtlıyor gibi görünüyor (yorumlara bakınız). Ayrıca filene yazık ki eksik olan birleşik bir çıktıya sahiptir .

  • exiv2EXIF üstbilgisi olmasa bile JPEG, TIFF, PNG, GIF, WEBP gibi birçok format için boyutlar sunar. Yine de bunun için tüm verileri okuyup okumadığına dair kesin bir bilgi yoktur. Desteklenen tüm görüntü formatları için exiv2'nin kılavuz sayfasına bakınız.

  • head -n1 PPM, PGM formatları için boyutları verecektir.

Formatları web üzerinde popüler, her ikisi için exiv2ve identifyiş yapacak. Kullanım durumuna bağlı olarak, çeşitli araçların çıktılarını birleştiren / ayrıştıran kendi komut dosyanızı yazmanız gerekebilir.


3
Tanımlanan görüntüden ne kadar veri okunduğunu görmek için açık / okuma / mmap / yakın çağrıları kaydetmek için strace kullanarak ImageMagick identify komutuyla bazı testler yaptım. Biraz dosya türüne ve dosya boyutuna bağlıdır, ancak 5-335 MB görüntüler için "tanımla" ile 20-60 KB okunmaya başlamıştım (ayrıca okunan tüm baytları gösteren "dönüştürme" ye karşı da test ettim). Bu yüzden "tanımla" burada iyi bir seçim gibi görünüyor (çünkü tüm popüler formatları destekliyor ve sadece başlığı okuyor).
coderforlife

1
Bence exiv2 de PNG yapıyor.
chx

Bu dosya komutlarının çıktısını kolayca ayrıştırmanın herhangi bir yolu var mı? Tanımlamak harika ama WebP dosyalarıyla ne yazık ki çalışmıyor
Brian Leishman

Tanımlayın yapar WebP ile çalışmalarını ve ImageMagick yıllardır WebP desteği vardır. Belki bir güncelleme alabilirsin?
ypnos

32

Yüklü php emin değilim, ama bu PHP işlevi oldukça kullanışlı

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

1
Bu "tanımlamaktan" daha hızlıdır. Iyi bir yaklaşım. Teşekkürler.
souravb

19

ImageMagick'in tanımlama işlevini kullanabilirsiniz . Bunu bash'da nasıl yapacağınız (Not $ 0, görüntünün yoludur):

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

Bu da olası hata mesajlarını gizler. Modern uygulamalar identifysadece başlığı okur, tüm görüntüyü değil, bu yüzden hızlıdır. Yine de diğer yöntemlerle nasıl karşılaştırıldığından emin değilim.


2
Bu şekilde çok daha verimli olduğuna inanıyorum:read width height < <(identify -format "%w %h" "${1}")
Cromax

5

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

Burada iki format için PNG ve JPG.

Kodum benim kullanımım için tasarlanmış bir sınıftan, ihtiyaçlarınıza göre düzenleyebilirsiniz.

Lütfen PHP kullanarak bu işlevleri / yöntemi kontrol edin :

  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 Kodunu Kullanma:

      $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

Şimdi bu işlevleri / yöntemi JAVA kullanarak :

  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 kodunu kullanma:

        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]

Java'da almak ref/ outparametreler için bir hack olarak argümanlar için diziler kullandığınızı görüyorum - bu en iyi yöntem olarak kabul ediliyor mu?
Dai

Bu cevap çok eski, şimdi güncellemek istemiyorum (çok şey unuttum ve zamanım yok), ancak kodu kontrol edip düzenleyebilirsiniz.
joseluisbz


Bu örnek için, bu sınıfın bir örneğini döndüren Biçim, Yüksek ve Genişlik olmak üzere 3 alanlı yeni bir sınıf uygulamanızı öneririm.
joseluisbz

1

İstediğiniz piksel boyutları (genişlik ve yükseklik), sanırım?

Çoğu dosya formatının boyutları tanımlayan bazı başlık bilgilerine sahip olduğunu düşünüyorum, böylece dosyayı okuyan yazılım dosyayı okumaya başlamadan önce ne kadar yer ayırması gerektiğini bilebilir. Bazı "ham" türdeki dosya biçimleri, her yatay piksel satırının sonunda bazı "satır sonu" baytları olan bir bayt akışı olabilir (bu durumda yazılımın ilk satırı okuması ve bayt akışının boyutunu bölmesi gerekir) yüksekliği elde etmek için çizgi uzunluğuna göre).

Bunu nasıl okuyacağınızı bilmek için dosya biçimini (veya tabii ki bir kütüphaneyi kullanmanız) anlamanız gerektiği için bunu herhangi bir "genel" şekilde yapabileceğinizi sanmıyorum. Muhtemelen tüm dosyayı okumadan boyutların kaba bir tahminini verecek bazı kodlar bulabilirsiniz, ancak bazı dosya türlerinin gerçekten hangi boyutlara sahip olduğundan emin olmak için tüm dosyayı okumanızı gerektirebileceğini düşünüyorum. Çoğu web merkezli görüntü formatının, böyle bir bilgi içeren bir başlığa sahip olmasını bekliyorum, böylece tarayıcı tüm görüntü yüklenmeden önce kutu boyutlarını oluşturabilir.

İyi bir kütüphanenin işlediği dosyaların boyutlarını elde etmek için bazı yöntemleri olurdu ve bu yöntemlerin mümkün olduğunca verimli uygulanacağını tahmin ediyorum.

Güncelleme : imageinfo istediğini yapıyor gibi görünüyor. (Test etmedim)


Bu araç ihtiyacım kadar hızlı çalışır;). Düzgün kullanıp kullanamayacağımı göreceğim.
dAnjou

0

Görüntülerde EXIF ​​bilgileri varsa, EXIF ​​başlığını okuyabilirsiniz.


Ne yazık ki ne tür görüntüler olacağını ve EXIF ​​verilerinin olup olmadığını bilmiyorum.
dAnjou

3
Kaç resimlerinizin DO bilgilerimiz var? Belki% 90'ında EXIF ​​verisi varsa, diğer% 10'da ImageMagick kullanmanın yavaşlığı kabul edilebilir.
Andy Lester

Bu cevabın neden aşağı oyları var? Bu soruya geçerli bir cevaptır ve OP veya başka birinin tam olarak aradığı şey olabilir.
Will Sheppard

0

-ping , bu amaç için tanıtmış gibi görünen bir seçenektir.

Ancak ImageMagick 6.7.7'den itibaren her büyük dosya için bile yavaşlama gözlemlemiyorum, örneğin:

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

Hâlâ yavaş olan örnek bir girdi görüntüsü üretebilir misiniz?


0

tldr: "imagename" dosyası yapacak

webp ile çalışır, tüm jpg formatları (jpeg, jpg200, ..),

Örnek çıktı şuna benzer

JPEG görüntü verileri, JFIF standardı 1.02, en boy oranı, yoğunluk 1x1, segment uzunluğu 16, taban çizgisi, hassas 8, 650x400, çerçeveler 3

dosyanın çıktısını bir python listesine yükleyin ve listedeki 4. alanı kullanın.

FYI, ağ trafiğini azaltmak için 18000'den fazla görüntüyü optimize etti.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.