【问题标题】:Bash script check if image is animated png (apng)Bash脚本检查图像是否为动画png(apng)
【发布时间】:2018-04-16 16:47:41
【问题描述】:

试图在我的 bash 脚本中找出一种方法来检查文件是否为动画 PNG (apng) 文件。就我而言,如果是,我想忽略它。有什么想法吗?

更新: 下面使用 pngcheck 的答案允许我检查图像是否是动画。此外,我检查文件的大小,如果它“大”,我也会忽略它。最后,截至 2017 年 11 月,“识别”不起作用,这主要是我最初的问题。感谢马克的帮助。

【问题讨论】:

  • .apng 还是.png
  • 这些图片的文件扩展名是否正确?例如,动画 png 是否总是以 .apng 结尾?一个通用的png会以.png结尾吗?另外,您在什么情况下检查文件?从stdin 读取ls -l 时这是在while 循环中吗?
  • 尝试运行file YourImage.pngfile YourAnimatedImage.png 看看它是否能区分。如果做不到这一点,请尝试pngcheck YourImage.png。如果做不到这一点,请尝试 ImageMagick identify YourImage.png 每帧只有一行 - 因此动画文件将有多行输出。
  • 我希望它是那么简单...。动画 png 文件可以包含:.apng 或 .png 文件扩展... ex。 apng.onevcat.com/assets/elephant.png
  • @MarkSetchell 很好的建议,我实际上尝试过,它似乎并没有真正帮助。我也尝试过 identify -verbose 但我不确定 apng 的独特之处

标签: bash shell animation


【解决方案1】:

动画PNG的特点是存在acTL(动画控制块)和fcTL(帧控制块) - 请参阅Wikipedia article

所以,我认为一个合适的测试是使用详细选项运行pngcheck,并至少查找acTL 块:

pngcheck -v animated.png | grep -E "acTL|fcTL"

样本输出

  chunk acTL at offset 0x00025, length 8
  chunk fcTL at offset 0x00039, length 26
  chunk fcTL at offset 0x02f27, length 26
  chunk fcTL at offset 0x05901, length 26
  chunk fcTL at offset 0x083a2, length 26
  chunk fcTL at offset 0x0aea8, length 26
  chunk fcTL at offset 0x0d98c, length 26
  chunk fcTL at offset 0x10406, length 26
  chunk fcTL at offset 0x12e19, length 26
  chunk fcTL at offset 0x15985, length 26
  chunk fcTL at offset 0x185e2, length 26
  chunk fcTL at offset 0x1b2b0, length 26
  chunk fcTL at offset 0x1dfe1, length 26
  chunk fcTL at offset 0x20d24, length 26
  chunk fcTL at offset 0x23a03, length 26
  chunk fcTL at offset 0x26663, length 26
  chunk fcTL at offset 0x29218, length 26
  chunk fcTL at offset 0x2bcdf, length 26
  chunk fcTL at offset 0x2e7e0, length 26
  chunk fcTL at offset 0x312b0, length 26
  chunk fcTL at offset 0x33c51, length 26
  chunk fcTL at offset 0x36598, length 26
  chunk fcTL at offset 0x38f49, length 26
  chunk fcTL at offset 0x3b9bd, length 26
  chunk fcTL at offset 0x3e45e, length 26
  chunk fcTL at offset 0x40ed9, length 26
  chunk fcTL at offset 0x4393c, length 26
  chunk fcTL at offset 0x46521, length 26
  chunk fcTL at offset 0x4919b, length 26
  chunk fcTL at offset 0x4bde2, length 26
  chunk fcTL at offset 0x4eabd, length 26
  chunk fcTL at offset 0x51827, length 26
  chunk fcTL at offset 0x5453a, length 26
  chunk fcTL at offset 0x571c7, length 26
  chunk fcTL at offset 0x59d94, length 26

所以,这将建议在脚本中进行此测试:

# Test an animated image, `grep` exit status is zero meaning `acTL` was found
pngcheck -v animated.png | grep -q "acTL"
echo $?
0

# Test a still image, `grep` exit status is 1 meaning `acTL` was not found
pngcheck -v still.png | grep -q "acTL"
echo $?
1

如果你没有,或者不想在你的项目中发送pngcheck,我制作了一个小 Perl 脚本,它只是对 PNG 文件进行分块并告诉你块和偏移量,它应该可以在任何地方运行因为它是 Perl。欢迎您使用。

样本运行

./pngchunks ball.png

13 IHDR
8 acTL                   <--- This one means it is animated
26 fcTL
4634 IDAT
26 fcTL
4344 fdAT
26 fcTL
4042 fdAT
26 fcTL
3828 fdAT
26 fcTL
3521 fdAT
26 fcTL
3168 fdAT
26 fcTL
2777 fdAT
26 fcTL
2588 fdAT
26 fcTL
2720 fdAT
26 fcTL
2792 fdAT
26 fcTL
2665 fdAT
26 fcTL
2581 fdAT
26 fcTL
2652 fdAT
26 fcTL
2774 fdAT
26 fcTL
2844 fdAT
26 fcTL
2886 fdAT
26 fcTL
2966 fdAT
26 fcTL
3197 fdAT
26 fcTL
3518 fdAT
26 fcTL
3995 fdAT
0 IEND

#!/usr/bin/perl -w
################################################################################
# pngchunks
# Mark Setchell
#
# Simple Perl tool to read the chunks in a PNG image file
# See https://en.wikipedia.org/wiki/Portable_Network_Graphics
#
# Usage: pngchunks image.png
################################################################################
use strict;
use Fcntl qw( SEEK_CUR );

my $f=shift or die "Usage: pngchunks image.png\n";

my ($handle,$offset,$buffer,$type,$length);

# Open file
open($handle,'<',$f) || die("Error opening file\n");

# Check 8 byte PNG signature
read($handle,$buffer,8);
if(substr($buffer,0,8) ne "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a"){
   die("ERROR: Invalid PNG signature\n");
}

# Loop till IEND chunk
for(;;){

   # Read 4 bytes of length, Network (big-endian)
   read($handle,$buffer,4);
   $length=unpack("N",$buffer);

   # Read 4 bytes of chunk type
   read($handle,$buffer,4);
   $type=substr($buffer,0,4);

   printf("%d %s\n",$length,$type);

   # Break out of loop if IEND chunk
   last if $type eq "IEND";

   # Seek past this chunk and its 4 byte CRC
   $offset=4+$length;
   seek($handle,$offset,SEEK_CUR);
}

【讨论】:

  • 谢谢!需要注意的是,截至 2017 年 11 月,“Identify”并未列出此信息。你已经超越了!我在 AMI 实例中使用它,遗憾的是 pngcheck 命令似乎丢失了,所以我使用的是旧的 RPM。
【解决方案2】:

首先使用expr提取文件的扩展名。

查看http://tldp.org/LDP/abs/html/string-manipulation.html:

expr match "$string" '.*\($substring\)'

$string 的末尾提取$substring,其中$substring 是一个正则表达式。

然后将提取的扩展名与“.png”进行比较

【讨论】:

  • 不,我不只是需要检查它是否有 ext ,这还不够好......您可以使用 ext="${file_name##*.} "
【解决方案3】:

我没有看到一个“好”的方法来做到这一点,所以我要作弊。首先,我的尝试:

两个测试图像:一个elephant 和一个ball。它们实际上很让人分心,所以我会让你单独打开它们,而不是把它们放在这里(我只是盯着它们呆了整整一分钟)。

为简单起见,我们将它们重命名为 elephant.apngball.apng

$ file elephant.apng ball.apng
elephant.apng: PNG image data, 480 x 400, 8-bit/color RGBA, non-interlaced
ball.apng:     PNG image data, 100 x 100, 8-bit/color RGBA, non-interlaced

$ file -b --mime-type elephant.apng ball.apng
image/png
image/png

$ identify elephant.apng ball.apng
elephant.apng PNG 480x400 480x400+0+0 8-bit sRGB 379KB 0.000u 0:00.000
ball.apng PNG 100x100 100x100+0+0 8-bit sRGB 65.6KB 0.000u 0:00.000

$ strings elephant.apng |grep -i png
APNG Assembler 2.8Q\

$ strings ball.apng |grep -i png

$

所以 libmagic(文件 5.32,没有选项或通过请求 MIME 类型)并用 grep(GNU grep 3.1)识别(ImageMagick 6.9.7-4)和字符串(GNU Binutils 2.29.1)都找不到任何东西除了APNG Assembler留下的水印,不能保证。


现在让我们作弊吧。我将假设大量熵意味着它是一个动画 PNG(而不是其他东西,比如 steganographic message),只需通过 ImageMagic convert 运行它以将其转换为标准 PNG:

$ convert elephant.apng elephant.png
$ convert ball.apng ball.png
$ wc -c *
 65557 ball.apng
  5239 ball.png
379013 elephant.apng
 21068 elephant.png
470877 total

好的,我们可以解决这个问题:

#!/bin/sh

for image in "$@"; do
  size1="$(wc -c "$image")"
  size2="$(convert "$image" -format PNG - |wc -c)"
  if [ "$size1" -ge "$((size2*2))" ]
    then echo "$image: Animated or steganographic PNG"
    else echo "$image: Basic PNG"
  fi
done

这会将size1 设置为以字节为单位的图像大小(使用wc -c 来获取字符数),然后将size2 设置为将图像“转换”为PNG 后的大小(@987654335 @ 告诉 convert 将最终图像推送到标准输出,wc 将其读入)。如果size1 至少是size2 的两倍大,那么我们假设它是一个动画PNG。

这是一个循环,因此您可以在任意数量的图像文件上调用它(即使是非 PNG,虽然这没有多大意义,而且您总是会被告知它是某种 PNG)。请注意,您不能通过管道输入它,因为它会在第一次 wc 调用时吸收标准输入,并且没有任何剩余可用于转换。


如果您安装了MediaInfo(例如apt install mediainfo),您可以(暂时!)使用此命令检测出问题:

$ mediainfo elephant.apng |grep ^FileExtension_Invalid
FileExtension_Invalid                    : png pns

$ mediainfo ball.apng |grep ^FileExtension_Invalid
FileExtension_Invalid                    : png pns

我不确定这意味着什么,但它不会显示在我转换的 PNG 上,所以它可能是安全的……至少在 MediaInfoLib 真正支持 APNG 文件格式之前(这是为什么我说“暂时”)。这至少在 v0.7.99 中有效。

grep -q 的身份调用以使您的if 测试保持沉默。

【讨论】:

    猜你喜欢
    • 2013-08-20
    • 2013-08-16
    • 2011-06-09
    • 2019-01-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-14
    • 1970-01-01
    相关资源
    最近更新 更多