在 Linux 上使用 ImageMagick 命令行批量转换时出现错误结果

Broken results on batch convert with ImageMagick command line on Linux

这是我的 IM 命令:

/usr/bin/convert 
'src.tif'
  -limit memory 0
  -limit map 0
  -limit file 0
  -alpha transparent
  -clip
  -alpha opaque
  -resize 800x600
  'end.png'
2>&1

所以这将通过剪切文件中给定的路径来删除我的 TIFF 的白色背景。它将调整大小并保存为透明 PNG。

我从 IM 运行中没有收到任何错误。

但是如果我 运行 使用 PHP 这个命令对大约 13000 个文件执行它 - 我有时会遇到这些错误:

sh: line 1: 25065 Killed                  /usr/bin/convert \
            'public_html/source_files/XXXX123/XXXX123/XXXX123.tif' \
             -limit memory 0 -limit map 0 -limit file 0 -alpha transparent \
             -clip -alpha opaque -resize 800x600 \
            'public_html/converted/XXXX123/XXXX123/XXXX123_web.png' 2>&1

sh: line 1: 25702 Killed                  /usr/bin/convert \
            'public_html/source_files/XXXX123/XXXX123/XXXX123.tif' \
             -limit memory 0 -limit map 0 -limit file 0 -alpha transparent \
             -clip -alpha opaque -resize 800x600 \
            'public_html/converted/XXXX123/XXXX123/XXXX123_web.png' 2>&1

但更大的问题是:有些图片坏了。下面左边是 "bad" 图片,右边是 "good" 图片(ondrag/on 深色背景你看问题更清楚):

在 运行手动执行命令时,结果正常。只有在 运行 上,此 PHP 循环脚本才会提供损坏的结果。 ( PHP loop script )

我运行脚本是这样的:php55 run.phpfind 作为 shell 脚本的简单循环提供了相同的结果。

所以我在 IM discourse server 和 运行 2 台不同分布的机器上搜索,询问这个程序(Debian Wheezy,Ubuntu Server 14.04)

Note/EDIT 1: 运行终端中相同文件的命令提供了完美的结果。

编辑 2: 添加了示例 TIFF 文件 here

我不确定这是否是答案。现在这纯粹是猜测。所以这里...

通过将限制设置为 0 值,您基本上是在告诉 ImageMagick:"Your resources are not limited at all. You do not need to care for any limits."

  • 如果没有设置任何限制怎么办? 从命令中删除所有 -limit ... 0 部分.在这种情况下,ImageMagick 将使用其内置默认值或其他定义的设置(可能包含在 IM 安装的 policy.xml 文件中,或通过各种 环境变量)。您可以使用以下命令查询系统的当前限制:

    identify -list resource
    

    在我的系统上,我得到这些值:

    File       Area     Memory     Map       Disk  Thread  Throttle        Time
    ---------------------------------------------------------------------------
     192    4.295GB       2GiB    4GiB  unlimited       1         0   unlimited
    
  • 如果您确实将这些限制设置为合理的值,与您系统的实际可用资源相匹配,会怎样?假设您有:8 GByte 的 RAM,50 GByte 的可用磁盘 space 和磁盘卷上的大量可用 inodes。然后尝试这样设置:-limit disk 10GB -limit memory 3GB -limit map 6GB.


ImageMagick 资源管理

对于所有处理和中间步骤,ImageMagick 需要访问中间 像素缓存 memory/storage,然后才能提供最终结果。

这种对像素缓存存储的需求可以通过不同的资源来满足:

  • 堆内存,
  • 匿名内存映射,
  • 基于磁盘的内存映射,
  • 直接磁盘。

ImageMagick 逐步使用所有这些资源:

  • 堆内存用完后,它会将像素存储在匿名地图中。
  • 匿名内存映射用完后,它会在磁盘上创建像素缓存并尝试对其进行内存映射。
  • 一旦内存映射内存耗尽,它就简单地使用标准磁盘I/O。

磁盘存储很便宜但也很慢:它比内存慢 3 个数量级(一千倍)。通过使用内存映射到基于磁盘的缓存可以获得一些速度提升(最多 5 倍)。

ImageMagick 知道控制这些资源数量的各种方法:

  1. 内置默认值。这些限制是:768 个文件、3GB 图像区域、1.5GiB 内存、3GiB 内存映射和 18.45EB 磁盘 space.

  2. policy.xml 配置文件。请查看您自己的 policy.xml 文件中的内容。先用convert -list policy找到这个文件的位置。然后使用 cat /some/path/policy.xml 查看其内容。 (该文件使用 XML 语法。不要忘记:包含在 <!----> 中的任何内容都是注释!)它还包含解释各种细节的注释。 policy.xml 可以定义比可用限制资源更多的东西。 policy.xml 中的设置优先于内置默认值(如果在此处定义)。

  3. 环境变量。以下是可以限制 IM 资源的环境变量列表:MAGICK_AREA_LIMIT(图像区域限制),MAGICK_DISK_LIMIT(磁盘 space 限制),MAGICK_FILE_LIMIT(最大打开数文件限制)、MAGICK_MEMORY_LIMIT(堆内存限制)、MAGICK_MAP_LIMIT(内存映射限制)、MAGICK_THREAD_LIMIT(最大线程数限制)和 MAGICK_TIME_LIMIT(最大运行时间秒)。如果设置了这些环境变量,则优先于 policy.xml 配置文件。

  4. -limit <name> <value> 命令行设置。以下 <names> 被识别:

    • width(图像的最大宽度)。超过限制时,抛出异常并停止处理。
    • height(图像的最大高度)。超过限制时,抛出异常并停止处理。
    • area(任何单个图像驻留在像素缓存内存中的最大字节数)。当超过限制时,自动缓存到磁盘(可能是内存映射)设置。
    • memory(从匿名映射内存或堆中为像素缓存分配的最大内存)。
    • map(为像素缓存分配的内存映射的最大数量)。
    • disk(像素缓存允许使用的最大磁盘量 space)。超过限制时,不会创建像素缓存并抛出致命异常。
    • files(打开像素缓存文件的最大数量)。当超过限制时,缓存到磁盘的所有后续像素将关闭并根据需要重新打开。
    • thread(最大并行线程数)
    • time(允许进程执行的最长时间,以秒为单位)。当超出此限制时,将引发异常并停止处理。

    命令行上的 -limit 设置优先并覆盖所有其他设置。