Cara cepat untuk mendapatkan dimensi gambar (bukan ukuran file)

138

Saya mencari cara cepat untuk mendapatkan tinggi dan lebar gambar dalam piksel. Ini harus menangani setidaknya JPG, PNG dan TIFF, tetapi lebih banyak lebih baik. Saya menekankan dengan cepat karena gambar saya cukup besar (hingga 250 MB) dan butuh waktu sangat lama untuk mendapatkan ukuran dengan ImageMagick identifykarena jelas membaca gambar secara keseluruhan terlebih dahulu.

Lebih disukai, saya mencari cara yang bekerja dengan baik di Ruby, atau bahkan di Rails 3.

Saya tahu hal-hal teori (berbagai format gambar, header dan perbedaannya, dan sebagainya). Memang, saya meminta semacam perpustakaan yang dapat menyelesaikan masalah saya dengan cara yang cukup umum.

Saya baru saja menemukan imageize yang terlihat menjanjikan meskipun perkembangannya sepertinya sudah mati.

dAnjou
sumber
8
Ini tampaknya tidak benar untuk versi baru ImageMagick. Menggunakan ImageMagick 6.5.4-7 Saya telah mengkonfirmasi bahwa identifikasi (setidaknya untuk TIF dan PNG) hanya membaca header (hingga 60KB) dan bekerja sangat cepat, bahkan untuk gambar 335MB.
coderforlife

Jawaban:

195
  • The fileperintah mencetak dimensi untuk beberapa format gambar (misalnya PNG, GIF, JPEG; versi terbaru juga PPM, WebP), dan tidak hanya membaca header.

  • The identifyperintah (dari ImageMagick) mencetak banyak informasi gambar untuk berbagai macam gambar. Tampaknya menahan diri untuk membaca bagian header (lihat komentar). Ini juga memiliki output terpadu yang filesayangnya kurang.

  • exiv2memberi Anda dimensi untuk banyak format, termasuk JPEG, TIFF, PNG, GIF, WEBP, meskipun tidak ada header EXIF. Tidak jelas apakah ia membaca seluruh data untuk itu. Lihat halaman manual exiv2 untuk semua format gambar yang didukung.

  • head -n1 akan memberi Anda dimensi untuk PPM, format PGM.

Untuk format yang populer di web, keduanya exiv2dan identifyakan berfungsi. Bergantung pada kasus penggunaan, Anda mungkin perlu menulis skrip Anda sendiri yang menggabungkan / mengurai keluaran dari beberapa alat.

ypnos
sumber
3
Saya telah melakukan beberapa tes dengan perintah identifikasi ImageMagick, menggunakan strace untuk merekam panggilan buka / baca / mmap / tutup untuk melihat berapa banyak data yang telah dibaca dari gambar yang diidentifikasi. Itu tergantung pada jenis file dan ukuran file sedikit, tapi saya mendapatkan 20-60 KB dibaca dengan "mengidentifikasi" untuk 5-335 MB gambar (saya juga menguji "mengkonversi" yang menunjukkan semua byte sedang dibaca). Jadi sepertinya "identifikasikan" adalah pilihan yang baik di sini (karena mendukung semua format populer dan hanya membaca header).
coderforlife
1
Saya pikir exiv2 juga melakukan PNG.
chx
Adakah cara untuk mengurai output perintah file itu dengan mudah? Identifikasi itu bagus tetapi sayangnya tidak berfungsi dengan file WebP
Brian Leishman
Mengidentifikasi melakukan pekerjaan dengan WebP, dan ImageMagick memiliki dukungan untuk WebP selama bertahun-tahun. Mungkin Anda bisa mendapatkan pembaruan?
ypnos
32

Saya tidak yakin Anda telah menginstal php, tetapi fungsi PHP ini sangat berguna

 php -r "print_r(getimagesize('http://www.google.com/images/logos/ps_logo2.png'));"
ajreal
sumber
1
Ini jauh lebih cepat daripada "mengidentifikasi". Pendekatan yang bagus. Terima kasih.
Souravb
19

Anda dapat menggunakan fungsi identifikasi ImageMagick . Inilah cara Anda melakukannya di bash (Catatan $ 0 adalah jalur gambar):

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

Dan ini juga menyembunyikan pesan kesalahan potensial. Implementasi modern identifyhanya membaca header, bukan seluruh gambar, jadi cepat. Tidak yakin bagaimana perbandingannya dengan metode lain.

James L.
sumber
2
Saya percaya ini jauh lebih efisien dengan cara ini: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 atau WMF)

Di sini untuk dua format PNG dan JPG.

Kode saya berasal dari kelas yang dirancang untuk saya gunakan, Anda dapat mengedit sesuai kebutuhan Anda.

Silakan periksa fungsi / metode ini menggunakan 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);
  }

Menggunakan Kode 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

Sekarang fungsi / metode ini menggunakan 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));
  }

Menggunakan kode 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]
joseluisbz
sumber
Saya melihat Anda menggunakan array untuk argumen sebagai peretasan untuk mendapatkan ref/ outparameter di Java - apakah itu dianggap praktik terbaik?
Dai
Jawaban ini sangat lama, sekarang saya tidak mau memperbarui (saya lupa banyak hal dan saya tidak punya waktu), tetapi Anda dapat memeriksa kode dan mengeditnya.
joseluisbz
joseluisbz.wordpress.com/2013/07/26/… (penjelasan untuk WMF)
joseluisbz
Untuk contoh ini saya merekomendasikan mengimplementasikan kelas baru dengan 3 bidang, Format, Tinggi dan Lebar, mengembalikan contoh kelas ini.
joseluisbz
1

Ini dimensi piksel yang Anda inginkan (lebar dan tinggi), menurut saya?

Menurut saya, sebagian besar format file memiliki beberapa info header yang menentukan dimensinya, sehingga perangkat lunak yang membaca file tersebut dapat mengetahui berapa banyak ruang yang harus dipesan sebelum mulai membaca file. Beberapa format file tipe "mentah" mungkin hanya berupa aliran byte dengan beberapa byte "akhir baris" di akhir setiap baris horizontal piksel (dalam hal ini perangkat lunak harus membaca baris pertama dan membagi ukuran aliran byte dengan panjang garis untuk mendapatkan ketinggian).

Saya tidak berpikir Anda dapat membuat ini dengan cara "umum", karena Anda perlu memahami format file (atau menggunakan perpustakaan tentunya) untuk mengetahui cara membacanya. Anda mungkin dapat menemukan beberapa kode yang dalam banyak kasus akan memberikan perkiraan kasar tentang dimensi tanpa membaca keseluruhan file, tetapi saya pikir beberapa tipe file mungkin mengharuskan Anda untuk membaca seluruh file untuk memastikan dimensi apa yang sebenarnya dimilikinya. Saya berharap sebagian besar format gambar web centric memiliki header dengan info seperti itu sehingga browser dapat membuat dimensi kotak sebelum seluruh gambar dimuat.

Saya kira perpustakaan yang baik akan memiliki beberapa metode untuk mendapatkan dimensi file yang ditanganinya, dan metode tersebut akan diimplementasikan seefisien mungkin.

Pembaruan : imageinfo sepertinya melakukan apa yang Anda inginkan. (Belum mengujinya)

Stein G. Strindhaug
sumber
Alat itu bekerja secepat saya membutuhkannya;). Saya akan melihat apakah saya dapat menggunakannya dengan benar.
dAnjou
0

Jika Anda memiliki informasi EXIF ​​dalam gambar, Anda cukup membaca header EXIF.

Georgi
sumber
Sayangnya saya tidak tahu gambar seperti apa yang akan ada dan apakah mereka memiliki data EXIF.
dAnjou
3
Berapa banyak gambar Anda yang MEMILIKI informasi itu? Mungkin jika 90% dari mereka memiliki data EXIF ​​maka kelambatan menggunakan ImageMagick pada 10% lainnya akan dapat diterima.
Andy Lester
Mengapa jawaban ini memiliki suara negatif? Ini adalah jawaban yang valid untuk pertanyaan tersebut dan mungkin persis seperti yang dicari OP atau orang lain.
Will Sheppard
0

-ping adalah opsi yang sepertinya telah diperkenalkan untuk tujuan itu.

Namun pada ImageMagick 6.7.7 saya tidak melihat perlambatan bahkan untuk setiap file besar, misalnya:

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

Dapatkah Anda menghasilkan contoh gambar input yang masih lambat?

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
sumber
0

tldr: file "imagename" bisa digunakan

berfungsi dengan webp, semua format jpg (jpeg, jpg200, ..),

Keluaran sampel terlihat seperti

Data gambar JPEG, standar JFIF 1.02, rasio aspek, kepadatan 1x1, panjang segmen 16, baseline, presisi 8, 650x400, frame 3

muat keluaran file ke daftar python & gunakan bidang ke-4 dalam daftar.

FYI, memang mengoptimalkan sekitar 18000+ gambar untuk mengurangi lalu lintas jaringan.

mj-ek
sumber