Bash:URLで画像サイズを決定する最速の方法

Bash:URLで画像サイズを決定する最速の方法

私はBashで画像サイズを決定する非常に迅速な方法を見つけようとしています。

私は画像を取得し、imagemagickを使用して画像の高さと幅を決定できることを知っています。これが最速の方法ではないかもしれません。

また、小さな機能セットだけが必要なときにimagemagickをインストールする必要があることも心配です。私が作業している組み込みシステムには、リソース(CPU、RAM、ストレージ)が非常に限られています。

どんなアイデアがありますか?

答え1

ご存知のように、全体は必要ありません。イメージマジシャンパック。あなたはただidentify

また、実行可能ファイルがリンクされているライブラリ(およびこれらのライブラリがリンクされているライブラリ)が必要です。

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

lddリストが表示されます。私がこれを行ったとき、いくつかのXライブラリ、libjpegなどが含まれており、ImageMagickパッケージから来たように見える2つのライブラリもlibMagickCore含まれていましたlibMagickWand。これらは同じ項目に結び付けられているように見えるため、identify機能します。 。

identifyサイズはファイルの先頭のヘッダーにあり、私たちが見ているものなので、サイズを取得するためにイメージ全体をダウンロードする必要はありません。たとえば、ここではjpeg全体の最初の4kBを新しいファイルにコピーします。

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

ヘッダーを含めるには4kBで十分です。その量の1/4で十分だと思います。今:

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

これらは正しいサイズですreal.jpg。ただし、その情報は画像ヘッダーでは提供されないため、サイズ(4.1KB)は切り捨てられたファイルのサイズです。

したがって、各画像の最初のKB程度をダウンロードするだけです。

答え2

これを使用してcurl画像の一部をダウンロードできます。それはすべてそれがどれほど頑丈であるかに依存します。テストケースは最初の500バイトです。多くのpng金額を処理し、jpgサイズをidentify確認するために、または同様のものを使用するようです。

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

編集する:


イメージパーサーを作成してからかなり時間が経ちましたが、思いを見て思い出を少し蘇りました。

私はそれだと思うあらゆる種類の確認したい画像(ただし、もう一度確認しない可能性があります)。より一般的なものについて説明しますPNGJPEG (JFIF)そしてGIF


パプアニューギニア:

次元抽出においては簡単です。ヘッダーはpng最初の24バイト以内のサイズを格納します。まず固定ヘッダー:

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.

次は彫刻ファイルを削除します。これは、固定長フィールド、タイプ、およびチェックサムで構成されます。オプションもありますデータ部分長さサイズ。

最初になったのは幸運です彫刻レイアウトは常にIHDR次のようになります。

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

これから、バイト16-20と21-24のサイズを取得します。 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

Big Endian / Motorolaシステムでは、次の方法で寸法を直接印刷することもできます。

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

しかし、Little Endian/Intelではこれは容易ではなく移植性が良くありません。

これにより、次のようにbash + hexdumpスクリプトを実装できます。

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

しかし、これは直接的に効果的ではありません。より大きなブロック(75〜100バイト)が必要ですが、identifyかなり高速です。あるいは、Cでルーチンを作成すると、ライブラリ呼び出しよりも高速です。


JPEG:

それに関してはjpgそれほど簡単ではありません。また、次から始まります。署名ヘッダしかし、大小の塊固定オフセットではありません。タイトルの後ろ:

 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  ...

で始まる2バイトのタグで指定された新しいブロックが表示されます0xff。ディメンションに関する情報を保持するデータは価値がありますが、0xffc0データにかなり埋もれている可能性があります。

つまり、ジャンプブロックサイズバイト、チェックマーク、スキップブロックサイズ正しいタグが表示されるまでバイト、タグの読み取りなどを実行します。

見つかった場合、サイズはオフセット3と5にそれぞれ2バイトとして格納されます。表示

 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.

いくつかのファイル(約10,000個のjpg画像)を確認するための簡単なCプログラムを書いています。約50%は最初の500バイト内のサイズ情報を持ち、ほとんどの50%は約10,000バイトの間にあります。 100と200。最悪の場合は約80,000バイトです。私たちが絵と呼ぶ絵は次のとおりです。

JFIF_SOF_graph


GIF:

しかし、GIF複数の画像を保存できることがよくあります。キャンバスヘッダーで指定されたサイズで、画像を収容するのに十分な大きさです。それは同じですパプアニューギニア、さらに発熱バイトも必要です: 10. 魔法とバージョンの後、我々は次元を探します。 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

つまり、最初の6バイトをチェックしてgifであることを確認し、次の4バイトを読み取ってサイズを判断できます。


その他の形式:

続けることもできましたが、今はここで止まります。

答え3

「識別」があるとします。これをスクリプトに入れてchmod +x <scriptname>実行すると、<scriptname> picture.jpg画像の高さと幅を取得できます。最初の2つの部分は画像が存在することを確認し、それをIMAGE変数に設定します。次の部分は、ファイルが実際に存在することを確認することです。最後の2つの部分は、「識別」出力から関連情報を取得して表示することです。

#!/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}"

答え4

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"

あなたfile://http://

関連情報