Bash: Cách nhanh nhất để xác định kích thước của hình ảnh từ URL


8

Tôi đang cố gắng tìm ra một phương pháp thực sự nhanh chóng trong việc xác định kích thước hình ảnh.

Tôi biết tôi có thể quên hình ảnh và sau đó sử dụng hình ảnh để xác định chiều cao và chiều rộng của hình ảnh. Tôi lo ngại rằng đây có thể không phải là cách nhanh nhất để làm điều đó.

Tôi cũng lo ngại về việc phải cài đặt fantemagick khi tôi chỉ cần một tập hợp con rất nhỏ của chức năng. Tôi đang ở trên một hệ thống nhúng có tài nguyên rất hạn chế (CPU, RAM, lưu trữ).

Có ý kiến ​​gì không?


Những loại hình ảnh nào bạn cần hỗ trợ?
Gilles 'SO- ngừng trở nên xấu xa'

Câu trả lời:


13

Như bạn lưu ý, bạn không cần toàn bộ gói ImageMagick . Bạn chỉ cần identify.

Bạn cũng sẽ cần các thư viện các liên kết thực thi đến (và các thư viện mà các thư viện liên kết đến).

> whereis identify
identify: /bin/identify /usr/bin/identify /usr/share/man/man1/identify.1.gz
> ldd /bin/identify

lddsẽ hiển thị một danh sách. Khi tôi làm điều này, nó bao gồm một số lib lib, libjpeg, v.v. và hai thư viện rõ ràng từ gói ImageMagick libMagickCorelibMagickWand. Những người có vẻ được liên kết với cùng một loạt các điều, vì vậy nếu bạn có điều đó, identifynên làm việc.

Bạn không phải tải xuống toàn bộ hình ảnh để có được kích thước, bởi vì những thứ này nằm trong một tiêu đề ở đầu tệp và đó là những gì identifynhìn vào. Ví dụ: ở đây tôi đang sao chép 4 kB đầu tiên từ một jpeg hoàn chỉnh vào một tệp mới:

dd if=real.jpg of=test.jpg bs=1024 count=4

4 kB là quá đủ để bao gồm tiêu đề - Tôi chắc chắn bạn có thể làm điều đó với 1/4 số tiền đó. Hiện nay:

>identify test.jpg 
test.jpg JPEG 893x558 893x558+0+0 8-bit DirectClass 4.1KB 0.000u 0:00.000

Đó là những kích thước chính xác cho real.jpg. Tuy nhiên, lưu ý rằng kích thước (4.1KB) là kích thước của tệp bị cắt bớt, vì thông tin đó không phải từ tiêu đề hình ảnh.

Vì vậy: bạn chỉ phải tải xuống kilobyte đầu tiên hoặc hơn của mỗi hình ảnh.


12

Bạn có thể sử dụng curlđể tải về các phần của hình ảnh. Tất cả phụ thuộc vào mức độ mạnh mẽ của nó. Một trường hợp thử nghiệm có thể là 500 byte đầu tiên. Có vẻ như để làm việc cho rất nhiều pngjpg, sau đó sử dụng identifyhoặc muốn kiểm tra kích thước.

curl -o 500-peek -r0-500 "http://example.net/some-image.png"

Biên tập:


Lâu rồi tôi mới viết trình phân tích cú pháp hình ảnh, nhưng đã suy nghĩ và làm mới một số ký ức của tôi.

Tôi nghi ngờ rằng đó là tất cả các loại hình ảnh bạn muốn kiểm tra (nhưng sau đó một lần nữa, có lẽ không). Tôi sẽ mô tả một số những cái phổ biến hơn : PNG, JPEG (JFIF)GIF.


PNG:

Đây là đơn giản khi khai thác kích thước. Một pngtiêu đề lưu trữ kích thước trong 24 byte đầu tiên. Đầu tiên là một tiêu đề cố định:

byte  value  description
   0  0x89   Bit-check. 0x89 has bit 7 set.
 1-3  PNG    The letters P,N and G
 4-5  \r\n   Newline check.
   6    ^z   MS-DOS won't print data beyond this using `print`
   7    \n   *nix newline.

Tiếp đến khối trough ra các tập tin. Chúng bao gồm một trường cố định về chiều dài, loại và tổng kiểm tra. Ngoài ra một phần dữ liệu tùy chọn kích thước chiều dài .

May mắn thay, đoạn đầu tiên luôn luôn là IHDRvới bố cục này:

byte  description
0-3   Image Width
4-7   Image Height
  8   Bits per sample or per palette index
...   ...

Bằng cách này, chúng ta có các kích thước đó là byte 16-20 và 21-24. Bạn có thể kết xuất dữ liệu bằng cách ví dụ hexdump:

hexdump -vn29 -e '"Bit-test: " /1 "%02x" "\n" "Magic   : " 3/1 "%_c" "\n" "DOS-EOL : " 2/1 "%02x" "\n" "DOS-EOF : " /1 "%02x" "\n" "NIX-EOL : " /1 "%02x" "\n" "Chunk Size: " 4/1 "%02u" "\n" "Chunk-type: " 4/1 "%_c" "\n" "Img-Width : " 4/1 "%02x" "\n" "Img-Height: " 4/1 "%02x" "\n" /1 "Depth : %u bit" "\n" /1 "Color : %u" "\n" /1 "Compr.: %u" "\n" /1 "Filter: %u" "\n" /1 "Interl: %u" "\n"' sample.png

Trên máy Big Endian / Motorola, người ta cũng có thể in các kích thước trực tiếp bằng cách:

hexdump -s16 -n8 -e '1/4 "%u" "\n"' sample.png

Tuy nhiên, trên Little Endian / Intel, nó không phải là dễ dàng, và nó cũng không phải là rất di động.

Bằng cách này, chúng ta có thể triển khai tập lệnh bash + hexdump như trong:

png_hex='16/1 "%02x" " " 4/1 "%02x" " " 4/1 "%02x" "\n"'
png_valid="89504e470d0a1a0a0000000d49484452"

function png_wh()
{
    read -r chunk1 img_w img_h<<<$(hexdump -vn24 -e "$png_hex" "$1")
    if [[ "$chunk1" != "$png_valid" ]]; then
        printf "Not valid PNG: \`%s'\n" "$1" >&2
        return 1
    fi
    printf "%10ux%-10u\t%s\n" "0x$img_w" "0x$img_h" "$1"
    return 0
}

if [[ "$1" == "-v" ]]; then verbose=1; shift; fi

while [[ "$1" ]]; do png_wh "$1"; shift; done

Nhưng, điều này không trực tiếp hiệu quả. Mặc dù nó đòi hỏi một khối lớn hơn (75-100 byte), nhưng identifykhá nhanh hơn. Hoặc viết thói quen trong ví dụ C, sẽ nhanh hơn các cuộc gọi thư viện.


JPEG:

Khi nói đến jpgnó không phải là dễ dàng. Nó cũng bắt đầu với một tiêu đề chữ ký , nhưng phần kích thước không ở mức bù cố định. Sau tiêu đề:

 byte  value
 0-1   ffd8          SOI (Start Of Image)
 2-3   ffe0          JFIF marker
 4-5   <block-size>  Size of this block including this number
 6-10  JFIF\0        ...
11-12  <version>
   13  ...

một khối mới đi kèm được chỉ định bởi một điểm đánh dấu hai byte bắt đầu bằng 0xff. Thông tin lưu giữ về kích thước có giá trị 0xffc0nhưng có thể bị chôn vùi khá nhiều dữ liệu.

Nói cách khác, bỏ qua các byte kích thước khối , kiểm tra điểm đánh dấu, bỏ qua các byte kích thước khối , đọc điểm đánh dấu, v.v. cho đến khi một byte chính xác xuất hiện.

Khi tìm thấy các kích thước được lưu trữ bởi hai byte ở mỗi độ lệch 3 và 5 sau điểm đánh dấu .

 0-1   ffc0          SOF marker
 2-3   <block-size>  Size of this block including this number
   4   <bits>        Sample precision.
 5-6   <Y-size>      Height
 7-8   <X-size>      Width
   9   <components>  Three for color baseline, one for grayscale.

Đã viết một chương trình C đơn giản để kiểm tra một số tệp và khoảng 10.000 hình ảnh jpg, khoảng 50% có thông tin kích thước trong 500 byte đầu tiên, chủ yếu là 50% giữa ca. 100 và 200. Tệ nhất là khoảng 80.000 byte. Một hình ảnh, như chúng ta nói chuyện hình ảnh:

JFIF_SOF_graph


QUÀ TẶNG:

Mặc dù gif thường có thể có nhiều hình ảnh được lưu trữ bên trong, nhưng nó có kích thước canvas được chỉ định trong tiêu đề, nhưng điều này đủ lớn để chứa hình ảnh. Nó dễ dàng như với PNG và yêu cầu các byte thậm chí gây sốt: 10. Sau phép thuật và phiên bản, chúng tôi tìm thấy kích thước. Ví dụ từ hình ảnh 364x472:

<byte>  <hex>   <value>
  0-2   474946  GIF  Magic
  3-5   383961  89a  Version (87a or 89a)
  6-7   6c01    364  Logical Screen Width
  8-9   d801    472  Logical Screen Height

Nói cách khác, bạn có thể kiểm tra sáu byte đầu tiên để xem đó có phải là gif không, sau đó đọc bốn byte tiếp theo để biết kích cỡ.


Các định dạng khác:

Có thể đã tiếp tục, nhưng đoán tôi dừng ở đây bây giờ.


1

Giả sử bạn đã "xác định". Đặt điều này trong một kịch bản và chmod +x <scriptname>. Để chạy nó <scriptname> picture.jpg, bạn sẽ có được chiều cao và chiều rộng của hình ảnh. 2 phần đầu tiên là để kiểm tra xem có hình ảnh không, sau đó đặt nó làm biến IMAGE. Phần tiếp theo là đảm bảo tập tin thực sự ở đó. Hai phần cuối cùng sẽ lấy thông tin liên quan từ đầu ra 'nhận dạng' và hiển thị thông tin đó.

#!/bin/bash
if [[ "${#}" -ne "1" ]]
then
die "Usage: $0 <image>"
fi

IMAGE="${1}"

if [[ ! -f "${IMAGE}" ]]
then
die "File not found: ${IMAGE}"
fi

IMG_CHARS=`identify "$1" | cut -f 3 -d' '`
WIDTH=`echo $IMG_CHARS | cut -d'x' -f 1`
HEIGHT=`echo $IMG_CHARS | cut -d'x' -f 2`

echo -e "W: ${WIDTH} H: ${HEIGHT}"

kịch bản hay. tuy nhiên, thật tuyệt nếu bạn có thể giải thích những gì nó làm (vì Stack Exchange là về học tập).
strugee

0
mohsen@debian:~/codes/amlak/amlak/src$ file ~/Screenshot\ from\ 2013-07-10\ 01\:25\:34.png 
/home/mohsen/Screenshot from 2013-07-10 01:25:34.png: PNG image data, 1366 x 768, 8-bit/color RGB, non-interlaced

file command được cài đặt theo mặc định trên các distors và chỉ phụ thuộc vào:

Depends: libc6 (>= 2.4), libmagic1 (= 1:5.14-2), zlib1g (>= 1:1.1.4)

Tôi nghĩ rằng bạn có thể cài đặt nó dễ dàng để nhúng. Bạn chỉ cần viết một regular expressioncho đầu ra của nó.


2
filekhông cung cấp kích thước cho, ví dụ, .jpgcác tệp.
goldilocks

0
mohsen@debian:~/codes/amlak/amlak/src$ php -r "print_r(getimagesize('file:///archives/Picture/12 farvardin/20120331_013.jpg'));"
Array
(
    [0] => 2560
    [1] => 1440
    [2] => 2
    [3] => width="2560" height="1440"
    [bits] => 8
    [channels] => 3
    [mime] => image/jpeg
)
mohsen@debian:~/codes/amlak/amlak/src$ php -r "print_r(getimagesize('file:///archives/Picture/12 farvardin/20120331_013.jpg'));" |egrep w
    [3] => width="2560" height="1440"
mohsen@debian:~/codes/amlak/amlak/src$ php -r "print_r(getimagesize('file:///archives/Picture/12 farvardin/20120331_013.jpg'));" |egrep w | awk {'print $3'}
width="2560"
mohsen@debian:~/codes/amlak/amlak/src$ php -r "print_r(getimagesize('file:///archives/Picture/12 farvardin/20120331_013.jpg'));" |egrep w | awk {'print $4'}
height="1440"

Bạn thay thế file://bằnghttp://


Tôi không chắc PHP rất phù hợp với các hệ thống nhúng tài nguyên thấp. Cộng với điều này dường như để lấy toàn bộ tập tin.
peterph

Đó là php-cli không phải mô-đun php cho apache, nó không cần apache.
Tiếng Ba Tư

Tuy nhiên, nó sẽ tải toàn bộ công cụ PHP là một bộ nhớ. Cộng với một phần hợp lý của PHP sẽ phải được cài đặt, đây có thể là một vấn đề đối với hệ thống nhúng (không gian đĩa có thể bị giới hạn). Đối với một hệ thống thông thường, nó có thể là một tùy chọn, mặc dù bạn cần sửa đổi nó để ngăn chặn toàn bộ hình ảnh (xem câu trả lời của Sukminder).
peterph
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.