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 包的库,libMagickCore以及libMagickWand.这些看起来与同一堆东西相关联,所以如果你有的话,identify应该可以工作。

您不必下载整个图像来获取尺寸,因为这些尺寸位于文件开头的标题中,这就是我们所identify查看的内容。例如,我在这里将完整 jpeg 的前 4 kB 复制到新文件中:

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

4 kB 应该足以包含标头——我相信您可以用 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 个字节。似乎适用于很多pngjpg,然后使用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  ...

出现一个新块,由以 开头的两字节标记指定0xff。保存有关维度的信息的数据具有价值0xffc0,但可能会被埋藏在数据中相当多的位置。

换句话说,一跳块大小字节、检查标记、跳过块大小字节、读取标记等等,直到出现正确的标记。

找到后,大小将在偏移量 3 和 5 处各存储两个字节标记

 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.

编写了一个简单的 C 程序来检查一些文件,大约 10.000 张 jpg 图像,大约 50% 在前 500 字节内有大小信息,大多数 50% 在大约 10000 个字节之间。 100 和 200。最差的是 80.000 字节左右。一张图片,正如我们所说的图片:

JFIF_SOF_graph


动图:

尽管动图通常可以存储多个图像,它有一个帆布标题中指定的大小,这足以容纳图像。这就像巴布亚新几内亚,甚至需要发烧字节: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

换句话说,您可以检查前六个字节以查看它是否是 gif,然后读取接下来的四个字节以了解大小。


其他格式:

本来可以继续,但我想我现在就停在这里。

答案3

假设你有“识别”。将其放入脚本中并chmod +x <scriptname>.要运行它<scriptname> picture.jpg,您将获得图像的高度和宽度。前两部分是检查是否存在图像,然后将其设置为 IMAGE 变量。下一部分是确保该文件确实存在。最后两部分是从“识别”输出中获取相关信息并显示它。

#!/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://

相关内容