Cách nhanh chóng để có được kích thước hình ảnh (không kích thước tập tin)


138

Tôi đang tìm kiếm một cách nhanh chóng để có được chiều cao và chiều rộng của hình ảnh bằng pixel. Nó sẽ xử lý ít nhất JPG, PNG và TIFF, nhưng càng nhiều càng tốt. Tôi nhấn mạnh nhanh vì hình ảnh của tôi khá lớn (lên tới 250 MB) và phải mất rất lâu để có được kích thước với ImageMagick identifyvì nó rõ ràng là đọc toàn bộ hình ảnh trước tiên.

Tốt hơn là, tôi tìm kiếm một cách hoạt động tốt trong Ruby, hoặc thậm chí trong Rails 3.

Tôi biết các công cụ lý thuyết (các định dạng hình ảnh khác nhau, tiêu đề của chúng và sự khác biệt của chúng, v.v.). Thật vậy, tôi yêu cầu một số loại thư viện có thể giải quyết vấn đề của tôi một cách khá chung chung.

Tôi chỉ tìm thấy hình ảnh có vẻ đầy hứa hẹn mặc dù sự phát triển dường như đã chết.


8
Điều này dường như không đúng với các phiên bản mới của ImageMagick. Sử dụng ImageMagick 6.5.4-7 tôi đã xác nhận rằng nhận dạng (ít nhất là đối với TIF và PNG) chỉ đọc tiêu đề (tối đa 60KB) và hoạt động rất nhanh, ngay cả đối với hình ảnh 335 MB.
coderforlife

Câu trả lời:


195
  • Các filelệnh in kích thước cho một số định dạng hình ảnh (ví dụ như PNG, GIF, JPEG; phiên bản gần đây cũng PPM, WebP), và không chỉ đọc tiêu đề.

  • Các identifylệnh (từ ImageMagick) in rất nhiều thông tin hình ảnh cho một loạt các hình ảnh. Nó dường như hạn chế đọc phần tiêu đề (xem bình luận). Nó cũng có một đầu ra thống nhất mà fileđáng buồn thiếu.

  • exiv2cung cấp cho bạn kích thước cho nhiều định dạng, bao gồm JPEG, TIFF, PNG, GIF, WEBP, ngay cả khi không có tiêu đề EXIF. Không rõ là nó đọc toàn bộ dữ liệu cho điều đó mặc dù. Xem trang chủ của exiv2 để biết tất cả các định dạng hình ảnh được hỗ trợ.

  • head -n1 sẽ cung cấp cho bạn các kích thước cho các định dạng PPM, PGM.

Đối với các định dạng phổ biến trên web, cả hai exiv2identifysẽ thực hiện công việc. Tùy thuộc vào trường hợp sử dụng, bạn có thể cần phải viết tập lệnh của riêng mình kết hợp / phân tích kết quả đầu ra của một số công cụ.


3
Tôi đã thực hiện một số thử nghiệm với lệnh nhận dạng ImageMagick, sử dụng strace để ghi lại các cuộc gọi mở / đọc / mmap / đóng để xem lượng dữ liệu đã được đọc từ hình ảnh được xác định. Nó phụ thuộc vào loại tệp và kích thước tệp một chút, nhưng tôi đã nhận được 20-60 KB đọc bằng cách "xác định" cho hình ảnh 5-335 MB (Tôi cũng đã thử nghiệm với "chuyển đổi" cho thấy tất cả các byte đang được đọc). Vì vậy, có vẻ như "nhận dạng" là một lựa chọn tốt ở đây (vì nó hỗ trợ tất cả các định dạng phổ biến và chỉ đọc tiêu đề).
coderforlife

1
Tôi nghĩ exiv2 cũng làm PNG.
chx

Bất kỳ cách để phân tích lệnh tập tin đầu ra dễ dàng? Xác định là tuyệt vời nhưng thật đáng buồn khi nó không hoạt động với các tệp WebP
Brian Leishman

Xác định không hoạt động với WebP và ImageMagick đã hỗ trợ WebP trong nhiều năm. Có lẽ bạn có thể nhận được một bản cập nhật?
ypnos

32

Tôi không chắc bạn đã cài đặt php, nhưng chức năng PHP này khá tiện dụng

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

1
Điều này nhanh hơn nhiều so với "xác định". Cách tiếp cận tốt. Cảm ơn.
souravb

19

Bạn có thể sử dụng chức năng nhận dạng của ImageMagick . Đây là cách bạn thực hiện trong bash (Lưu ý $ 0 là đường dẫn của hình ảnh):

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

Và điều này cũng ẩn bất kỳ thông báo lỗi tiềm năng. Việc triển khai hiện đại identifychỉ đọc tiêu đề, không phải toàn bộ hình ảnh, vì vậy nó rất nhanh. Không chắc chắn làm thế nào nó so sánh với các phương pháp khác mặc dù.


2
Tôi tin rằng nó hiệu quả hơn nhiều theo cách này: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 hoặc WMF)

Ở đây cho hai định dạng PNG và JPG.

Mã của tôi là từ một lớp được thiết kế để sử dụng, bạn có thể chỉnh sửa theo nhu cầu của bạn.

Vui lòng kiểm tra các hàm / phương thức này bằng 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);
  }

Sử dụng mã 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

Bây giờ các hàm / phương thức này sử dụng 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));
  }

Sử dụng mã 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]

Tôi thấy bạn đang sử dụng mảng cho các đối số như là một hack để lấy ref/ outtham số trong Java - đó có được coi là cách thực hành tốt nhất không?
Đại

Câu trả lời này rất cũ, bây giờ tôi không sẵn sàng cập nhật (Tôi quên rất nhiều thứ và tôi không có thời gian), nhưng bạn có thể kiểm tra mã và chỉnh sửa nó.
joseluisbz


Trong ví dụ này, tôi khuyên bạn nên triển khai một lớp mới với 3 trường, Định dạng, Cao và Rộng, trả về một thể hiện của lớp này.
joseluisbz

1

Đó là kích thước pixel bạn muốn (chiều rộng và chiều cao), tôi giả sử?

Tôi nghĩ rằng hầu hết các định dạng tệp đều có một số thông tin tiêu đề xác định kích thước, để phần mềm đọc tệp có thể biết nó phải dự trữ bao nhiêu phòng trước khi bắt đầu đọc tệp. Một số định dạng tệp loại "thô" có thể chỉ là một luồng byte với một số byte "cuối dòng" ở cuối mỗi hàng pixel ngang (trong trường hợp đó phần mềm phải đọc dòng đầu tiên và chia kích thước của luồng byte theo chiều dài dòng để có được chiều cao).

Tôi không nghĩ bạn có thể thực hiện điều này theo bất kỳ cách "chung chung" nào, vì bạn cần hiểu định dạng tệp (hoặc sử dụng thư viện tất nhiên) để biết cách đọc nó. Bạn có thể tìm thấy một số mã trong hầu hết các trường hợp sẽ đưa ra ước tính sơ bộ về kích thước mà không cần đọc toàn bộ tệp, nhưng tôi nghĩ rằng một số loại tệp có thể yêu cầu bạn đọc toàn bộ tệp để chắc chắn kích thước thực sự có. Tôi hy vọng rằng hầu hết các định dạng hình ảnh trung tâm web đều có tiêu đề với thông tin như vậy để trình duyệt có thể tạo kích thước hộp trước khi toàn bộ hình ảnh được tải.

Tôi đoán một thư viện tốt sẽ có một số phương pháp để lấy kích thước của các tệp mà nó xử lý và các phương thức đó sẽ được triển khai hiệu quả nhất có thể.

Cập nhật : imageinfo có vẻ như nó làm những gì bạn muốn. (Chưa thử nghiệm)


Công cụ đó hoạt động nhanh như tôi cần;). Tôi sẽ xem nếu tôi có thể sử dụng nó đúng cách.
dAnjou

0

Nếu bạn có thông tin EXIF ​​trong ảnh, bạn có thể đọc tiêu đề EXIF.


Thật không may, tôi không biết sẽ có loại hình ảnh nào và liệu chúng có dữ liệu EXIF ​​không.
dAnjou

3
Có bao nhiêu hình ảnh của bạn DO có thông tin đó? Có thể nếu 90% trong số họ có dữ liệu EXIF ​​thì việc chậm sử dụng ImageMagick trên 10% còn lại sẽ được chấp nhận.
Andy Lester

Tại sao câu trả lời này có downvote? Đó là một câu trả lời hợp lệ cho câu hỏi và cũng có thể chính xác là những gì OP hoặc người khác đang tìm kiếm.
Will Sheppard

0

-ping là một tùy chọn dường như đã giới thiệu cho mục đích đó.

Tuy nhiên, kể từ ImageMagick 6.7.7, tôi không quan sát thấy sự chậm lại ngay cả đối với mọi tệp lớn, ví dụ:

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

Bạn có thể tạo ra một hình ảnh đầu vào ví dụ mà nó vẫn còn chậm không?


0

tldr: tập tin "hình ảnh" sẽ làm

hoạt động với webp, tất cả các định dạng jpg (jpeg, jpg200, ..),

Mẫu đầu ra trông như

Dữ liệu hình ảnh JPEG, tiêu chuẩn JFIF 1.02, tỷ lệ khung hình, mật độ 1x1, chiều dài phân đoạn 16, đường cơ sở, độ chính xác 8, 650x400, khung 3

tải đầu ra của tệp vào danh sách python và sử dụng trường thứ 4 trong danh sách.

FYI, đã tối ưu hóa khoảng 18000+ hình ảnh để cắt giảm lưu lượng mạng.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.