ImageMagick 示例 -- 基础用法
这里我们将详细解释 IM 所遵循的命令行处理流程、一些新的图像处理能力、相关理念、设计哲学与方法论,以及内部实际发生的过程。有了这些背景知识,后续示例页面的内容就会清晰得多。即使你只使用应用程序接口(API),这一节也非常值得了解和理解。
ImageMagick 命令行处理
命令行风格为何会改变!或者说……
旧版本 IM 存在的问题
在以前的主要版本中(5.5.7 及更早),进入 IM 库的命令行接口很容易出现与操作执行顺序相关的问题。它非常杂乱无章,让任何试图弄清楚到底发生了什么的人都感到困惑。而且,某次能正常工作的写法,换一种顺序可能就不行了;IM 的作者一直在与这个接口搏斗,努力让它按人们预期的方式工作。问题的根源在于 ImageMagick 遵循了一种相当标准的 UNIX 命令行风格……
**command [options] input_image output_image**
随着时间推移,这开始产生问题,因为图像是复杂的对象,可以对其执行数量庞大的操作,而且这些操作往往还涉及其他图像。因此上面的形式慢慢扩展成了……
**command [options] image1 [options] image2 [options] output_image**
这种方式可以工作,也是 5.5.7 版本所用的基本风格。诸如 "[-negate](https://imagemagick.org/command-line-options/#negate)"、"[-resize](https://imagemagick.org/command-line-options/#resize)"、"[-crop](https://imagemagick.org/command-line-options/#crop)" 等各种图像操作,可以出现在它所要应用的图像之前或之后。例如在 5.5.7 版本下,下面两条命令同样有效,并且做的是同一件事。
magick -negate image.gif output.gif
magick image.gif -negate output.gif
问题在于:如果你要处理两个图像处理操作怎么办!例如……
magick -size 40x20 xc:red xc:blue \
-append -rotate 90 append_rotate.gif
其结果(在 IM v5.5.7 中)是两幅输入图像先被旋转,然后才拼接在一起,生成的图像像这样……也就是说,"[-rotate](https://imagemagick.org/command-line-options/#rotate)" 操作符会在 "[-append](https://imagemagick.org/command-line-options/#append)" 之前被应用,而这很可能不是用户想要的结果。
从 ImageMagick 版本 6 开始,操作符将始终按用户在命令行中给出的顺序应用。
因此,前面那个示例在 IMv7 中将得到:两幅图像 先 被拼接在一起,然后对该结果进行旋转;生成这样的图像……
如果用户确实想在拼接之前先做旋转,他可以明确要求 IM v6 按那个顺序执行。
magick -size 40x20 xc:red xc:blue \
-rotate 90 -append append_rotate_bad.gif
这种精细的控制是旧版本 IM 完全做不到的,要实现它很可能需要用到管道,或者保存中间图像。不幸的是,解决这个问题需要采取激进的措施,并带来一些不兼容性。另一方面,几乎所有在 IM 版本 5 中能工作的“简单”命令,在 IM 版本 6 中仍能如你所料地工作。本质上,版本 6 之前的命令行用法定义不清,在我看来是有缺陷的,会产生大量奇怪和意外的结果。
IMv7 命令语法
注意,在至少读入或创建了一幅图像之前,不应给出任何“操作”。事实上,你不妨把“读入/创建图像”也看作一种操作。毕竟它确实是一项图像处理操作——把文件中的图像转换为内存中的图像。所以在 IMv7 中正确的做法是:读入图像、处理,然后用最后那个“隐式写出”参数把结果写出。也就是……
**command "image" { -operation }... "output_image"**
当然,有些设置需要在实际读入图像之前给出,用以控制图像的读取(关于“设置”的含义见下文)。因此 IMv7 语法 基本遵循如下形式……
**command { [settings] [operation] }... "implict_write"**
其中 '{...}' 部分会按你想要或需要的“读入”或“操作”次数重复。而 '[operation]' 既可以是一次图像读入或创建,也可以是真正“做点什么”的图像处理操作。你要按照希望处理图像的确切顺序来排列它们。
选项的类型——操作符与设置……
下面内容的摘要现在也可以在 ImageMagick 官网 的 命令行剖析 页面找到。所有命令行选项现在都归入两大基本类别:“设置”和“图像操作符”。设置用于设定值,操作符则实际执行某些动作。 设置型选项(Setting Options)
| 是仅保存信息的命令行选项,这些信息稍后会被其他“图像操作符”使用。也就是说,它们除了设定某个值供以后使用外,什么也不做。许多选项同时有 '-' 和 '+' 两种形式。后者通常用于关闭该设置,或将其重置为正常的默认状态。这让你能够快速简单地消除某个设置的效果。例如 "[+gravity](https://imagemagick.org/command-line-options/#gravity)" 会把重力(gravity)设置恢复到初始的 'gravity none' 状态。设置还可以进一步细分为若干子类别…… 操作符设置(Operator Settings),用于控制后续操作符的工作方式。它们设定操作符可能用到的颜色和字体,控制图像和文本的摆放位置,从源图像中查找颜色,控制某些更复杂操作符的处理方法,等等等等。
-dither -gravity -fill -background -bordercolor -stroke -font -pointsize -strokewidth -box -virtual-pixel -interpolate
大多数设置型选项都属于这一类别。 输入设置(Input Settings) 专门用于控制所创建或读入图像的生成。它们通常用于为该设置定义之后所创建(或从外部文件读入)的图像赋予或覆盖特定的元数据。
-label -delay -dispose -page -comment -size
请记住,它们只在图像被创建或读入时才生效,否则会被完全忽略。专门提供了特殊操作符 "[-set](https://imagemagick.org/command-line-options/#set)" 用于在图像已被读入内存或经过某种处理之后修改其元数据。更多细节见下文 元数据。 输出设置(Output Settings),仅在把图像写出或保存回磁盘时使用。它们虽然可以在命令行的任何位置给出,但只在写出图像时才被应用——无论是作为默认的最后一个图像文件名参数操作,还是通过 "[-write](https://imagemagick.org/command-line-options/#write)" 或 "[-identify](https://imagemagick.org/command-line-options/#identify)" 操作。
-quality -loop -compression -format -path -transparent-color
如果未设置或被关闭(使用其加号 '+' 形式),将使用适当的默认值。通常这个默认值是从最后读入的图像中保存下来的值。某些“操作设置”(例如当前的 "[-background](https://imagemagick.org/command-line-options/#background)" 颜色)在文件格式需要时也会被赋给图像。 控制与调试设置(Control & Debugging Settings),用于控制 IM 总体上如何执行其任务。包括……
-verbose -debug -warnings -quiet -monitor -regard-warnings
关于这些特殊设置的更多信息,见下文 IM 操作控制。
图像操作符(Image Operators)
| 是会以某种方式修改图像的命令行参数。它们在被看到时 立即 执行,并且可能会用到此前在命令行中给出的“设置型选项”。这些操作符可分为若干子类别…… 图像创建操作符(Image Creation Operators),会从文件或管道读入图像,或生成新图像。包括……
image.png xc: canvas: logo: rose: gradient: radial-gradient: plasma: tile: pattern: label: caption: text:
作为“操作符”,它们在命令行中被看到时也会立即执行。它们只是把新图像添加到已在内存中的图像之后,而不会改动此前读入的图像。当然,作为操作符,此前定义的任何“设置”都会应用到它们身上,尤其是用于控制从文件或文件流输入的 输入设置。例如 "[-size](https://imagemagick.org/command-line-options/#size)",它提示你想创建的图像大小;或者定义、覆盖图像元数据的设置,如 "[-delay](https://imagemagick.org/command-line-options/#delay)" 和 "[-page](https://imagemagick.org/command-line-options/#page)"。 简单图像处理操作符(Simple Image Processing Operators) 会修改所有已读入内存的图像。每幅图像都与其他图像分开、各自被修改。它们包括如下操作……
`-crop -repage -border -frame -trim -chop -draw -annotate -resize -scale -sample -thumbnail -magnify -adaptive-resize -liquid-resize -distort -morpohology -sparse-color -rotate -swirl -implode -wave -flip -flop -transpose -transverse -blur -gaussian-blur -convolve -shadow --radial-blur -motion-blur -sharpen -unsharp -adaptive-sharpen -adaptive-blur -noise -despeckle -median -negate -level -level-color -gamma -auto-level -auto-gamma -sigmoidial-contrast -normalize -linear-stretch -contrast-stretch -colorize -tint -modulate -contrast -equalize -sepia-tone -solarize -recolor -opaque -transparent -colors -map -ordered-dither -random-dither -raise -paint -sketch -charcoal -edge -vignette -emboss -shade -poloroid -encipher -decipher -stegano -evaluate -function -alpha -colorspace -separate
以及大概还有许多我遗漏的(或新增的)操作符!`
因为所有图像操作符在命令行中被看到时就会立即执行,所以它们必须给在它们所要操作的图像 之后,也就是这些图像已被读入内存之后。如果存在多幅图像,则 所有 图像都会被操作,按顺序一幅接一幅地处理。因此你必须留意当前图像列表中有哪些图像。注意,其中某些操作符有可能生成多幅图像。例如 "[-crop](https://imagemagick.org/command-line-options/#crop)" 可能生成多幅图像“瓦片”,又如 "[-separate](https://imagemagick.org/command-line-options/#separate)" 会把图像拆分成各个独立的通道图像。因此你内存中最终可能会有更多图像。但它们每个都只以一幅图像为输入。注意,许多 API 只把等效操作应用于给定图像列表中的第一幅图像,也就是说它们可能不会遍历每一幅图像。然而 "magick" 和其他 CLI(命令行接口)命令会依次把操作符应用于当前图像列表中的每一幅图像。 多图列表操作符(Multi-Image List Operators) 比较特殊,它们把整个当前图像列表当作单一实体来修改。它们可能把整个列表替换为单一的合并图像,或者根据其前后的其他图像来修改每幅图像。它们用于 alpha 合成、动画处理、颜色通道处理等……
-append -flatten -mosaic -layers -composite -combine -fx -coalesce -clut -evaluate-sequence mean -evaluate-sequence
请记住,整个列表被当作单一实体处理,某些图像可能被移除或替换。上述大多数操作符会把给定的多幅图像合并为最终的单一图像。图层合成(Layers Composite) 方法是目前唯一一个会先把当前图像列表拆分成两个完全独立的图像列表,再将它们合并以构成全新图像列表的操作符。它通过在当前图像列表中查找特殊的 'null:' 图像来进行拆分。这些操作符都不能用于 "[mogrify](#mogrify)" 命令,因为该命令把(在末尾给出的)输入图像列表当作一个个独立的图像来处理。 图像栈操作符(Image Stack Operators) 会影响当前内存中图像列表的排列顺序。具体来说,它们提供对图像的特殊“侧旁”处理。它们在许多方面类似于前面的 图像列表操作符,但它们并不实际修改图像本身,只改变图像在内存中的排列方式。
( ) -delete -insert -swap -reverse -duplicate -clone
注意,圆括号 '(' 和 ')' 可能需要转义或加引号,以防命令行 shell 接口(CLI)赋予它特殊含义。这些操作符都不能用于 "[mogrify](#mogrify)" 命令,因为该命令把(在末尾给出的)输入图像列表当作一个个独立的图像来处理。 杂项特殊操作符(Miscellaneous Special Operators) 是以异常或非标准方式(相比上述各类)执行任务的操作符。
-geometry -version -list -bench -concurrent -preview
"[-geometry](https://imagemagick.org/command-line-options/#geometry)" 操作符很特殊,因为它是唯一一个只影响图像列表中某一幅图像(最后一幅)、而非以某种方式影响所有图像的操作符。它仅出于向后兼容和特殊的 alpha 合成需求而提供。详见 Geometry,仅调整最后一幅图像的大小。另外两个,"[-version](https://imagemagick.org/command-line-options/#version)" 和 "[-list](https://imagemagick.org/command-line-options/#list)",是生成信息的操作符,会在返回所请求的信息后让 IM 显式退出。关于这些选项的更多信息,见下文 IM 特殊控制。某些选项甚至可能导致整条命令被运行多次。基本上它们是以某些奇特而异常的方式被特殊处理的。一般情况下,除非在特殊场合或为了获取某些全局信息,否则不会用到它们。
我希望把选项区分为设置和操作符这一点已经讲清楚了,因为它对于理解 IM 现在的工作方式至关重要。请记住,在 ImageMagick 版本 6 中……
设置会以某种方式被 保存 起来供以后使用,
而操作符则会 立即 应用于图像。
这正是版本 6 与之前每个 IM 版本不同的地方。所有选项都被定义为“设置”或“操作符”,其顺序将精确决定该选项在何时、应用于哪些图像。可以用 IM 示例选项参考 来识别什么是“设置”、什么是“操作符”。
IM 命令的实际示例
让我们看一个示例,以及 IM 版本 6 是如何处理它的。 |
magick eye.gif news.gif -append storm.gif tree.gif \
-background skyblue +append result.gif
![[IM Output]](../static/img/basics/result.gif)
让我们拆开来看看 IM v6 做了什么…… 参数 | | 执行的动作 | 图像
---|---|---|---
magick | 初始化并创建一个空的“图像列表” | 空序列
eye.gif | 读入图像并添加到当前图像列表末尾 | 1 幅图像
news.gif | 把第二幅图像加入列表(现在有两幅图像) | 2 幅图像
-append | 取当前列表中的所有图像,纵向拼接。
所有图像被替换为单一图像。 | 1(已合并)
storm.gif | 向图像列表添加另一幅图像 | 2
tree.gif | 再添加一幅 | 3
-background skyblue | 设定一个“背景色”供以后使用。
不对任何图像做改动。 | 3
+append | 把列表中的全部 3 幅图像横向拼接
当前背景色用于填充空白处 | 1(已合并)
result.gif | 由于这是最后一个参数,会以此参数执行一次隐式的 -write 操作。当前列表中的单一图像将以给定文件名写出,文件名同时也决定了所用的图像文件格式。 | 已写出
如你所见,ImageMagick 版本 6 对命令行的处理非常直接、合乎逻辑,使结果可预测。而这正是关键所在……
遗留命令行风格
由于外面有大量非常旧的 IM 脚本使用如下形式的、带单个图像操作符的命令……
**command -operator input_image output_image**
也就是说,你在实际读入操作符所要应用的图像之前就指定了该操作符。为处理这种遗留情形,IM 会把它看到的所有图像操作符都暂存起来,并在命令行上最终遇到第一幅图像时把它们应用到该图像。也就是说,上述写法会像你按 IMv7 方式书写那样工作……
**command input_image -operator output_image**
例如,这条 IMv5 遗留风格(UNIX 选项处理)命令…… |
magick -flip storm.gif cmd_flip_legacy.gif
magick storm.gif -flip cmd_flip_postfix.gif
![[IM Output]](../static/img/basics/cmd_flip_postfix.gif)
遗留命令行风格能工作,但存在困扰 IM 版本 5 的同样问题(见上文 命令行风格为何会改变)。所有设置都在第一次读入之前应用,而所有操作符只是被暂存起来,等到第一幅图像被读入时才执行(且只作用于第一幅图像)。此外也无法保证多个操作符的执行顺序与你给出的顺序一致,尽管它们很可能按那个顺序应用。还有,由于操作符会被暂存直到第一幅图像被真正读入,你可能会发现:在读入图像之前多次重复某条命令,可能会导致较早的某些命令“消失”。这不是 bug,而是对 IM 遗留能力的误用。这种命令行风格仅用于遗留支持,因此已被弃用,应尽可能避免使用。任何包含这种旧风格的脚本,也应更新为先读入图像,再应用你想要的操作符。 | 遗留支持将延续到 IM 版本 7,其中包含一个允许对命令行进行单遍处理的命令。这使它能够真正从脚本文件甚至管道中读取图像处理选项。但单遍处理技术不允许在读入图像之前就暂存操作符以备应用。事实上,如果你试图在内存中没有图像时使用某个操作符,"magick" 命令会产生“no image”类型的错误。
---|---
命令行与 API
命令行版的 IM 与使用 Magick API(如 PerlMagick、RMagick、PHP IMagick、MagickWand)之间有几个主要区别。
- 只有一个活动的图像列表
- 命令行在任一时刻都只有一个可供操作的图像列表。你可以临时“压入”或保存一个图像列表(见 圆括号 和 MPR:命名内存寄存器)。你甚至可以“克隆”(高效复制)最后“压入”列表中的图像。但你不能真正同时操作两个这样的列表。而其他语言的 API 则允许你拥有任意多个独立的图像列表或“wand”。事实上,你通常会把每幅图像作为一个单独的 wand(图像列表加设置)保存起来以便更好地处理,并仅在需要时、或作为最后一步,才把图像合并进列表。你还可以按任意顺序处理它们,把它们存进数据库或其他数据结构以便排序或日后比较。而在命令行上,单一图像列表意味着你不能以任意顺序做操作,而通常要按更合乎逻辑的顺序,边走边完整地完成每一个图像处理步骤。基本上这意味着“回退”或日后修改某些东西要困难得多——比如用一组操作的结果来选择或修改接下来应执行的处理操作。尤其是把两个完全独立的图像列表合并或交错(洗牌)成一个逻辑整体会更困难。不过,已经摸索出一些技术,让你能够从命令行做到这些。例如见 图像列表的多层 Alpha 合成。
- 对像素数据的直接访问
- 同样,你可以从命令行做一些数学处理以及对像素数据的合并,但你无法用命令行接口轻松地查询属性、读取或修改特定像素或区域。你可以用特殊的 FX 图像操作符 来合并图像并对其像素数据做数学修改,但它一般仅限于对整幅图像做变换,而且非常非常慢。为了让事情更简单,许多用户使用 FX 操作符开发出的常用操作如今已内建到 IM 中,形成诸如 颜色查找表、Evaluate 数学函数、多参数函数,还有 通用图像扭曲操作符,以及一些特殊的 图像合成方法。API 能以更直接的方式操纵图像,让你能够更容易地自行实现某个独特操作,并以 API 语言所提供的全速运行。
- 条件处理
- IM 命令行接口无法轻松地基于某个由图像派生出的属性来修改图像。例如,要根据图像使用浅色背景还是深色背景来分别处理,非常困难。是的,你可以用 FX 图像操作符 做一些有限而特定的条件动作,或者让 IM 根据某些条件调整(旋转)图像的 方向,或者在 调整图像大小 时只缩小而绝不放大。但这些只是处理一些特定且常见、众所周知的处理条件。要做条件处理,真正可行的唯一办法是使用分开的命令和临时文件。这方面的示例见有详尽注释的 拼图脚本。而 API 则能在把所有相关图像都保留在内存中的情况下做这类条件处理,随时准备根据具体条件继续处理。
- 循环处理
- 你也无法以受控方式简单地遍历图像,或者根据序列中正在处理的是哪一幅图像来轻松地改变处理过程。也就是说,你无法仅根据图像的“场景”编号或先前图像的结果,对每幅图像做不同的处理。例如以不同大小绘制文本、逐渐模糊一幅图像,或在单条命令中生成一个动画列表。是的,你可以修改图像列表中的特定图像。例如见 对动画逐帧修改。但你必须知道图像列表中有多少幅图像,并把循环“展开”,对列表中的每幅图像分别处理。从命令行循环处理图像,真正可行的唯一办法是把各幅图像作为独立的图像文件写出(见 写出多幅图像),然后在外部脚本循环中逐一处理它们。例如见用于 将图像纵向切分 的 shell 脚本。或者,你可以用 shell 脚本循环生成各幅图像,并把结果通过管道送入最后一条命令,将它们合并为最终图像或图像序列。这方面的示例见 分层图像示例,或各种 扭曲图像动画 的 shell 脚本生成器。而 API 处理多幅图像的循环则毫无问题,无论是在单个图像列表中、多个图像列表中,甚至是一整个由图像列表构成的数组或数据结构中。它还能把所有图像保留在内存中,随时准备进行最后的合并步骤,而无需管道或临时文件。
如果你的应用需要做这些事情中的任何一项(尽管很少有应用真的需要做到这一步),那么 API 可能是更好的选择。"[magick conjure](#conjure)" 程序(见下文)最初的设计目的就是允许更好地以脚本方式使用 ImageMagick,支持使用多个图像列表。IM v7 "magick" 所做的改进使得这个实验性 API 渐渐废弃不用,不过它仍然可用,并且仍在开发中。
参数处理
除了命令行上的文件名和选项之外,所用的选项参数只有几种基本样式。
- 常量名(用于特定的设置和方法类型)
- 常量名列表(例如两种颜色,或多个通道)
- Geometry 参数(一种带标志的、特殊格式化的数字列表)
- 浮点数列表(有时带 百分号转义)
- 自由格式文本字符串(带 百分号转义)
常量名
常量名是特定的字符串常量,用于在内部库中查找某个选项可能使用的允许设置。例如,"[-gravity](https://imagemagick.org/command-line-options/#gravity)" 设置可以取九种不同设置中的任意一种。一旦设定,该设置随后会被命令行中位于该设置之后的所有图像处理操作符使用。例如:'North'、'East' 或 'NorthEast' 等设置。你可以用 列表操作选项(见下文)获取所有有效设置的清单。例如使用命令……
magick -list gravity
只允许这些特定的设置,如果你试图使用其他设置,会得到一个错误。例如……
magick xc: -gravity Invalid null:
该设置可以用多种不同方式指定,全都完全有效。IM 对此非常宽容。例如,一个设置可以用大写、小写或两者的任意组合来指定。各个单词(在 "[-list](https://imagemagick.org/command-line-options/#list)" 输出中以大写字母标示)之间可以包含额外的空格、连字符或下划线,它们会被直接忽略(但仅限于单词之间)。因此,下面所有参数都能有效地把 "[-gravity](https://imagemagick.org/command-line-options/#gravity)" 设为 "North East"……
'`NorthEast`'、'`northeast`'、'`NORTHEAST`'、'`NorTheAst`'、'`north east`'、'`north-EAST`'、'`NORTH_EAST`'、'` North East `'、'`___North___East___`'。
但参数 'Nor The Ast' 无效,即使字母全部正确,因为它在该设置所声明的单词内部使用了空格。这些常量名不仅用于设置,也用于声明某些更复杂的图像处理操作符中要使用的操作方法,例如 "[-layers](https://imagemagick.org/command-line-options/#layers)"、"[-distort](https://imagemagick.org/command-line-options/#distort)" 和 "[-morphology](https://imagemagick.org/command-line-options/#morphology)"。某些常量名是从外部配置文件读取的。例如用于 "[-fill](https://imagemagick.org/command-line-options/#fill)"、"[-stroke](https://imagemagick.org/command-line-options/#stroke)"、"[-background](https://imagemagick.org/command-line-options/#background)" 和 "[-mattecolor](https://imagemagick.org/command-line-options/#mattecolor)" 的颜色名。又如用于 "[-ordered-dither](https://imagemagick.org/command-line-options/#ordered-dither)" 的特殊“阈值”映射图。同样,可以用 "[-list](https://imagemagick.org/command-line-options/#list)" 来查找你当前安装的 IM 版本所知道的名称。
常量名列表
这是一种较少使用的参数,最常用于需要一两种颜色的设置中,例如 按颜色进行级别调整。"[-level-colors](https://imagemagick.org/command-line-options/#level-color)" 选项可以接受以下任意一种参数样式。
color color1,color2 color1-color2
它也用于图像选择,即用于那些使用多个图像索引的操作,例如 Duplicate 和 Clone。索引从零开始表示第一幅图像,而负索引可用于表示从图像列表末尾开始计数的图像索引。例如 '-2-1' 表示取倒数第二幅图像(索引 '-2')到第二幅图像(索引 '1')。是的,这实际上意味着按指定顺序的相反顺序取图像!另一个大量使用这种形式的选项是 通道选择,你可以指定一个具名通道的列表。例如:'Red,Green,Blue,Black,Alpha'。不过 通道设置 也可以用一串单字母的简写形式(例如:'RGBA')
Geometry 参数
这是最常见的选项参数形式,通常用于为各种操作指定尺寸、矩形和偏移量。但它也被任何需要 1 到 5 个数字列表的选项使用,无论这些数字是整数还是浮点数。例如,"[-crop](https://imagemagick.org/command-line-options/#crop)" 和 "[-resize](https://imagemagick.org/command-line-options/#resize)" 等选项会使用 geometry 参数的完整语法,而 "[-border](https://imagemagick.org/command-line-options/#border)"、"[-level](https://imagemagick.org/command-line-options/#level)" 和 "[-gamma](https://imagemagick.org/command-line-options/#gamma)" 等选项可能只使用完整 geometry 语法的一小部分。这类参数太常见了,以至于专门编写了一个特殊(且复杂)的解析器,把这类字符串参数转换为数字和标志,供任何需要 geometry 参数的操作符使用。geometry 参数基本上允许用户用单个字符串参数指定多达 5 个浮点值(尽管大多数操作符只使用整数)。下面所有字符串形式都能被 geometry 参数解析器理解……
WxH+X+Y WxH +X+Y A A/B/C A,B,C,D,E
用户可以用上述任意一种形式来指定这一小串数字,但通常使用哪种形式取决于该参数所用于的操作。前几种通常用于指定一个具有特定大小和位置的矩形,或者仅仅是某种用途的偏移量。偏移量总是被解码为不同的数字,即字符串中 'x' 两侧的那些数字。也就是说,"+X+Y" 总是被解码为第 3 个和第 4 个数字,同时它标志着第 1 个和第 2 个数字未定义(或为零)。后几种形式最多允许 5 个可能的输入值,通常用于为标准 RGBKA 图像通道各自指定一个值。除这些数字之外,解析器还会报告是否存在任何特殊的“标志”字符('%'、'^'、'!'、'<'、'>' 中的任意一个)。然而解析器只报告这些字符是否存在,并不报告它们在参数中出现的位置。例如 IM 不会记住 '%' 是附着在某个特定数字上的。它也不报告该字符是否多次出现。这意味着 geometry 参数 '%50' 与 '50%' 含义完全相同,不过后者更易读,因而更受推荐。同样,'50%x30' 很可能实际上表示 '50%x30%',而 不是 你可能以为的“宽度的 50%、高度 30 像素”。 | _由于 geometry 参数可以包含特殊的 '%' 标志,你目前不能使用 百分号转义 来根据图像属性设定其值。
有一个 未来提案 讨论了百分号转义究竟应在何时展开,这可能会修复 geometry 参数的这个问题,并且有望成为 IMv7 的一部分。
浮点数列表
如果需要超过 5 个浮点数,甚至是数量未知的值,那么就使用 浮点数列表 参数;不过目前这类参数一般由各个选项各自解析,因为它们在不同选项之间可能略有差异。一般而言,它们由一个(通常加引号的)字符串组成,其中是以逗号或空格分隔的浮点数。Distort 操作符 大概是最广为人知、会使用浮点数列表的操作符。其他还包括 用户自定义形态学与卷积核,不过它还有专门用于定义数字数组(核)的额外语法。"[-sparse-color](https://imagemagick.org/command-line-options/#sparse-color)" 使用了浮点数的一种变体,允许你用颜色替换某些浮点值。在内部,当结果数组传入核心库函数时,这些颜色仍会被转换为浮点值。
自由格式字符串
另有一些选项只接受字符串作为参数,用于生成标签、标注文本,或保存为图像元数据。这些字符串通常会包含 百分号转义,它们会在字符串被使用之前的某个时刻被替换(替代)。这可能是即时替换,也可能是稍后、就在参数即将被实际使用之前才进行(见下文 延迟百分号转义)。
带百分号转义的参数
由于其性质,上述最后两类参数往往会被预处理,以便展开字符串中的 图像属性百分号转义。这意味着特定的字符序列会被展开(字符串替换或替代)成某个其他字符串,或者从正在处理的图像中查找或计算出来的某个值。这通常就在参数即将被操作符实际应用到某幅具体图像之前进行,以便能够使用该图像特有的设置。如果某个参数允许使用百分号转义,你也可以改为在参数前加上 '@' 前缀,从而让整个参数改为从给定的外部文件(或标准输入)读取。例如 '@filename' 会被替换为文件 'filename' 的内容。这种情况下,不会应用任何百分号或其他特殊转义。也就是说,从文件读取的字符串将被当作字面内容,原封不动地使用。 |
警告:那个文件可能是任何东西,包括程序可读的系统文件和密码文件。因此,网络用户应预先检查输入字符串是否属于这种特殊情况,或者更好的做法是把该字符串用 '@filename' 子句喂给 IM,作为一种安全措施。 |
|---|---|
如果字符串不是从文件或输入流读取的,那么其中任何 '\n' 字符串都会被替换为“换行”字符,任何以 '%' 为前缀的标签都会被替换为相应的值。完整的替换列表见 图像属性百分号转义。在参数中使用百分号转义,意味着对于越来越多允许使用此类转义的操作符(例如 "[-set](https://imagemagick.org/command-line-options/#set)"、"[-sparse-color](https://imagemagick.org/command-line-options/#sparse-color)"、"[-distort](https://imagemagick.org/command-line-options/#distort)" 或 "[-morphology](https://imagemagick.org/command-line-options/#morphology)"),你可以基于各种图像属性和元数据来生成参数。ImageMagick 版本 7 允许在几乎 每一个 参数中使用百分号转义(这是 IMv7 的一项关键特性!)。不仅如此,你甚至可以根据图像的内容或索引计算出不同的参数!你甚至可以使用逐图像的或预定义的全局设置,预先计算出一些复杂的设置。 |
在 IM v6.6.9-0 之前,百分号转义,更具体地说是涉及图像索引的 FX 百分号转义,例如 '%p'、'%n'、'%[fx:t]' 和 '%[fx:n]',都是有问题的。它们通常只返回无用的值 '0' 或 '1',而非当前图像列表中实际的图像索引和图像数量。 |
| --- | --- |
延迟百分号转义
注意,对于某些设置型选项,百分号转义 不会在被看到时立即展开,而是按给定的样子直接存储。只有在文本被实际使用时、当最终确定它们将与哪幅图像一起使用时,字符串中出现的任何 百分号转义 才应被展开。也就是说,这些参数必须把 百分号转义 的替换延迟到参数被实际使用时。这些选项包括 输入设置,例如:"[-label](https://imagemagick.org/command-line-options/#label)"、"[-comment](https://imagemagick.org/command-line-options/#comment)",以及 "[-format](https://imagemagick.org/command-line-options/#format)" 设置和全局 "[-define](https://imagemagick.org/command-line-options/#define)" 值。这意味着你可以在某幅图像被实际读入之前很久,就为它指定一个包含图像专属 百分号转义 的 "[-label](https://imagemagick.org/command-line-options/#label)"。只有当标签被真正附加到图像上时(在图像被读入之后),百分号转义 才会展开,从而能够利用它所要应用到的那幅图像的属性。 | _更广泛地使用百分号转义的主要限制在于,它目前只应用于有限的一组选项参数。例如我们目前不能在 Geometry 参数 中使用它们,因为后者也使用“百分号”字符,但用于不同的目的。
这个问题是 IMv7 将要修复的主要问题之一。_
---|---
ImageMagick 命令
虽然这些 ImageMagick 示例页面的大部分都使用 "magick" 命令来处理图像,但还有许多其他 ImageMagick 命令,我将在这里简要介绍。不过其中某些命令无法在网页上恰当地演示。即便如此,我仍会尽量在这里给出涉及这些命令的提示与技巧,哪怕我无法在此直接展示它们的输出。
Convert -- 转换和修改图像
"magick" 命令是 ImageMagick 的主力,因此这些页面中几乎每一组示例都使用它。所以我不会在这里过多讲述该命令的用法,而是看一点历史。该命令在 IM 最初被创建时的初衷,是把图像从一种图像格式转换为另一种格式。事实上它至今仍用于此目的,这也是它被称为 "magick" 的原因。正因如此,该命令甚至可能不会把图像读入内存,而是使用 IM 本体之外的辅助 Delegate 程序直接完成转换。不过这种完全外部的方式随着时间推移和需求减少而逐渐废弃,只剩下用作读入和写出复杂图像文件格式的手段。在很长一段时间里,加入了一些额外的图像处理功能,以便在图像于格式之间(甚至同一格式之间)转换时对其做些小改动。这些起初一般是简单的选项,但到了 IM 版本 5,这些处理功能的使用已变得相当广泛,对 "magick" 命令而言,它已成为比图像转换重要得多的一面。随着选项增多、开始同时使用多个选项,选项的顺序开始产生奇怪而不可控的结果。在用户眼中,IM 在使用多个图像处理选项时变得不稳定、不可控,开始失宠。IM 版本 6 见证了图像处理从简单的“选项”风格切换到“边看边做”风格,结果图像处理能力变得稳定、可预测,IM 的命令行能力也变得有用了许多个数量级。因此,"magick" 如今与其说是把图像从一种格式“转换”为另一种格式,不如说是一个用于访问图像处理函数的命令行 API,可以用非常复杂的方式创建和修改图像,而无需图像处理学位,也无需用某种计算机语言(如 Perl、PHP 或 C)编程。当然,懂一些 shell 脚本知识会有帮助,尽管并非严格必需。
identify -- 打印 IM 所看到的图像细节
"identify" 命令旨在以简单而有用的方式返回关于图像的信息。默认情况下,它输出一个简洁的概要,列出图像的名称、文件格式、图像尺寸、虚拟画布尺寸与偏移、色深、内部格式类型,以及(若已知)图像在磁盘上的原始大小(以易懂的方式表示)。例如……
magick identify tree.gif
注意,上面结果中的 '8c' 不是该图像内的颜色数量(实际为 6),而是“伪彩色”调色板的大小(实际颜色数量见后面的示例)。还要注意,图像“虚拟画布”与实际图像大小相同且偏移为零,意味着它当前未被使用。加上 -verbose 这个 操作控制,将产生 IM 所知道的、或能够轻松计算出来的、关于图像的尽可能多的信息。这包括颜色统计、颜色计数、配置文件信息、图像的内部保存类型等等。不过请注意,这些输出真的非常…… verbose(冗长)!你可以用 "[-format](https://imagemagick.org/command-line-options/#format)" 设置以及 IM 特殊的百分号('%')转义来以特定方式获取和输出特定信息,以输出 图像属性。不过通常你需要把 EOL(UNIX 或 MacOSX 下的换行符)作为该参数的一部分指定出来(IM v6.8.5-8 起有改动)。例如你可以仅提取一幅图像内的颜色数量。
magick identify -format '%k\n' tree.gif
| 在 IM v6.8.5-8 之前,"[-format](https://imagemagick.org/command-line-options/#format)" 会自动在输出末尾添加行尾字符,以分隔多幅图像的结果。现在不再这样做了,因此你可能需要自己在 "[-format](https://imagemagick.org/command-line-options/#format)" 字符串中添加适当的 EOL 字符。
---|---
Identify,要不要 Ping
"[magick identify](#identify)" 默认只读取关于图像的最少基本信息,使用一种称为 "[-ping](https://imagemagick.org/command-line-options/#ping)" 的技术。这意味着 identify 只读取图像文件中足以确定简单图像信息(例如尺寸)的部分,而不会尝试把整幅图像读入内存。见下文 Ping,操作控制。这是 "[magick identify](#identify)" 相对于 "[magick](#magick)" 的一大优势。然而,大多数图像元数据将无法获得,例如来自 PNG 图像文件的图像标签。比如,这里我创建一幅带有“标签”的图像,并尝试用一个简单的 format 设置来打印该标签。
|
magick rose: -set label "rose with a label" rose.png
magick identify -format '"%l"\n' rose.png
不过这只在非常特定的情况下才会发生。任何带有更复杂转义的 "[-format](https://imagemagick.org/command-line-options/#format)" 都会自动禁用最小化的 'ping' 读取。
magick identify -format '"%[label]"\n' rose.png
或者你可以专门禁用这种最小化的 'ping' 读取,强制 identify 把图像“整幅”读入,从而获取所需信息。
magick identify +ping -format '"%l"\n' rose.png
一般来说你不用太担心这个问题。除非你在处理非常大的图像,例如照片。
Identify 作为浮点计算器
你可以用 FX 转义表达式 做一些浮点数学运算……
magick identify -ping -format 'double_width=%[fx:w*2] PI=%[fx:atan(1)*4]\n' tree.gif
注意,这些运算甚至不必与图像本身相关,因而你可以把 IM 用作脚本中的简单浮点计算器。由于我们只需要基本信息,所以使用了 Ping 控制以阻止 identify 把整幅图像读入。在本例中它对结果没有影响,但能极大地加快命令速度。
关于 Identify 的额外注意事项
- 特定格式细节
- 通常 IM 会先用各种图像库 API 和 delegate 程序把图像读入内存(本质上就是读入其自有的内部数据格式),然后再用 identify 输出它所看到的结果。也就是说,"
magick identify" 分析的是它已读入并存储的图像/数据内容。它不分析特定文件格式如何存储或处理图像数据。这一点很重要,因为某些文件格式可能有非常具体的方面,是 "magick identify" 不会报告的。例如,虽然它会列出 GIF 图像中每幅图像(可能有多幅)的颜色表内容,但它不会告诉你文件中的所有图像是否共享同一个颜色表。如果你需要关于特定图像文件格式的具体信息,最好使用专为该格式设计的工具。例如用于 GIF 文件格式的 "giftrans",以及用于 JPEG 文件格式的 "jpegtrans"。 - 颜色直方图输出
- 注意,如果图像有超过 1024 种颜色,冗长(verbose)输出中将不包含任何直方图或颜色表。要强制生成此信息,你可以使用特殊的 '
histogram:' 文件格式,它会把所有内容作为一个大的图像注释包含进来。 - 退出状态
-
如果遇到损坏的图像,并且你加上了 Regard Warnings 控制,identify 程序会返回非零退出状态。
error=
magick identify -regard-warnings image 2>&1 >/dev/null;if [ $? -eq 0 ]; then echo "The image is good" else echo "The image is corrupt or unknown format" echo "$error" fi
Identify 的输出替代方案
从 IM v6.2.4 起,你也可以用 "[convert](#convert)" 命令、通过特殊的 "[info:](files.html#info)" 输出文件格式来产生 identify 输出。
magick ../images/k* \
-format 'image \"%f\" is of size %G\n' info:
你可以用 Write 操作符 在一系列操作的中途写出到 "[info:](files.html#info)",例如作为调试工具。你也可以让它把输出写到某个特定文件(或文件流)。更简单的方法是使用 "[-identify](https://imagemagick.org/command-line-options/#identify)" 选项写到普通的“标准输出”。
magick ../images/k* \
-format 'Image #%p named \"%f\" is a %m\n' -identify \
null:
这还可以与另一个选项 "[-print](https://imagemagick.org/command-line-options/#print)" 结合,以输出其他信息。
magick null: -print ' (50 + 25)/5 ==> %[fx: (50+25)/5 ]\n' null:
"[-identify](https://imagemagick.org/command-line-options/#identify)" 与 "[-print](https://imagemagick.org/command-line-options/#print)" 的主要区别在于:前者会对内存中的每一幅图像运行一次,而后者只运行一次。这意味着我们可以完全在单条 ImageMagick 命令内,针对内存中的图像生成几乎任意我们想要的文本文件。例如,这里我为前一个示例中用过的同一组图像生成一个 HTML 文件……
magick ../images/k* \
-print "<HTML><BODY><CENTER>\n" \
-print "<H1> Display of %n Thumbnails </H1>\n" \
-print "\n" \
-format "<IMG SRC=\"%i\" ALT=\"%f\" WIDTH=%w HEIGHT=%h>\n" -identify \
-print "\n" \
-print "<BR>That's all folks\!\n" \
-print "\n" \
-print "</CENTER></BODY></HTML>\n" \
null:
你可以把上述输出的结果当作一个展示这些图像的 HTML 网页 来查看。关于这些选项的最后一点说明:默认情况下它们全都打印到 "magick" 命令的“标准输出”。你无法专门输出到其他“管道”或某个特定文件,除非你事先重定向了“标准输出”。用 "[info:](files.html#info)" 写出输出,可以让你像写到图像文件那样把输出导向某个特定文件。你也可以用特殊的 "[fd:](files.html#fd)" 输出文件格式,把输出导向一个事先准备好的文件描述符。当然,这会针对每幅图像各写出一次,因此可能需要对图像做一些处理,才能安排它只输出一次。
Mogrify -- 就地批处理
"magick mogrify" 命令在许多方面与 "magick" 类似,区别在于它被设计用来 就地修改图像。也就是说,它的主要目的是逐个文件地读入图像(或动画)并加以修改,然后把图像保存回它被读取时的 完全相同的文件名。正因如此……
Mogrify 很危险,因为它很容易毁掉原始图像!
因此,在你做任何最终操作之前,请先用图像的单独副本来测试 "magick mogrify"。不要在没有备份的原始图像上使用它。现在,虽然 "magick mogrify" 通常把修改后的图像保存到相同的文件名,但它有两个特殊选项,可以让它把图像保存到不同的文件。"magick mogrify" 专有的设置 "[-format](https://imagemagick.org/command-line-options/#format)" 定义了保存文件时所用的不同格式和后缀。因此一条像这样的命令……
magick mogrify -format jpg *.png
将允许你转换或批量修改图像,而不会毁掉原始图像。在本例中,是把所有 PNG 文件转换为同名但后缀不同的 JPEG 文件。不过请注意,如果已存在同名文件,它将被 覆盖。所以让我再强调一遍……
Mogrify 前要思考和检查
否则你可能会发现自己刚刚覆盖了某个想保留的东西。从 IM v6.2.0 起,你还可以使用新的 "[-path](https://imagemagick.org/command-line-options/#path)" 选项来指定一个用于输出已处理图像的不同目录。这样更安全,但它仍会覆盖该目录中可能已存在的任何同名图像。此外,留在该目录中的任何旧图像也不会被移除。因此你可以用类似下面的方式让 IM 把结果(比如图像缩略图)保存到一个已存在的子目录中……
magick mogrify -path thumbnail-directory -thumbnail 100x100 *
| 在 IM v6.3.4-3 之前,"[-format](https://imagemagick.org/command-line-options/#format)" 和 "[-path](https://imagemagick.org/command-line-options/#path)" 设置是互斥的。从该版本起,你可以同时更改格式和输出目录位置。
---|---
由于其多图像处理能力,"magick mogrify" 命令不能使用任何 多图列表操作符 或 图像栈操作符。这意味着你不能在 "magick mogrify" 命令中使用诸如 "[-fx](https://imagemagick.org/command-line-options/#fx)"、"[+swap](https://imagemagick.org/command-line-options/#swap)"、"[-composite](https://imagemagick.org/command-line-options/#composite)"、"[-append](https://imagemagick.org/command-line-options/#append)"、"[-flatten](https://imagemagick.org/command-line-options/#flatten)" 和 "[-layers](https://imagemagick.org/command-line-options/#layers)" 等图像处理操作符。由于某些设置型选项需要在第一幅图像被读入之前设定(例如 "[-size](https://imagemagick.org/command-line-options/#size)"、"[-label](https://imagemagick.org/command-line-options/#label)" 和 "[-density](https://imagemagick.org/command-line-options/#density)"),这些选项会在第一幅图像被读入之前被处理和设定。此后每幅图像被读入,操作符按命令行顺序应用于它们,然后图像被保存,再读入下一幅图像。记住这一点很重要,因为如果你在序列后面更改了其中某个设置,可能会让 IM 忘记先前的某个设置。例如……
magick mogrify -format gif -size 200x200 -pointsize 18 \
-font Candice -gravity north -annotate 0 "%f" \
-font Ravie -gravity Center -annotate 0 "%f" \
-font Gecko -gravity south -annotate 0 "%f" \
-size 100x64 xc:gold xc:orange xc:tomato
如你所见,上面生成的图像大小是由第二个 "[-size](https://imagemagick.org/command-line-options/#size)" 输入设置决定的,第一个较大的设置被完全忽略了。另一方面,操作符设置 "[-font](https://imagemagick.org/command-line-options/#font)" 则为每个单独的 "[-annotate](https://imagemagick.org/command-line-options/#annotate)" 操作正确地设定了。这种额外的复杂性意味着,最好还是……
简单地 Mogrify 图像。
不要试图在 "magick mogrify" 的批处理操作中做非常长、非常复杂的、类似 "magick" 的操作,它很可能会出现“设置”方面的问题。如果你真的想做复杂处理,请编写 shell/dos/perl 脚本,用 "magick" 逐一处理每幅图像,或者改用某个 ImageMagick API 接口。关于用脚本修改大量图像的示例,见 ImageMagick 进阶示例。请记住,"magick mogrify" 是一条危险的命令,在投入生产之前,应始终在备份图像上彻底测试。实际上,我还建议脚本中包含对 "magick mogrify" 之类操作的快速“测试”,以确保该命令在处理非常大的一批图像之前不会破坏任何东西(由于版本变化或不同计算机安装环境的差异)。也就是说,先做一个小的“测试用例”,若它未能产生正确结果就中止。这其实对任何大规模图像处理项目都是个好主意,可以保护用户免受意外后果之害。我自己在 IM 示例中就是这么做的,它为我省去了很多麻烦。
使用 "magick mogrify" 进行 Alpha 合成
由于 "magick mogrify" 不能使用 多图列表操作符,它无法轻松地叠加诸如徽标之类的东西,或用 Alpha 合成 来对图像做遮罩。不过有一个例外,即使用 "[-draw](https://imagemagick.org/command-line-options/#draw)" 来执行图像 alpha 合成。这允许你把第二幅图像作为操作符参数的一部分指定,使其位于当前图像列表之外。例如,这里我先用一个特殊的 "[cp_perl](http://www.ict.griffith.edu.au/anthony/software/#mv_perl)" 脚本复制我想要处理的原始图像。然后我创建一幅临时的圆形“遮罩”图像,再用它通过 "magick mogrify" 配合 '[Dst_In](compose.html#dstin)' alpha 合成方法,从所有这些图像中切出一个圆形。
cp_perl 's/^/mogrify_/' eye.gif news.gif storm.gif tree.gif
magick -size 32x32 xc:none -draw 'circle 15.5,15.5 15.5,0' circle.gif
magick mogrify -alpha Set -draw 'image Dst_In 0,0 0,0 "circle.gif"' mogrify_*.gif
注意,任何 Alpha 合成方法都可以这样使用,但只能用一个恒定的“源”或“叠加”图像应用于所有图像。此外,由于 "magick mogrify" 会多次读取“源”图像,我建议你使用 IM 专有的 "MPC:" 文件格式,以减少反复读取时解码图像的开销。这种图像文件格式无需 IM 解析,因为它会直接从磁盘映射到内存(仅限创建它的同一台机器)。这能节省大量处理时间,尤其是在处理大量图像时。
用 Convert 代替 Mogrify
利用一种特殊技术,通过 百分号转义 修改输出文件名(见 文件名百分号转义),你可以用功能更全面的 "[convert](#convert)" 命令替代 "[mogrify](#mogrify)"。不仅如此,它还能让你对图像的最终目标名称有更多控制,并让你更好地处理诸如合成和动画之类的多图像处理。例如,这里我为当前目录中的图像创建缩略图,在输入文件名中插入一个 "_tn" 字符串,以构造合适的输出图像文件名。
magick *.jpg -thumbnail 120x90 \
-set filename:fname '%t_tn' +adjoin '%[filename:fname].gif'
警告,不要在文件名设置本身中包含不同的文件后缀。IM 在决定要使用的图像文件格式时不会看到它。注意,如果 IM 无法从文件名判断格式,它会回退到读入时的原始文件格式,因此在使用这种技术时,明确的后缀或编码器前缀可能很重要。要获取源图像的确切原始文件名,可使用 "%i"、"%d/%f" 或 "%d/%t.%e"。当然,这些里面都带有文件名后缀(在文件名设置中),IM 不会使用它,但这应该没问题,因为它是相同的图像文件格式。用 "[convert](#convert)" 代替 "[mogrify](#mogrify)" 的真正问题在于:所有图像都会先被读入内存!Mogrify 煞费苦心地一次只读/改/写一个文件(尽管该文件可以包含多幅图像)。但 "[convert](#convert)" 不是这样。因此,如果你不小心,很容易超出内存限制。不过也有一些规避办法。见 读取修饰符 和 缩略图 中的示例。此外,由于所有图像都作为单个图像列表存在于内存中,你需要小心处理这些图像。例如,你不能像平常那样直接使用 Alpha 合成,而可能需要使用专门的 多图列表合成 来完成。当然,正如 "magick mogrify" 一样,这种使用 "magick" 的方法也可能很危险,因为它很容易覆盖并毁掉原始图像文件。
批处理的替代方案
如果用 "magick mogrify" 批处理图像不切实际——尤其是当你要复制图像而非就地修改它们时——那么使用某种非 IM 的循环方案可能更好。这些方案包括……
# 使用简单的 shell 循环来处理每一幅图像。
mkdir thumbnails
for f in *.jpg
do magick $f -thumbnail 200x90 thumbnails/$f.gif
done
# 用 find 把文件名替换进 'convert' 命令。
# 通过移除 -prune 选项,这还提供了递归遍历目录的能力,
# 以及做其他文件检查(如图像类型,或某图像占用的磁盘空间)。
find * -prune -name '*.jpg' \
-exec magick '{}' -thumbnail 200x90 thumbnails/'{}'.gif \;
# 使用 xargs —— 配合一个 shell 包装器把参数放入变量。
# 这可以与 "find" 或 "ls" 结合来列出文件名。
ls *.jpg | xargs -n1 sh -c 'magick $0 -thumbnail 200x90 thumbnails/$0.gif'
# 在 linux(而非纯 unix)上的另一种方法
# 它无需 shell 来处理参数。
ls *.jpg | xargs -r -I FILE magick FILE -thumbnail 200x90 FILE_thumb.gif
等等。我建议同时使用 "find" 和 "xargs" 来做递归或非递归的文件处理。请阅读它们的手册页。要快速入门,可参见这篇 IM 讨论帖,以及 Xargs - 维基百科 指南,其中包含了相关风险的信息。如果你的命令开始变得比这更复杂,也许就该转向 shell 脚本或 API 程序了,以读入多幅图像、收集信息、计算合适的参数并处理图像。我还强烈建议好好了解一下 "[parallel](http://www.gnu.org/software/parallel/)" 命令(通常可直接替换 "xargs")。它不仅能让你同时运行多条命令,稍加设置后还能在不同计算机上运行各条命令,让你对数量极大的任务进行网络分布式处理。对于 Windows 用户,我请你参阅 Windows 用法 一节,特别是 Windows,批处理多个文件。 |
记住,"[mogrify](#mogrify)" 以及所有其他 IM 命令也会展开任何包含 shell 元字符(如 '*' 和 '?')的文件名。这样做是为了允许在旧的 DOS 命令行 shell 上使用这些元字符。然而这可能导致 bug、"magick mogrify" 的重复执行,甚至可能来自某个邪恶源头(其提供了要使用的文件名)的“黑客攻击”。建议保持谨慎并完全理解相关的安全问题。 |
|---|---|
Composite -- 以特殊方式叠加图像
"magick composite" 命令专门设计用于以各种方式对两幅图像进行简单的 alpha 合成(叠加)。这包括通过第三幅遮罩图像来限定图像合并的区域。与 "magick" 不同,"magick composite" 命令是一条非常传统的命令,它会先读取所有选项和设置,然后才执行它所设计的那一个图像处理操作。"magick composite" 命令还提供了对一些更复杂的 alpha 合成模式的简单访问。例如 "[-dissolve](https://imagemagick.org/command-line-options/#dissolve)"、"[-blend](https://imagemagick.org/command-line-options/#blend)" 和 "[-watermark](https://imagemagick.org/command-line-options/#watermark)" 图像合成。如果给出了这些参数中的任何一个,它们将覆盖该命令此前(或将要)给出的任何其他 "[-compose](https://imagemagick.org/command-line-options/#compose)" 设置。还要注意,"[-tile](https://imagemagick.org/command-line-options/#tile)" 设置在这里的工作方式也与 "magick"、"magick montage" 和 "magick display" 中的不同。在 "magick composite" 中,它会使叠加图像在整个背景图像上平铺。这是其他 IM 命令尚不具备的功能。虽然这些特殊功能让 "magick composite" 成为一条有用的命令,但 alpha 合成现在也可以在 "magick" 命令中使用了(详见 IM 中的 Alpha 合成)。关于把两幅或更多图像叠加在一起的多种不同方式的概述,见 多对图像的合成 中的示例。关于把两幅图像合并在一起的方法的更多信息,见 Alpha 合成 示例页。叠加的限定或“遮罩”能力,也在上述示例页的 使用 Compose 遮罩限定合成区域 中有详细说明。
Montage -- 生成缩略图阵列
特殊的 IM 图像索引命令 "magick montage" 也遵循与 "magick" 相同的“边看边做”式命令行结构。唯一的区别在于,当到达命令末尾时(除最后的输出图像文件名参数外),"magick montage" 会根据当前设定的各项设置,开始把图像列表处理成缩略图索引页。这使得 "magick montage" 比它在 IM 版本 5 中灵活得多,因为你现在可以像在 "magick" 中那样处理图像,然后设定你想要的所有 "magick montage" 设置,让它完成余下的工作。关于 "magick montage" 的更多细节,见 Montage,缩略图阵列。
display -- 图像幻灯片放映
"magick display" 程序旨在以循环幻灯片放映的形式显示一幅图像或图像列表。它不是为精心编排和定时的图像动画而设计的,那种用途请使用 "[animate](#animate)" 命令。每幅图像都会在一个根据其大小适当调整尺寸的窗口中显示,除非有其他选项(如窗口 "[-geometry](https://imagemagick.org/command-line-options/#geometry)",见下文)覆盖此行为。图像通常还会显示在棋盘格背景上,以便展示图像可能具有的任何透明度的效果(见下文)。请记住,这 不是 为显示动画而设计的,而是作为实际图像的幻灯片放映。因此,在脚本程序中使用 display 时可能需要一些注意。图像显示时间、循环及其他选项 默认情况下,在用户用 "[-delay](https://imagemagick.org/command-line-options/#delay)" 设置指定的任何延迟之上,还会再使用约 2 秒的延迟。不过你可以用选项 "-delay 0" 让它等待用户输入(空格键)。然而默认值可能会被图像本身覆盖,这取决于其文件格式。因此,诸如 GIF 和 MIFF 之类的动画格式,可能导致暂停,也可能导致 2 秒加上图像元数据延迟设置的延迟。因此建议你始终根据需要设定一个合适的 "[-delay](https://imagemagick.org/command-line-options/#delay)"(记住 "-delay 5x1" 会延迟 5+2 即约 7 秒),以适应你的脚本和需求。"[-loop](https://imagemagick.org/command-line-options/#loop)" 设置同理。默认情况下 "magick display" 永远循环("-loop 0"),但 MIFF 或 GIF 等图像格式可以覆盖此设置,使其在循环中的最后一幅图像之后退出。请根据你的情况适当设置 "[-loop](https://imagemagick.org/command-line-options/#loop)" 选项。注意,"magick display" 不会处理任何 GIF 动画设置,因此各帧不会被处置(dispose),虚拟画布尺寸和偏移也会被忽略。换句话说,你会看到 GIF 动画中原始的局部图像,而非正确叠加后的图像。它确实提供了一个 "[-coalesce](https://imagemagick.org/command-line-options/#coalesce)" 选项,用于为显示目的清理此类动画。
透明度处理
包含完整 alpha 通道的图像(例如 PNG 和 MIFF 格式)将被叠加在一个“棋盘格”背景图案上,以便让你看到任何半透明效果,例如阴影效果。你可以用 "[-texture](https://imagemagick.org/command-line-options/#texture)" 选择不同的背景来更改它,例如……
magick display -texture granite: test.png
magick display -texture xc:black test.png
具有调色板(或布尔)透明度的图像,例如 GIF 和 PNG8 格式,会以当前用于在颜色表中表示透明度的“透明色”来显示。也就是说,可能会使用某种通常是随机的颜色(一般是黑色),而非默认的棋盘格图案。这可以被视为一个 bug,尽管技术上它不是。不过,如果你希望 display 像处理其他含透明度信息的图像那样处理此类图像,可以在把图像喂给 "magick display" 之前移除调色板元数据,使用下面的命令来更改该图像输出格式的内部样式。
magick image.gif -type truecolormatte miff:- | display -
或者,几乎任何修改被显示图像的操作也会移除现有的调色板元数据。因此某些 "magick display" 选项可用于移除调色板,例如使用 "[-coalesce](https://imagemagick.org/command-line-options/#coalesce)"。
magick display -coalesce image.gif
这样做还有个额外好处:清理可能存在的 GIF 动画优化。不过对于多幅不相关的图像,它可能会有其他不良副作用。是的,这些方法很笨拙,但它们能用。
使用 Convert 进行显示
除了使用 "magick animate"(见下文)之外,另一种显示方法是使用更简单的 "x:" 输出图像格式(见 display 输出格式)。
magick image.png x:
这种方法不提供背景窗口、菜单选项或其他控件。它只是简单地一次一幅地显示图像。如果你只想简单地“显示”结果图像,特殊的 'show:' 或 'win:' 输出 Spawning Delegate 也能做同样的事,它会对输出图像运行 "[display](#display)" 命令,然后退出而不等待该窗口被关闭。
magick image.png show:
Display 输出尺寸
Display 不会缩放图像以适配 X 窗口显示。窗口大小会被调整以适配每幅图像,除非用 "[-geometry](https://imagemagick.org/command-line-options/#geometry)" 设置加以指定。该设置还可用于固定窗口在 X 窗口显示上的位置。比屏幕更大的图像也不会被调整大小,而是会溢出屏幕;不过 display 会提供一个“滚动窗口”让用户在图像内滑动浏览。在查看现代高分辨率数码照片时,这可能会很痛苦。要把 display 限制在比如 800x600 像素的区域(只缩小,绝不放大),使用……
magick display -resize 800x600\> photo.jpg
对于 JPG 图像,你可以用一个特殊的 jpeg 输入尺寸提示设置来加快图像读取。见 读取 JPEG 控制选项。
magick display -define jpeg:size=1600x1200 -thumbnail 800x600\> photo.jpg
如果图像来自现代数码相机,你还可以用 "[-auto-orient](https://imagemagick.org/command-line-options/#auto-orient)",利用图像文件格式中的 EXIF 元数据来校正所显示图像的相机旋转。如果你不想要菜单,可以用 "[-immutable](https://imagemagick.org/command-line-options/#immutable)" 设置把它们关闭,告诉 "magick display" 不允许编辑。
在脚本中使用 Display
考虑到这些选项,下面是我推荐的、用 "magick display" 来显示复杂 shell 脚本结果的方式……
magick display -delay 0 -loop 1 -coalesce -resize 800x600\> some_random_image
在 X Windows 中使用 Display
可以用选项 "[-window](https://imagemagick.org/command-line-options/#window) root" 把图像显示在 X 窗口的背景(root)窗口上。这种情况下,"magick display" 程序会自动退出。默认情况下,图像会在背景上平铺。例如试试这个……
magick display -window root pattern:checkerboard
关于图像瓦片的许多其他示例及其生成方法,见 平铺画布 和 背景图像示例。如果你想用单幅图像作为 X Windows 背景,你可能需要知道 X 窗口显示的大小。"xdpyinfo" 程序虽不是 ImageMagick 的一部分,但可以给你提供该信息。
xdpyinfo | grep dimensions:
这里我们用 "xdpyinfo" 的输出,把图像调整为完全填满 X 窗口背景。
screen_size=`xdpyinfo | sed '/dimensions:/!d;s/^[^0-9]*//;s/ pixels.*//'`
magick display -resize $screen_size! -window root photo.jpg
Display 远程控制
Display 确实提供了一个特殊的 "[-remote](https://imagemagick.org/command-line-options/#remote)" 选项。它会查找已在运行的 "magick display" 命令,然后把给定的参数传递给它。例如……
magick display wizard: &
sleep 5
magick display -remote logo: &
这会在一个后台运行的命令中显示内建的 "wizard" 图像。然后脚本会等待 5 秒,再用内建的 "logo" 图像替换它。注意,如果没有正在运行的 "magick display" 命令,当前命令会打开一个窗口而不退出。因此作为预防措施,你也应该把 "display -remote" 命令放到后台。目前你无法请求一个远程的 "magick display" 退出。因此关闭远程 display 的最好方法,是杀死正在运行的进程,或者用某个 X 窗口命令“删除”该 display 窗口。例如(使用非 IM 命令 "xdotool")……
xdotool search -class "display" windowkill
animate -- 显示图像动画
在许多方面,"magick animate" 与 "[display](#display)" 极为相似。然而,"[display](#display)" 只是“原样”显示给定图像文件中的图像而不做更改,并在每帧之间加入最少 2 秒的暂停以等待用户输入。而 "magick animate" 则会应用随图像保存的任何 GIF 动画设置,仅根据每幅图像的“时间延迟”设置来显示它,并循环回到起点重复该动画。换句话说,"magick animate" 能正确地“动画化”动画格式,而 "[display](#display)" 不能。但正因如此,第一幅图像的虚拟画布将控制输出图像的尺寸,其他图像会被叠加到该图像区域中。当然,由于图像是被动画化的,你确实可以用诸如 "[-delay](https://imagemagick.org/command-line-options/#delay)" 等选项精细地控制图像显示的时序。该命令还有一个额外参数 "[-pause](https://imagemagick.org/command-line-options/#pause)",可在动画循环末尾、在最后一帧的 "[-delay](https://imagemagick.org/command-line-options/#delay)" 设置所指定的延迟之外,再添加一个额外暂停。例如你可以用 "magick animate" 来生成两幅极为相似图像的 闪烁比较,使用类似下面的命令……
magick image1.png image2.png -scale 400% miff:- |\
magick animate -delay 50 -loop 0 -
我写了一个利用此方法的脚本,叫做 "[flicker_cmp](../static/img/scripts/flicker_cmp)",我发现它对于捕捉那些我本会错过的、极其细微的像素强度变化非常有用。
compare -- 查找差异
关于这一点的所有当前信息都在 IM 示例的 图像比较页 一节。
stream -- 对海量图像进行管道处理
"magick stream" 是一个特殊程序,专门用于处理从超大图像文件中提取一部分。它是 ImageMagick 内唯一这样的程序,其他所有程序都会先把图像完整读入内存再处理(例外是通过 "[-size](https://imagemagick.org/command-line-options/#size)" 处理的 JPEG 图像,因为该选项会被传递给 JPEG delegate 库)。你可以用 "[-extract](https://imagemagick.org/command-line-options/#extract)" 设置选取图像的一部分。可以用 "[-depth](https://imagemagick.org/command-line-options/#depth)" 设置指定原始字节的深度。最后,你可以用 "[-channel](https://imagemagick.org/command-line-options/#channel)" 选项选择要提取哪些颜色通道。不过 "magick stream" 只会按图像深度所定义的格式输出图像的原始颜色字节(RAW 格式),因此你可能需要把所提取片段的输出通过管道送入 convert。例如…… |
magick stream -map rgb -storage-type char -extract 100x100+200+100 logo: - |\
magick -depth 8 -size 100x100 rgb:- magick stream_wand.gif
![[IM Output]](../static/img/basics/stream_wand.gif)
更多信息和示例见 真正海量图像的处理。
import -- 从屏幕显示中读取图像
"magick import" 命令是一个特殊程序,可用于从 X 窗口显示中抓取并提取图像。例如,让我们用它来抓取并打印你从显示器上选定的一个窗口……
magick import -page A4 -gravity center ps:- | lpr
它实际上很少被使用,因为特殊文件格式 "[X:](files.html#x)" 也能在 magick 命令内提供完全相同的功能。两者唯一的区别是,"magick import" 比 "[X:](files.html#x)" 格式拥有更多 X 窗口专属的设置,例如指定要从哪个 display、screen 和/或 window ID 抓取图像。其他选项包括控制显示器“蜂鸣”和重复快照。如果未指定具体窗口,可以用鼠标来选择用户想抓取为图像的显示部分。
- 如果使用单次鼠标点击,则点击所在的整个窗口会被抓取并作为图像返回。注意,如果显示器上有其他窗口遮挡了所选窗口的一部分,那么你抓取到的图像中,被抓取的所选窗口会被那些遮挡的其他窗口所遮挡。
- 在 root 窗口中点击,或选择 "
-window root",将返回整个屏幕。 - 如果使用鼠标点击并拖动,则会返回整个屏幕的一个 裁剪 区域,这当然也意味着该区域在整个显示(虚拟画布,即页面,尺寸)上的位置(虚拟画布偏移)也会被返回。
其他选项允许你避免与鼠标的人为交互,方法是抓取整个屏幕("-window root")或某个特定窗口(给定窗口标题或 X 窗口 ID,你可以用 X 窗口工具 "xwininfo" 找到它)。你还可以用 "[-extract](https://imagemagick.org/command-line-options/#extract)" 来缩减所选窗口的区域。另见特殊输入格式 "[X:](files.html#x)",作为使用 "magick import" 的替代方案。
注意,要从 Windows 剪贴板导入,请使用
magick clipboard:myimage image.png
而不是 "import"
conjure -- IM 实验性脚本语言
最初的设计目的是允许以脚本方式使用 ImageMagick,支持使用多个图像列表,但 IM v6 "magick" 所做的改进使这个实验性 API 渐渐废弃不用。它是一种基于 XML 的语言。不过如果你想要 XML,SVG 也许更能满足你的需求。在我看来,处理多图像列表时,使用 "magick conjure" 脚本大概更好、更容易。它确实有人在用,不过由于缺乏示例和用户支持,使用并不广泛。
图像列表……
使用 ImageMagick 时最重要的一点——也是同时让新用户和有经验用户都感到困惑的一点——就是……
ImageMagick 处理的是有序的图像列表,而不是单幅图像
也就是说,IM 处理的不只是一幅图像,而可能是一个有序的图像列表,它们可以是各自独立的图像、一组彼此叠加的图像,或者一个动画的各帧。另外,一般而言,所有图像操作符都会应用于 当前列表中的所有图像。因此,如果你使用 "[-draw](https://imagemagick.org/command-line-options/#draw)" 操作符,它不会像许多新用户以为的那样只在列表的最后一幅图像上绘制,而是会绘制到当前图像列表中 所有 其他图像上,并且依次对每幅图像都这样做。图像分层操作符,例如 "[-coalesce](https://imagemagick.org/command-line-options/#coalesce)" 和 "[-layers](https://imagemagick.org/command-line-options/#layers)",会把列表中的每幅图像替换为一幅根据列表中其他图像修改而来的新图像。它甚至可能添加或移除额外的图像!此外,图像列表操作符,如 "[-append](https://imagemagick.org/command-line-options/#append)"、"[-mosaic](https://imagemagick.org/command-line-options/#mosaic)" 和 "[-fx](https://imagemagick.org/command-line-options/#fx)",会把当前图像列表中的所有图像替换为合并后的结果图像。也就是说,它会销毁所有图像,除非它们此前用 圆括号 保存过,并使用了 克隆图像。实际示例见下文 图像列表操作符。最后,当读入或创建一幅新图像时,IM 只会把这幅新图像添加到当前图像列表(它总是存在)的末尾。某些格式(如 GIF)实际上可能向当前图像列表添加多幅图像,除非在输入文件名上加了特殊的 索引读取修饰符 以限制读入的内容。保存图像时,IM 会保存写出时内存中的整个图像列表。如果图像格式允许,IM 会把所有图像写入单个文件。如果格式不允许多幅图像(例如 JPEG),它会把图像写入各自独立的文件(见 写出多幅图像)。
圆括号 -- “在一旁”处理图像
随着命令行选项的规范化,处理顺序现在变得完全可预测,也使得在图像处理中加入圆括号(或方括号)成为可能。这是 IM 用户长期以来梦寐以求的功能,它让你能够在单条命令中做到以前不可能做到的事情。开括号 '(' 实际上会开启一个新的图像列表,所有被括起来的操作符都将作用于该列表。匹配的闭括号 ')' 则会把生成的图像列表(可能不止一幅图像,也可能一幅都没有)添加到上一个图像列表的末尾。换句话说,使用圆括号意味着……
“我需要在一个独立的图像列表中做一点工作,
然后把结果添加到上一个列表的末尾。”
它让你能够在一个子图像集合上工作——就像一块草稿板——然后把结果加回主图像列表,而不影响你此前已读入或一直在处理的图像。让我们看几个简单的示例…… |
magick eye.gif storm.gif -negate +append cmd_negate.gif
![[IM Output]](../static/img/basics/cmd_negate.gif)
如你所见,"[-negate](https://imagemagick.org/command-line-options/#negate)" 操作符对两幅图像都做了颜色反相,因为当时它们都在当前内存中的图像列表里。但通过添加圆括号,我们可以把反相限制在只作用于第二幅图像…… |
magick eye.gif \( storm.gif -negate \) +append cmd_bracket.gif
![[IM Output]](../static/img/basics/cmd_bracket.gif)
因为 "storm.gif" 图像被读入到一个与第一幅图像分开的图像列表中(由 "(" 这个图像列表操作符生成),所以它可以被反相而不影响第一幅图像。然后我们可以把结果加回主图像列表(即 ")" 操作符),再像之前那样把两幅图像拼接在一起。 | _圆括号必须作为单独的参数给出。也就是说,你必须用空格把它们与其他参数分开。你不能把它们紧贴着相邻的参数。换句话说,在 IM 命令行参数中 "\(+clone " 是错误的,而 " \( +clone " 才是正确的。
此外,在上一个示例中我需要在圆括号前加一个反斜杠 '\'。这是因为在 UNIX(linux)机器上使用 IM 时,圆括号对命令行 shell 有特殊含义。因此当我使用它们时,需要对括号符号进行转义或加引号。
Windows DOS 脚本不需要用反斜杠转义圆括号。关于这一点以及与 linux 脚本编写的其他差异,见 Windows DOS 脚本。
_
---|---
圆括号还使得在单条 "magick" 命令中做到以前不可能做到的事情成为可能:生成图像阵列! |
magick eye.gif news.gif +append \
\( storm.gif tree.gif +append \) -append cmd_array.gif
![[IM Output]](../static/img/basics/cmd_array.gif)
当然,这样的阵列用 "magick montage" 也是可以做到的(见 Montage 拼接模式),但使用一条单独的命令会让图像处理脚本更复杂。当然,如果你想让命令本身看起来更像阵列,可以随意添加一些额外的圆括号。 |
magick \( eye.gif news.gif +append \) \
\( storm.gif tree.gif +append \) \
-append cmd_array2.gif
![[IM Output]](../static/img/basics/cmd_array2.gif)
第一组圆括号严格来说并非必需,确实会给 IM 的内部处理增加一点点额外工作,但它通过分隔各处理步骤,让命令在做什么更加清晰。对图像处理脚本来说,把每个处理步骤作为单独的圆括号来执行,作为分隔所应用处理步骤的手段,可能也更容易。
圆括号与设置
选项“设置”不受圆括号影响,会跨越圆括号内的图像操作符继续生效,直到该设置被更改或关闭。例如…… |
magick -pointsize 24 \
-font Candice label:Outside \
\( label:Inside \
-font Gecko label:Inside \) \
label:Outside -append cmd_settings.gif
![[IM Output]](../static/img/basics/cmd_settings.gif)
注意,进入圆括号时,第一个 "-font Candice" 设置并没有被重置回其默认设置;而离开圆括号时,第二个 "-font Gecko" 也没有被原来的字体设置替换。换句话说……
圆括号只创建一个独立的图像序列。
它们不限制设置,只限制所操作的图像。
从 IM v6.4.1-4 起,新的操作控制选项 "[-respect-parentheses](https://imagemagick.org/command-line-options/#respect_parenthesis)" 可以覆盖此行为。当它在 IM 命令开头给出时,会使圆括号同时保存和恢复此前给出的设置。这意味着圆括号内给出的任何设置,只在圆括号结束之前保持有效。例如…… |
magick -respect-parentheses -pointsize 24 \
-font Candice label:Outside \
\( label:Inside \
-font Gecko label:Inside \) \
label:Outside -append cmd_settings2.gif
![[IM Output]](../static/img/basics/cmd_settings2.gif)
如你所见,当圆括号结束时,字体设置被恢复为之前的 'Candice' 字体,而不是圆括号内设定的 'Gecko' 字体。当你需要短暂地更改大量设置时,这非常有用……
magick -respect-parentheses \
-font Arial label:"This is a line of plain text." \
\( -font Candice -pointsize 16 -fill red -undercolor lightblue \
label:"A line using a lot of different settings." \) \
label:"Text is back to normal -- like Magick\!" \
-append cmd_settings_lots.gif
图像列表操作符
随着 IM 更强调图像序列(尤其是在圆括号内),提供一组用于操纵图像列表的新图像操作符也就不足为奇了。
这些操作符的参数是对图像列表进行索引的数字,第一幅图像从零('0')开始,第二幅图像为一('1'),以此类推。不过,如果你给出负索引,则从图像列表的末尾(最后添加的图像)开始引用图像。也就是说,索引 '-1' 是当前图像列表中的最后一幅图像(一般是最后读入或创建的图像),'-2' 是倒数第二幅,以此类推。
-delete {index_range_list}
"[-delete](https://imagemagick.org/command-line-options/#delete)" 列表操作符是最简单的图像列表操作符,它只是从当前图像列表中删除图像。 |
magick font_[0-3].gif -delete 1 +append seq_delete.gif
![[IM Output]](../static/img/basics/seq_delete.gif)
该操作符的“加号”形式 "[+delete](https://imagemagick.org/command-line-options/#delete)" 不接受参数,只是删除当前图像列表中的最后一幅图像。"[-delete](https://imagemagick.org/command-line-options/#delete)" 操作符也接受逗号分隔的数字列表,或要删除的数字范围。 |
magick font_[0-7].gif -delete 1-4,6 +append seq_delete2.gif
magick font_[0-7].gif -delete 0--1 tree.gif seq_delete3.gif
![[IM Output]](../static/img/basics/seq_delete3.gif)
'0--1' 参数表示删除从第一幅图像(索引 0)到最后一幅图像(索引 -1)的图像。换句话说,就是当前图像列表中的所有图像。随后添加了 tree 图像,以给 IM 一个实际结果,从而避免“no image”类型的错误。也可以使用 "[NULL:](files.html#null)" 输出图像,以产生无输出。如果某个图像索引不存在,或某个数字范围反向了,"[-delete](https://imagemagick.org/command-line-options/#delete)" 会静默忽略该特定图像的删除。例如,参数 '-25' 会尝试删除图像列表中倒数第 25 幅图像,但如果存在的图像少于 25 幅,它会静默地什么也不做。因此你可以用如下序列生成一个 24 幅图像的滚动动画……
magick animation.gif new_frame.gif -delete -25 animation_new.gif
然而,如果图像数量为 24 或更少,则不会删除任何图像。结果是,每次运行该命令时,动画都会增加一帧,直到达到最多 24 帧。此后,每添加一帧新帧,就会删除最旧(第一)的那帧。从 IM v6.3.4 起,"[-delete](https://imagemagick.org/command-line-options/#delete)" 不会删除会导致编号范围反向的图像。这意味着上一个示例可以改写成这样……
magick long_animation.gif new_frame.gif -delete 0--25 animation_new.gif
这次,"[-delete](https://imagemagick.org/command-line-options/#delete)" 会删除从第一幅到倒数第 25 幅之间的所有图像,使列表中最多保留 24 幅图像。如果只存在 24 幅或更少的图像,给定的待删除图像范围实际上会反向,"[-delete](https://imagemagick.org/command-line-options/#delete)" 操作符将不会删除任何东西。
-insert {index}
"[-insert](https://imagemagick.org/command-line-options/#insert)" 操作大致是 "[-delete](https://imagemagick.org/command-line-options/#delete)" 的反操作。它会取当前图像列表中的最后一幅图像,并把它插入到给定索引的位置。 |
magick font_[0-3].gif tree.gif -insert 1 +append seq_insert.gif
![[IM Output]](../static/img/basics/seq_insert.gif)
你可以把插入索引理解为:应当出现在图像被插入点之前的图像数量。当然,原本位于该索引处的图像(以及其后的所有图像)会被向后顶到下一个索引位置,为新图像腾出空间。如果使用负索引位置,则插入位置是在把待插入图像从列表末尾移除之后再计算的。也就是说,它的行为就好像待插入图像并不属于原始图像列表。因此 "-insert -2" 会“滚动”最后三幅图像,在新插入的图像与图像列表末尾之间放置两幅图像。 |
magick font_[0-3].gif tree.gif -insert -2 +append seq_insert2.gif
![[IM Output]](../static/img/basics/seq_insert2.gif)
加号形式 "[+insert](https://imagemagick.org/command-line-options/#insert)" 会把最后一幅图像移到图像列表的最前面(索引 0),实际上把整个图像列表滚动一帧。 |
magick font_[0-3].gif tree.gif +insert +append seq_insert3.gif
![[IM Output]](../static/img/basics/seq_insert3.gif)
要做上面操作的逆操作(把一幅图像移到图像列表末尾),可以先用 "[-duplicate](https://imagemagick.org/command-line-options/#duplicate) 1,0" 复制第一幅图像,然后用 "[-delete](https://imagemagick.org/command-line-options/#delete) 0" 删除第一幅图像。
-swap {index}[,{index}]
简单地说,"[-swap](https://imagemagick.org/command-line-options/#swap)" 会交换当前图像列表中两幅图像的位置。例如 "-swap 0,2" 会交换当前图像列表中的第一幅和第三幅图像。 |
magick font_[0-3].gif -swap 0,2 +append seq_swap.gif
![[IM Output]](../static/img/basics/seq_swap.gif)
该选项的加号形式 "[+swap](https://imagemagick.org/command-line-options/#swap)" 会交换当前图像列表中的最后两幅图像。换句话说,它等价于 "-swap -2,-1"。 |
magick font_[0-3].gif +swap +append seq_swap2.gif
![[IM Output]](../static/img/basics/seq_swap2.gif)
该操作符最常见的用途,大概是在被诸如 "[-composite](https://imagemagick.org/command-line-options/#composite)"、"[-flatten](https://imagemagick.org/command-line-options/#flatten)"、"[-append](https://imagemagick.org/command-line-options/#append)" 或 "[-fx](https://imagemagick.org/command-line-options/#fx)" 等图像分层操作符使用之前,交换两幅图像。 |
magick tree.gif frame.gif +swap \
-gravity center -composite framed_tree.gif
![[IM Output]](../static/img/basics/framed_tree.gif)
从 IM v6.4 起,带单个数字的 "[-swap](https://imagemagick.org/command-line-options/#swap)" 会把最后一幅图像与给定编号的图像交换。也就是说,"-swap 1" 等价于 "-swap 1,-1"。 |
magick font_[0-3].gif -swap 1 +append seq_swap3.gif
-reverse
"[-reverse](https://imagemagick.org/command-line-options/#reverse)" 操作符(在 IM v6.3.4 中加入)会非常简单地把整个图像列表的顺序反转。 |
magick font_[0-3].gif -reverse +append seq_reverse.gif
![[IM Output]](../static/img/basics/seq_reverse.gif)
它基本上是一种终极的 Swap 操作符。
-clone {index_range_list}
这个图像列表操作符有点不同。给定一个图像列表编号,"[-clone](https://imagemagick.org/command-line-options/#clone)" 会复制一幅由“开括号”或“圆括号”操作符所保存的图像。也就是说……
Clone 应只在圆括号内使用
原因在于,它让你能够从最后保存(压入)的图像列表中提取一幅图像的副本,以便进一步处理。例如。 |
magick font_[0-2].gif \( -clone 1 -rotate 90 \) +append seq_clone.gif
![[IM Output]](../static/img/basics/seq_clone.gif)
不带参数的“加号”形式 "+clone" 只会复制最后保存(压入)的图像列表中的最后一幅图像,以便你进一步处理它。 |
magick font_[0-2].gif \( +clone -flip \) +append seq_clone2.gif
![[IM Output]](../static/img/basics/seq_clone2.gif)
从版本 6.2.2 发布起,"[-clone](https://imagemagick.org/command-line-options/#clone)" 操作符可以接受逗号分隔的图像列表,或形如 '_{index}-{index}_' 的索引范围。 |
magick font_[0-2].gif \( -clone 1-2 \) +append seq_clone_range.gif
![[IM Output]](../static/img/basics/seq_clone_range.gif)
当然,负索引仍会如你所料地工作。例如,要复制整个图像列表,你可以用数字 '0'(第一幅图像)和 '-1'(最后一幅图像)来指定,也就是使用范围 '0--1'。它看起来奇怪,但确有道理,而且工作得很好。 |
magick font_[0-2].gif \( -clone 0--1 \) +append seq_clone_all.gif
![[IM Output]](../static/img/basics/seq_clone_all.gif)
当你使用逗号分隔的索引列表时,图像会按你指定的顺序被提取。 |
magick font_[0-2].gif \( -clone 2,0,1 \) +append seq_clone_list.gif
![[IM Output]](../static/img/basics/seq_clone_list.gif)
如果某个范围内的图像是反向的(在负索引被转换为实际图像索引之后),那么所提取的图像也会作为该处理过程的一部分被反向。 |
magick font_[0-2].gif \( -clone 2-0 \) +append seq_clone_reversed.gif
Clone 图像操作符 可以不用圆括号使用,那样它只会从当前图像列表复制图像并直接追加。然而这并非它的设计用途,应予以劝阻,因为如果你之后用圆括号把那组操作括起来,它会产生不同的结果。此外,在上面的示例中,我生成克隆并把它们追加到当前图像列表,是为了演示该操作符。实际上,我应该使用 Duplicate 图像操作符 来复制当前图像列表中的图像。你也应当如此,因为这会让你想做的事情更清晰。MPR: 图像内存寄存器也可用于克隆图像,它在 IM v5 中就已可用。事实上,对于克隆和存储整个图像列表(长度未知)以备后用,它仍是一种有用的方法,而不像上述图像列表操作符那样只针对单幅图像。
-duplicate {count}[,{index_range}]
你可以用 "[-duplicate](https://imagemagick.org/command-line-options/#duplicate)" 从当前图像列表生成图像的额外副本(克隆)(在 IM v6.6.8-7 中加入)。新图像会被添加到列表末尾。与前面(也更老)的 Clone 操作符 不同,它不要求使用圆括号。例如,要为一幅图像制作 N 个额外副本(共 N+1 幅),你可以这样做…… |
magick font_5.gif -duplicate 4 +append seq_duplicate.gif
![[IM Output]](../static/img/basics/seq_duplicate.gif)
注意,这个操作符可以非常快速地生成数百幅图像,不过在图像被处理之前,这些图像只是彼此的“克隆”,它们之间共享实际的图像数据。因此,被复制的图像在内存上非常高效。如果存在多幅图像,则最后一幅图像被复制 N 次…… |
magick font_[0-1].gif -duplicate 3 +append seq_dup_n.gif
![[IM Output]](../static/img/basics/seq_dup_n.gif)
如果你只想把最后一幅图像复制一次,可以使用该参数的“加号”形式。 |
magick font_[0-3].gif +duplicate +append seq_dup_last.gif
![[IM Output]](../static/img/basics/seq_dup_last.gif)
如果你想对某幅特定图像多次复制,可以把图像索引指定为第二个参数。 |
magick font_[0-2].gif -duplicate 2,0 +append seq_dup_index.gif
![[IM Output]](../static/img/basics/seq_dup_index.gif)
参数的索引部分可以包含要被复制 N 次的图像索引列表或范围。例如,把整个列表复制两次,以创建三倍于原始数量的图像……
magick font_[0-4].gif -duplicate 2,0--1 +append seq_dup_list.gif
通过使用一个反向的图像列表,也很容易创建出 巡逻循环(Patrol Cycle) 类型的动画列表。 |
magick font_[0-9].gif -duplicate 1,-2-1 \
-set delay 50 -set dispose previous -loop 0 seq_reverse_anim.gif
![[IM Output]](../static/img/basics/seq_reverse_anim.gif)
注意,我没有复制整个图像列表,而是跳过了对第一幅(0)和最后一幅(-1)图像的复制,使图像索引为 -2 到 1。如果你的 IM 版本早于 v6.6.8-7,你仍然可以用 Clone 图像操作符 生成重复图像,但一次只能生成一组图像。或者,使用一种基本上算是误用 颜色变形操作符(Color Morph) 的技术来生成多幅重复图像。诀窍是先做一次克隆以生成两幅完全相同的图像,然后用 "[-morph](https://imagemagick.org/command-line-options/#morph)" 在它们之间生成最后 N-2 幅图像。 |
magick font_7.gif \( +clone \) -morph 3 +append seq_dup_morph.gif
![[IM Output]](../static/img/basics/seq_dup_morph.gif)
不过请注意,由于误用了 颜色变形操作符,这些图像实际上是被处理过的,因此 morph 需要花时间来实际处理这些图像(即便没有产生任何变化)。此外,所创建的图像将包含原始数据的实际副本,而不是简单的、节省内存的克隆。
组合图像序列操作
使用这些操作符,你可以提取某幅特定图像的副本、修改它,然后把该图像放回它原来的位置。例如,这里我对第 2 幅图像(图像索引 '1')做一次 "[-clone](https://imagemagick.org/command-line-options/#clone)",把图像的颜色从蓝色旋转到红色,然后先用 "[-delete](https://imagemagick.org/command-line-options/#delete)" 删除原图像、再用 "[-insert](https://imagemagick.org/command-line-options/#insert)" 插入新图像,从而用修改后的图像替换原图像。 |
magick font_[0-3].gif \( -clone 1 -modulate 100,100,166 \) \
-delete 1 -insert 1 +append seq_update_1.gif
![[IM Output]](../static/img/basics/seq_update_1.gif)
另一种似乎变得更常见的做法,是用 "[-swap](https://imagemagick.org/command-line-options/#swap)" 替换原图像,然后用 "[+delete](https://imagemagick.org/command-line-options/#delete)" 删除现在位于末尾的旧图像。这只需要你给出两次图像位置,而不是三次。一次用于克隆,一次用于替换修改后的图像。 |
magick font_[0-3].gif \( -clone 2 -modulate 100,100,166 \) \
-swap 2 +delete +append seq_update_2.gif
![[IM Output]](../static/img/basics/seq_update_2.gif)
这些技术将在下一节 复杂图像处理与调试 中继续讨论。
复杂图像处理与调试
得益于 图像序列操作符(见上文)的加入,你不再需要一步一步地处理图像、每次都保存图像再重新读取它。相反,你现在可以简单地把中间图像保留在内存中并继续处理它。这能节省大量时间,既省去了把图像转换为某种文件格式的时间,也省去了把图像保存到慢速磁盘的实际 IO。这类图像处理命令可能变得非常长、非常复杂。因此最好把命令写在脚本里,并尽量把每个主要操作单独放在一行,以便于编程和编辑。见 编写更好的 ImageMagick Shell/PHP 脚本的提示。例如,这里我走完一整套复杂的处理序列,在黑色背景上生成一个红色按钮。 |
magick -size 30x30 xc:black -fill white -draw 'circle 15,15 5,15' \
\( +clone -shade 110x90 -normalize -negate -alpha Off \) \
\( +clone -clone -2 -compose Plus -composite \) \
\( -clone 0 -shade 110x50 -normalize -alpha Off \) \
\( +clone -gamma 1,0,0 \) \
\( -clone 2,-1 -compose Multiply -composite \) \
-append seq_process_fx.gif
![[IM Output]](../static/img/basics/seq_process_fx.gif)
magick 命令的每一行都生成一幅新图像,除了最后一行——在那里我只是把所有工作图像 拼接 在一起,以输出所有处理步骤的结果,而非仅仅输出最终图像。这种技术让你能够跟踪这条非常复杂的命令在每个步骤(包裹在圆括号中)所产生的结果,并便于对一个流程中的每个步骤进行调试。注意,它只用初始图像的尺寸和形状来生成按钮的初始形状,所以你可以随意使用任何你喜欢的形状或图像!命令的其余部分会像之前那样处理它。当然,你通常会 删除 所有临时工作图像。也就是说,我会把上面命令的最后一行替换成类似这样的东西……
-delete 0--2 seq_process_result.gif
检查结果的其他方式,是把结果通过管道送入 display 命令,以便在屏幕上查看结果,而不是把它保存到图像文件。也就是说,最后一行用类似这样的东西……
+append miff:- | display -
或者,除了 "[display](#display)" 之外,你也可以使用 'show:',它会把结果图像显示在屏幕上,然后允许原始命令继续或退出。更多信息见 Show,显示图像输出。
+append show:
实际上你甚至不需要 "[+append](https://imagemagick.org/command-line-options/#append)",那样 IM 会依次显示每一幅图像,通过按“空格键”切换。你甚至可以更花哨一些,用 "[montage](#montage)" 命令以更美观的方式查看结果……
miff:- | montage - -bordercolor blue -border 1 -geometry +2+2 show:
这种图像处理方式还便于在图像刚被创建时立即查看中间图像。基本上,你可以在 "\( ... \)" 语句之间插入这样的行。
\( +clone -write show: +delete \)\
一旦该中间图像为显示目的而被输出,IM 会自动继续处理。见 Show,显示图像输出。或者,改为插入下面这行,你可以显示在处理到该点之前所生成的全部当前图像……
\( -clone 0--1 -append -write show: +delete \)\
在你把图像处理步骤调试好、确定下来之后,就可以优化代码,使其不使用那么多圆括号步骤,也使用更少的 克隆图像,从而在末尾需要 删除 的中间图像也更少。还要记住,"图像合成" 和/或 "图层扁平化" 会把多幅图像合并在一起,只留下一幅结果图像,这可以减少内存中中间图像的总数。 |
magick -font Ravie -pointsize 48 -background black -fill white \
label:'IM' -bordercolor black -border 5 seq_label.gif
magick seq_label.gif -alpha Off \
\( +clone -shade 110x90 -normalize -negate \
+clone -compose Plus -composite \) \
\( -clone 0 -shade 110x50 -normalize -gamma 1,0,0 -alpha Set \) \
-delete 0 +swap -compose Multiply -composite seq_button.gif
![[IM Output]](../static/img/basics/seq_button.gif)
ImageMagick 能够以标准的、程序化的、自动化的方式,在单条命令中用多个步骤处理任何图像,这正是它如此强大的原因。你可以脚本化一个非常复杂的操作,然后把它应用于许多图像。图像列表操作符和圆括号让 IM 的强大程度提升了一个数量级,使你能够用更少的命令编写更复杂的图像操控程序。关于把复杂图像处理脚本化在一起的另一个示例,见 由形状脚本化生成的 3D 项目符号。另见 编写更好的 ImageMagick Shell/PHP 脚本的提示,了解改进你的图像处理脚本的方法,既便于编辑和理解,也便于他人跟随你所做的工作。
图像元数据:属性、属性值与工件(Attributes, Properties and Artifacts)
到目前为止,我们看的是图像以及构成图像的实际内容或数据。但图像不仅仅是“图像数据”。还有许多属性或元数据也是图像的一部分,会影响其图像处理,以及其他程序应如何处理该图像。例如,一幅图像可能有一个“偏移”,或者是更大的“虚拟画布”(页面)的一部分。也就是说,一幅图像可能只是更大画面的一小部分,该画面由一系列其他图像构成,以形成“图层”或“动画”。IM 还为图像附加了许多特殊的“设置”,许多图像处理操作符会用它们来修改其工作方式。例如要使用的“背景色”。其中有些是全局设置,在整个图像列表中相同;而另一些则可能对列表中的每幅图像各不相同。那么,还有哪些东西也是图像的一部分呢?很多东西……
- 通常(尽管并非总是)随图像保存在图像文件格式中的图像元数据。例如:配置文件(profile)、标签、说明文字和注释,以及虚拟画布信息(页面)。这些都是逐图像的设置,可以对当前图像列表中的每幅图像各不相同。
- 许多不同图像处理操作符所使用、但一般不随图像保存的全局设置:诸如 background、bordercolor、fill 和 mattecolor 等颜色,还有 font、pointsize、gravity、compose 方法、颜色通道处理、颜色值的读/写位深。
- 用于控制特定图像处理操作符更深层、更底层操作的专家级设置和 define。例如:扭曲视口、特殊的 compose 方法参数。
- 图像实际上要在 ImageMagick 内如何存储于内存中:例如以 RGB 还是 CMYK。是否存在 alpha 通道,以及是否启用,还有图像读入时可能曾有的调色板。不过其中某些存储设置是在编译时硬编码的(例如内存中颜色值的 Quality)。
- 一些一般性的 IM 操作设置,例如调试或 verbose 设置,通常用于控制信息输出或错误处理。
也就是说,有大量信息可以被保存,并/或影响图像的处理方式。虽然它们可以归入若干组,但 ImageMagick 对这些事物中每一项处理得有多好、它们是全局的还是图像专属的,都在很大程度上取决于所涉及的具体事物。是的,我说得很含糊,因为不落到具体上,就很难不含糊。这也可能非常令人困惑。所有这些值都以三种不同方式与内存中的图像一起存储……
- 属性(Attributes)
- 这些作为每幅图像的特殊数据结构项存储,一般是为了让各种图像处理操作符能够快速、直接地访问。例如:图像尺寸、虚拟画布几何、background、fill、stroke、matte 颜色、pointsize、density、font、compose、interpolate、virtual-pixel 方法、profile 块、时间延迟和处置(disposal)设置;以及许多其他东西。注意,其中有些是每幅图像“专属”的,而另一些则被 CLI 接口当作“全局”设置,在所有图像上设为相同值,尽管它们仍作为每幅独立图像的一部分存储。属性通常作为正常图像处理的一部分,用众多选项来修改,或者更一般地用 Set 来修改。
- 属性值(Properties)
- 这些是一组自由格式的键值字符串,逐幅地附加到每幅图像上。每幅图像可以有一组完全不同的字符串。本质上它们是不需要被经常访问或解码、或以某种特殊方式使用的元数据项。这方面的典型例子有:label、caption 和 comment 字符串;创建和修改日期;用户自定义字符串;某些操作符的结果。用户可以用 Set 来设定或更改它们,只要其“键”不对应某个已知的“属性”。
- 工件(Artifacts)
- 这是一组在所有图像间通用的全局自由格式字符串。它用于保存自由格式的全局设置,这些设置定义或修改所有图像的读取和图像处理。其中一个例子是 "
verbose" 设置,它使某些操作输出关于其动作的一般信息,包括更冗长的 magick identify 输出。用户可以用 Define(见下文)来修改这些全局值,或用 Set 的一种特殊形式(见 使用 Set "Option:" 来定义工件)。
理解这三种存储方法,是了解 ImageMagick 内部设置和元数据处理工作方式的关键。它能让你做到一些非常高级、通常难以实现的图像处理技术。
设定/更改图像属性/属性值
简单元数据是图像属性,往往对图像处理具有最大的重要性。它们如此重要,以至于被解码并放入图像数据结构中,以便图像处理操作符快速使用。这类数据一般以两种方式修改。一种是在图像被读入或创建时直接更改图像元数据。另一种是对已在内存中的图像修改其元数据。例如, "-label 'string'" 会为该设置设定 之后 读入或创建的每一幅图像设定 comment(注释)。然而 "-set label 'string'" 会更改当前图像列表中所有已在内存中的图像的 'label' 元数据。之所以有两种方法,是出于历史上的向后兼容性和便利性。基本上,"-label" 传统上是在它所要应用的图像被读入 之前 设定的。它只影响在它被设定或更改 之后 读入(或创建)的图像。例如……
magick -label one image_one.png \
-label two image_two.png output_image_list
另一方面,"[-set](https://imagemagick.org/command-line-options/#set)" 操作符会更改当前图像列表中的所有图像,包括此前读入的图像。因此你通常必须使用圆括号来限定该选项所应用的图像,除非你想把它应用于到目前为止读入的所有图像。
magick \( image_one.png -set label one \) \
\( image_two.png -set label two \) output_image_list
你可以用 "+label" 取消该设置,这样在图像被读入或创建时其 label 元数据会保持不变。如果读入的图像本身也没有 label,IM 会回退到某个合乎逻辑的默认值。对于 label 而言,那就是空字符串。你可以在 Montage 为图像加标签 中看到这两种方法更详细、更具体的示例,那里为了加标签的目的大量使用了这一点。这种设定图像元数据的“二元性”,也存在于其他选项中。这包括…… "[-comment](https://imagemagick.org/command-line-options/#comment)"、"[-caption](https://imagemagick.org/command-line-options/#comment)"、"[-page](https://imagemagick.org/command-line-options/#page)"、"[-dispose](https://imagemagick.org/command-line-options/#dispose)" 和 "[-delay](https://imagemagick.org/command-line-options/#delay)"。不过,虚拟画布尺寸和图像偏移设置(页面)还有第三种方法,即使用特殊操作符 "[-repage](https://imagemagick.org/command-line-options/#repage)"(见下文 虚拟画布)。
例如,这里我使用所有可用的设定方法,来设定各幅图像的“虚拟画布偏移”或“页面”,并由它们创建一个 动画…… |
magick -delay 100 -dispose Background \
-page 100x100+5+10 eye.gif \
-page +35+30 news.gif \
\( storm.gif -set page +62+50 \) \
\( tree.gif -repage +10+55 \) \
-loop 0 animation_page.gif
![[IM Output]](../static/img/basics/animation_page.gif)
如你所见,在从各个独立图像文件创建多图列表时,传统(非 set)方法更简单。但当你需要更改已被读入内存、或由某种复杂图像处理方法创建的图像时,"[-set](https://imagemagick.org/command-line-options/#set)" 或专门的 "[-repage](https://imagemagick.org/command-line-options/#repage)" 操作符更好。例如,要更改上一个示例中第三幅图像(图像索引 '2',即 'tree')的图像偏移…… |
magick animation_page.gif \
\( -clone 2 -set page +55+10 \) -swap 2 +delete \
animation_mod.gif
![[IM Output]](../static/img/basics/animation_mod.gif)
关于在图像列表中提取和修改各个图像的更极端示例,见 对动画逐帧修改。这里是另一个示例,使用 "[-set](https://imagemagick.org/command-line-options/#set)" 为所有图像指定一个注释,然后修改其中某一幅特定图像。
magick xc: -duplicate 9 \
-set comment 'T minus %[fx:n-t]' \
\( -clone 7 -set comment 'We have ignition!' \) -swap 7 +delete \
-format "image #%p : %c" info:
你可以用 "[mpr:](files.html#mpr)" 作为为内存中图像设定属性的另一种方式。例如,这里我们取一幅内存中带有 'Bad' 注释的图像,并把该注释替换为 'Good' 的……
magick -comment 'Bad Comment' rose: \
-write mpr:rose +delete \
-comment Good mpr:rose rose.jpg
magick identify -format "image comment = %c" rose.jpg
这样能行,但极其笨拙、用起来很痛苦,尤其是在处理诸如动画之类的多幅图像时。事实上,在 IM 版本 5 中,这是更改内存中图像元数据的唯一方法。(真恶心!)
一般性全局属性
施工中
这些属性中的大多数通常是在把图像读入内存之前或之后全局设定的(没有区别)。
它们通常用作对后续图像处理操作的一般控制。
* 许多设置只是被全局保存起来以备需要时使用
-fill -background -bordercolor -strokecolor -mattecolor -quantize
+dither -channels -size -gravity -units -density -font -pointsize
-tile
* 某些设置影响图像如何保存到磁盘,或随图像保存的元数据。
这包括
-loop -compression -quality -depth
-density -background
* -compose 比较棘手,因为它只能全局设定。但若未设定,
则各个图像可以有不同的设置(用于分层)。
不过其中大多数都可以被关闭(使用 + 形式),这会
使操作符从图像元数据中获取该设置
(例如:+background 在存在时回退到原始图像的元数据)
但更一般地,它会回退到某个默认值。(例如:
+gravity 回退到 'None',意为未设定任何 gravity)。
其中少数在写出时也会随图像保存。具体来说,
GIF 格式会把 -background 和 -bordercolor 作为图像
属性的一部分保存,不过这些通常会被读取这些图像的
程序所忽略。
你可能已经注意到,某些设置在多个地方被使用。
例如 -density
* 用于读入许多矢量格式图像,如
Postscript、PDF 和 WMF 图像格式。
* 也用于特殊的图像生成器,如 label: caption: 和 text:
* 用作 -annotate -draw 和 -polaroid 操作符中字体绘制的一部分。
* 最后,某些格式把 density 或 resolution 作为图像
文件格式的一部分保存。例如 postscript 包装的栅格
图像、JPEG 和 TIFF。
那么,设置为何会如此令人困惑,也就不足为奇了。
虚拟画布,以及 Page 和 Repage 操作符
| “页面(page)”或“虚拟画布”设置在 IM 中的主要目的,是定义图像的“真实”部分(实际包含彩色像素数据的部分)如何在更大的“画布”语境中放置。当涉及多幅图像、需要它们相对彼此定位以用于 多图层 和 GIF 动画 时,这一点尤其重要。它也被用于(其术语“页面”一词的由来)定义图像在更大的物理纸张或“页面”上的位置,用于 Postscript,或用于生成 文本 的“页面”图像。虽然它最常用于 多图层 和 GIF 动画,但它也涉及在 裁剪 和 修剪 图像时记住图像的原始位置,以及 多图列表合成 和 通用图像扭曲。现在,“页面”定义了两个独立的部分:一个“虚拟画布”或区域,定义图像所处的更大空间;以及“偏移”或图像在该“画布”内实际放置的位置。 | 虽然允许负“偏移”,但“画布尺寸”被限制在从 0,0 到给定宽度和高度的区域内。也就是说,只能指定正向的画布。 |
|---|---|
这两个方面——“尺寸”和“偏移”——密切相关,但你通常希望分别地、或以更受控的方式处理它们。因此,除了正常的 "[-page](https://imagemagick.org/command-line-options/#page)" 和 "[-set](https://imagemagick.org/command-line-options/#page) page" 方法之外,还提供了一个单独的选项 "[-repage](https://imagemagick.org/command-line-options/#repage)" 以允许更精细的控制。具体来说…… |
- +repage
- 不带参数时,会把图像的虚拟画布重置为实际图像本身。也就是说,清除图像可能具有的任何虚拟画布信息。这在应用了诸如 裁剪 和 修剪 之类的图像细分操作符之后往往很重要。在保存为 GIF 或 PNG 图像文件格式之前移除虚拟画布尺寸和偏移尤其重要,因为许多浏览器会把画布/偏移信息作为图像显示的一部分。
- -repage WxH
- 更改现有图像的虚拟画布尺寸,但不重置图像在该画布上的位置。注意,把这个参数提供给 "
[-page](https://imagemagick.org/command-line-options/#page)" 或 "[-set](https://imagemagick.org/command-line-options/#set) page" 会把图像位置重置为 '+0+0',而这很可能不是你想要的。 - -repage +X+Y
- 只是把图像在虚拟画布上移动到这个绝对位置,而不更改图像的画布尺寸。
- -repage +X+Y\!
- 通过把给定的数字(正或负)加到图像现有的偏移位置上,对图像在虚拟画布上做相对移动。
- -repage 0x0
- 尝试找到能包含整幅图像的最佳虚拟画布尺寸。然而对于带负偏移的图像,这会失败,因为没有办法指定带负分量的虚拟画布。为避免问题,它会使用实际图像的尺寸作为可能的最小画布尺寸。也就是说,它绝不会分配带零维度的虚拟画布。
- -repage 0x0+X+Y
- 移动图像的偏移,然后调整虚拟画布大小以最佳地适配图像的新位置。
- -repage 0x0+0+0
- 等价于 "
[+repage](https://imagemagick.org/command-line-options/#repage)"、"[+set](https://imagemagick.org/command-line-options/#set) page" 或 "[-set](https://imagemagick.org/command-line-options/#set) page 0x0"。所有虚拟画布和偏移信息都会被移除。 - -repage WxH+X+Y
- 等价于 "
[-set](https://imagemagick.org/command-line-options/#set) page WxH+X+Y"。也就是说,直接赋予给定的值。
注意,使用 '!' 标志会使给定的偏移成为相对于图像当前偏移的相对位移。也就是说,'-repage +5+0\!" 会把图像偏移向右移动 5 像素,而不修改虚拟画布尺寸。目前无法直接指定虚拟画布尺寸的相对调整。不过可以用 FX 百分号转义 来做到,但这并不常需要。用特定颜色修剪 中给出了一个示例。给图像设定最终的负偏移位置时需要谨慎,因为 GIF 文件格式无法处理这种情况,遇到负值会把它重置为零。此外,某些浏览器在遇到带负偏移的 PNG 图像时会出问题。随图像保存的虚拟画布信息因格式而异。 JPEG |
与许多图像文件格式一样,JPEG 图像根本不保存虚拟画布信息。该信息会被直接忽略和丢弃。 |
|---|---|
| GIF | 虚拟画布的尺寸和偏移会作为其 GIF 动画处理的一部分被保存。但它不会处理负偏移。任何负偏移在保存时都会被重置为零。 |
| PNG | 偏移甚至负偏移都会被保存,但 PNG 文件格式通常不保存虚拟画布信息。不过,由 IM 保存的 PNG 图像会包含虚拟画布尺寸信息,但它只被其他 IM 命令使用。如果 IM 读入一幅不带这个 IM 专属属性的 PNG 图像,它会把图像的虚拟画布设为适当的尺寸,以确保图像在虚拟画布上可见(如同 "-repage 0x0")。对于不带偏移的图像,这意味着虚拟画布与实际图像同样大小。 |
某些格式(如 GIF 和 PNG)保存虚拟画布信息,而另一些(如 JPEG)则不保存。上述所有格式对虚拟画布信息都有各自的局限。只有内部的 MIFF 文件格式没有任何此类局限。注意,"[-page](https://imagemagick.org/command-line-options/#page)" 对 "text:" 和 "ps:" 图像生成器操作符有特殊含义(见 Text:多行文本文件 和 PS:Postscript 格式化文本和图形)。因此在创建这些图像时,不会使用它正常的画布尺寸和偏移含义。 |
Set 与逐图像属性值
然而 IM 无法为图像可能具有的每一种设置都做一个选项。那根本不可能。不仅如此,用户还常常喜欢添加或定义他们自己的设置。因此,"[-set](https://imagemagick.org/command-line-options/#set)" 选项实际上可以用任意值定义任意设置。如果该设置不是图像的某个特定已知属性(以便允许操作符快速访问的方式保存),它会作为一个“属性值(Property)”(一个字符串数组)保存到图像中,并会在冗长的 "magick identify" 输出的底部附近列出,或者用 百分号转义 检索和展开。例如,内建的 rose 图像会自动生成三个“属性值”:两个日期字符串和一个“签名哈希”。在此基础上,我还添加了我自己用户定义的“属性值”设置。
magick rose: -set my_property my_value -verbose info: |\
sed -n '/Artifacts/q; /Properties/,$ p'
某些图像处理操作符甚至会把具有特殊意义的值作为图像“属性值”返回。它们不被其他操作符需要,因此不作为“属性”存储,而是作为“属性值”字符串保存,供用户可能的使用。例如,最佳适配标签(Best Fit Label) 最终选定的 pointsize 会作为一个特殊的图像属性值保存。 |
magick -size 100x label:Anthony -verbose -identify property_label.gif |\
sed -n '/Artifacts/q; /Properties/,$ p'
| 注意,label: 生成器本身也会设定一个 'label' 属性,它恰好被保存为一个属性值字符串。
---|---
| _所有“属性值”都作为自由格式的字符串数据类型保存,并作为图像元数据存储。
正因如此,并非所有“属性”都被保存为“属性值”,因为许多属性需要由图像处理操作符以数值数据的形式直接保存和使用。一个例子就是虚拟画布的 'page' 属性。_
---|---
这里我使用 identify 的 "[-format](https://imagemagick.org/command-line-options/#format)" 设置,让 IM 输出它所创建并丢弃的那个标签的 pointsize。 |
magick -size 100x label:Anthony \
-format 'pointsize = %[label:pointsize]pts' info:
![[IM Output]](../static/img/basics/property_pointsize.txt.gif)
利用这一信息来生成一幅新的标签图像是个有技巧的活,将在下文讨论。你能用到的最有用的用户定义设置之一,是 "filename:" 设置。例如……
magick rose: -set filename:my_area '%wx%h' 'rose-%[filename:my_area].png'
上面这条会生成一幅名为 "rose-70x46.png" 的图像。作为安全措施,只有带 "filename:" 字符串前缀的用户定义设置才能用在输出文件名内,不过任何名称都可以使用。关于这方面的更多示例,见 文件名百分号转义。
Define 与全局工件
被定义的值称为“工件(Artifacts)”,它们在所有图像间全局定义,使用特殊的 "[-define](https://imagemagick.org/command-line-options/#define)" 操作符设定。这类“工件”的主要用途,是作为 图像文件格式编码器(Coder) 或 图像处理操作符 可用作额外(或带外)设置的特殊设置。基本上,它允许为特定需求添加自由格式的设置,而无需再创建一个“属性”。此外,由于它们是全局设定的,因此不附加于特定图像,而是附加于一个图像序列中的所有图像,并且在尚未读入或创建任何图像时就已可用。 |
注意,API 可以有多个图像列表,各自附加着不同的“工件”集合,但命令行接口(CLI)只有一个活动的图像列表,因此“工件”确实是全局的。 |
|---|---|
| 换句话说,“已定义的工件”为专家用户提供了一种途径,可以在正常参数用法之外,修改特定操作符的正常或标准操作。例如,JPEG 编码器设置,用于读取和写出此类图像…… |
-define jpeg:size=300x200
-define jpeg:preserve-settings=1
-define jpeg:optimize-coding=true
图像扭曲选项,例如……
-define distort:scale=2
-define distort:viewport=44x44+15+0
Resize 滤镜控制,例如
-define filter:blur=0.75
-define filter:support=1.25
某些工件 define 有快捷方式,因为它们被用户非常频繁地使用。例如 "[-verbose](https://imagemagick.org/command-line-options/#verbose)" 操作控制(见下文),其实等价于使用 "-define verbose",从而创建一个 'verbose' 工件。例如……
magick xc: -verbose info: |\
sed -n '/Tainted:/q; /Artifacts:/,$ p'
由此可见,加号形式 "[+verbose](https://imagemagick.org/command-line-options/#verbose)" 只是移除 'verbose' 工件,因而等价于 "+define verbose"。
工件与延迟百分号转义
工件还常用于保存应分配给图像的特殊属性,这些图像是在 define 给出之后读入的。"[-label](https://imagemagick.org/command-line-options/#label)" 设置也只是用用户提供的参数设定一个工件。然后,在一幅新图像被读入或创建之后,这个工件会被转换为一个 'label' 设置或属性值。例如,创建一幅设有 label 的 "rose:" 图像
magick -label "%wx%h" rose: -verbose info: |\
sed -n '/Tainted:/q; /Properties:/,$ p'
也就是说,"[-label](https://imagemagick.org/command-line-options/#label)" 首先定义了所示的 'label' 工件。稍后当 rose 图像被创建(且其尺寸属性已知)时,IM 把那个全局工件转换为一个图像专属的“属性值”,并仅在那时才展开任何 百分号转义。这就是所谓的 延迟百分号转义。同样的情形也发生在其他几个设置型选项上,例如 "[-comment](https://imagemagick.org/command-line-options/#comment)" 和 "[-caption](https://imagemagick.org/command-line-options/#caption)"。正是由于 延迟百分号转义,"[-define](https://imagemagick.org/command-line-options/#define)" 只会保存字符串,而 "[-set](https://imagemagick.org/command-line-options/#set)" 操作符则会进行展开。
使用 Set "option:" 来定义工件
上面我们演示了如何逐图像地 "[-set](https://imagemagick.org/command-line-options/#set)" 特殊用途的个人 属性值。例如…… |
magick -size 80x40 xc: -set myinfo 'I love IM!' \
-gravity center -annotate 0x0 '%[myinfo]' \
property_annotate.gif
![[IM Output]](../static/img/basics/property_annotate.gif)
但由于 属性值 附加于特定图像,你不能在创建新图像时使用它们。例如下面这条会失败…… |
magick rose: -set myinfo 'I love IM!' label:'== %[myinfo] ==' \
-gravity center -append property_append_fail.gif
![[IM Output]](../static/img/basics/property_append_fail.gif)
如你所见,'myinfo' 属性值在被拼接的标签中没有被找到或包含进来。另一方面,全局定义的 工件 对图像生成器是可用的。它们必须如此,以便图像生成器或图像文件编码器能够读取它们以获取各种控制设置。因此,使用 "[-define](https://imagemagick.org/command-line-options/#define)" 会按预期工作。 |
magick rose: -define myinfo='I love IM!' label:'== %[myinfo] ==' \
-gravity center -append artifact_append.gif
![[IM Output]](../static/img/basics/artifact_append.gif)
那么你如何用图像属性值或属性来创建标签呢?"[-define](https://imagemagick.org/command-line-options/#define)" 选项目前不允许使用图像属性值!诀窍是在使用 "[-set](https://imagemagick.org/command-line-options/#set)" 选项时使用一个特殊前缀 "option:"。这个附加项会使 "[-set](https://imagemagick.org/command-line-options/#set)" 定义一个名称为该前缀之后内容的“工件”。例如,这等价于上一个示例。 |
magick rose: -set option:myinfo 'I love IM!' label:'== %[myinfo] ==' \
-gravity center -append property_option_append.gif
![[IM Output]](../static/img/basics/property_option_append.gif)
更重要的是,"[-set](https://imagemagick.org/command-line-options/#set)" 选项会展开 百分号转义。这意味着如果我们有某个逐图像的 属性值,我们可以把它转换为一个全局 工件。例如,这里我创建一个标签,然后把 "label:" 图像生成器所创建的 'label:pointsize' 属性值,转换为一个全局工件 'my_pointsize'。作为工件,这一信息在我创建第二幅标签图像时可用。然后我把两个标签拼接在一起(中间用一条 'gray' 分隔线)。一个非常有技巧的示例。 |
magick -size 100x -gravity center label:Anthony \
-set option:my_pointsize '%[label:pointsize]' \
-set option:my_height '%h' \
-size 100x1 xc:gray \
-size 100x label:'at %[my_pointsize]pt and %[my_height]px high' \
-append property_append.gif
![[IM Output]](../static/img/basics/property_append.gif)
注意上面 "-set option:..." 的放置位置。如果你把它放在创建 "xc:gray" 之后,那么用于设定全局工件的就会是那幅图像了。也就是说,因为只有最后一幅图像的属性值才决定存储在全局工件中的值。原因在于只有最后一幅图像被用来定义工件。实际上,真正发生的是 "[-set](https://imagemagick.org/command-line-options/#set)" 被应用于当前图像列表中的每一幅图像,即便它生成的是一个全局工件。因此,每幅图像都会把自己的属性值赋给该全局工件,替换掉之前赋的值。完成后,只有最后一幅图像“定义了”该工件。 | 目前 'FX 转义' 无法读取属性值或工件。因此你目前不能对这类值做算术运算。
---|---
读取和写入时的图像类型
"[-type](https://imagemagick.org/command-line-options/#type)" 操作符/设置定义了在读入或写出图像时所使用的样式或色彩空间,以确保得到的图像(在内存中,或在图像文件中)是你所期望的样子。作为其一部分,它可能在文件 I/O 时做一些 色彩空间 修改,但仅为确保图像处于预期的形式。例如,"[-type](https://imagemagick.org/command-line-options/#type)" 有一个特殊的 'bilevel' 设置,可用于把图像转换并保存为某些图像格式的双色单色图像。类似地,'TrueColor' 和 'TrueColorAlpha' 可用于强制把 TIFF 图像保存为全彩 RGB 图像,即便该图像实际上纯粹是灰度的。其他设置包括 'GrayScale' 和 'GrayScaleAlpha',它们会确保写出的图像仅为灰度(分别为不带或带透明度)。或者 'Palette',在支持此选项的格式中强制使用索引颜色映射表。在读取图像文件格式期间,'TrueColorAlpha' 的 "[-type](https://imagemagick.org/command-line-options/#type)" 设置会强制正在读取的 JPEG 图像在其内存存储中添加一个 'Alpha' 通道,即便 JPEG 格式本身无法处理透明度。在写入 PNG 文件格式时,把 "[-type](https://imagemagick.org/command-line-options/#type)" 设为 'Pallette' 会强制它使用索引颜色的 "PNG8' 内部图像格式。类似地,使用 "BiLevel" 会强制 IM 对大多数图像文件格式把彩色图像抖动(dither)为黑白。遗憾的是,"[-type](https://imagemagick.org/command-line-options/#type)" 的确切含义和能力取决于你正在读取或写入的具体图像格式。见各个 图像文件格式 示例区。关于具体的 PNG 示例,见 PNG 输出格式。
控制图像质量
Depth - 文件格式位深
Quality(质量)和 Depth(深度) 是讨论论坛和这些示例页面中经常谈到的两个术语,所以我想稍微解释一下。Quality 是 ImageMagick 中的一个编译时设置,用于决定在 IM 内存中以及处理过程中存储图像所用的值的大小。基本上,它指的是某个特定 IM 被编译为支持的 处理质量。Depth 是图像在从图像文件格式读取或保存到图像文件格式时所用的值的大小。因此它更易变,由 "[-depth](https://imagemagick.org/command-line-options/#depth)" 设置控制,或由读入图像的原始“深度”控制。稍后再细说这一点。请记住……
Quality 是“内存中”的值大小,编译进 IM。
Depth 是文件格式的值大小,是可变的。
如今大多数图像格式的深度为 8。也就是说,它们用 8 位(即 0 到 28-1 的值)来保存图像中所用的每个颜色值。即红色 0 到 255、绿色 0 到 255、蓝色通道 0 到 255。更常见的是把这类图像称为 24 位图像(即“每 像素 位数”,而非 "[-depth](https://imagemagick.org/command-line-options/#depth)" 设置所用的“每 值 位数”)。这包括诸如 JPEG 之类的格式。如果还涉及 alpha 通道,那么你会得到 4 × 8 位值,即 32 位/像素的图像。这是 PNG 图像通常使用的,不过这类图像也可以用每值 16 位来保存。许多人所说的 8 位图像(8 位/像素),其实是带 8 位调色板或颜色映射表的图像(整幅图像最多 256 色限制)。实际的像素数据是一个 8 位索引值(0-255),随后用它从颜色表中查找该像素的颜色。也就是说,“栅格”(像素数组)只是一个索引,用于从单独的颜色表中查找实际的像素颜色。换句话说,虽然 8 位图像也有 8 位深度,但这个 8 位是指向颜色查找表的索引,而非实际颜色。GIF 图像就是这方面的一个好例子。这类图像中的透明度通常通过两种方式处理:指定某种特定颜色表示透明(用 "[-transparent-color](https://imagemagick.org/command-line-options/#transparent-color)" 元数据设置来设定),如 GIF 格式;或者对颜色表中特定数量的颜色使用一个特殊的 profile,如某些 PNG8 图像(它和 GIF 一样也是彩色映射图像)所用。总的来说……
24 位图像是:3 × 8 位值 - 仅 3 个颜色通道
32 位图像是:4 × 8 位值 - 3 种颜色 + Alpha 通道
8 位图像是:8 位颜色索引图像,最多 256 色限制
由于大多数图像格式只以 8 位/值的深度保存颜色值,许多人安装 IM 时使用了深度为 8 的 'Q' 即 Quality 级别,它所需内存远少于更常见的 Q16 版 IM,处理图像也更快,往往快 3 倍或更多。这些 Q8 版本在一般图像处理(裁剪等)和格式间转换方面工作良好,也可以很好地用于生成简单图像、标注或叠加图像。然而,虽然低质量的 IM 更快、更省内存,但当你开始使用涉及多次颜色更改、调整大小、变暗、变亮、gamma 或直方图颜色校正等的复杂操作序列时,它就不能很好地工作了。在 Q8 下,内存中的中间图像仍以 8 位质量存储,因此多次操作会各自引入小的、累积的颜色失真。其结果可能是舍入效应,尤其是对接近白色和黑色的极端颜色(见下文)。
Quality - 内存中位质量
请记住,Quality 是 ImageMagick 中的一个编译时设置,用于决定在 IM 内存中以及处理过程中存储图像所用的值的大小。除非从源码重新编译 ImageMagick,否则它无法更改。因此,'Q16' 的 ImageMagick(IMv7 默认)存储相同数量的图像数据所用的内存,至少是 'Q8' 版 ImageMagick 的两倍,并且取决于你的 CPU,可能会慢很多,不过在当今的处理器上这不太可能。同样,你可以编译 'Q32' 和 'Q64' 版本,不过它们不太常见,通常只用于非常高端的图像处理。另见下文新的 HDRI 编译质量选项。'Q16' 的 ImageMagick 还允许你为每个像素值保存更多位信息。也就是说,颜色值作为整数保存,取值范围从 '0' 到 '2^_quality_ -1'。最后那个值在 IM 编程中被称为当前的 'QuantumRange'(或旧的、已废弃的名称 'MaxRGB')。编译 IM 时所用的 Quality 设置越高,在内存中存储图像时颜色值就越精确。这意味着,如果在处理图像时你生成了大量非常小的、轻微的颜色变化,那么这些变化会被保留在 ImageMagick 的内存存储中,并可在后续处理步骤中使用。诸如调整大小、噪声滤镜、模糊、锐化、平均、全局颜色、gamma、直方图修改,或大量复杂的图像合成操作,在 Q8 的 IM 中都可能产生不需要的颜色误差,在结果图像上造成非常明显的颜色伪影。当然,把最终图像保存为 8 位“深度”的图像格式会把这些颜色值“量化”回 8 位,但在内存中处理图像的过程中,图像的中间质量得以保留。有一些格式可以保留 IM 所用的更高质量级别信息。例如 MIFF IM 格式、枚举像素的 TXT 格式,以及 NetPBM 图像格式。然而,虽然 Q8 版的 IM 会让你输出 16 位深度的图像,但这类图像仍只含有相当于 8 位深度的信息,因为内存中根本不存在那种质量可供保存。 | _如果 IM 用 8 位值读入一幅图像(许多图像格式都是如此),图像的“深度”会被设为 8 位,保存时 IM 通常会以同样的 8 位值深度保存图像,即便你用 Q16 版的 IM 处理图像。你可以为该图像覆盖或清除 "[-depth](https://imagemagick.org/command-line-options/#depth)" 设置,从而让 IM 以最适合该图像、匹配 IM 内存质量的深度保存它。
还要注意,许多生成额外颜色的操作符(例如 图像调整大小)也会把内存中图像的“深度”重置为编译时的质量设置,从而让 IM 尝试在可能的情况下以更高深度保存它。
HDRI - 浮点质量
HDRI,即 高动态范围成像,最初设计是为了更自然地表现我们眼睛同时看到一个场景中明亮区域和黑暗区域的能力。在实际图像处理方面,它做的远不止于此。HDRI 版的 IM(默认构建)被编译为对内存中存储的图像使用浮点值,以便让你能对图像操作执行更精确的 HDRI 处理,从而防止此类操作在极端处“裁切”图像颜色。HDRI 在内存存储中使用与默认编译时 Quality 设置 相同的颜色范围。也就是说,值的范围仍从 '0' 到 'Quantum Range',表示黑到白。但这些值用浮点数(C 编程术语中的 'doubles')而非整数保存,从而不会出现把值舍入为整数所带来的“量子”效应。当值超出 'Quantum Range' 或变为负数时,这些值也不会被“裁切”。基本上,你在处理步骤之间损失的信息要少得多。因此,当你打算对图像使用极重的数学处理(涉及负值的临时使用,或强烈缩放到非常小或非常大的值)时,HDRI 是 至关重要 的。对于想要充分利用 快速傅里叶变换(FFT) 能力的用户而言尤其重要,正是在这里你会在这些页面中看到最多的 HDRI 版 IM 的示例。关于编译 HDRI 版 IM 的信息,见 IM 主网站上的 在 ImageMagick 中启用 HDRI;关于 Windows 和 Ubuntu Linux 的具体信息,另见用户论坛上的 傅里叶变换公告讨论。使用 HDRI 时应牢记的一个重要操作符是 "[-clamp](https://imagemagick.org/command-line-options/#clamp)"。该选项会裁切图像中落在图像正常范围之外的值。也就是说,任何负值都会被裁切为零,任何大于 'QuantumRange' 的值都会被设为该值。不过它并不会把浮点值“舍入”为整数。
量子效应,HDRI 与非 HDRI
量子舍入…… 例如,这里我用 Level 和 反向 Level 操作符,把一幅渐变图像的颜色范围压缩到只使用 0 到 15 的值,然后再把它解压回来。所得渐变还会作为图像剖面(profile)显示出来(使用脚本 "[im_profile](../static/img/scripts/im_profile)"),以便更容易观察。 |
# 使用普通的非 HDRI 版 IM……
magick -size 20x600 gradient: -rotate 90 \
+level 0,15 -level 0,15 level_rounding.png
im_profile -s level_rounding.png level_rounding_pf.gif
注意现在可见的严重舍入(量子效应),在渐变剖面中形成阶梯。由于只使用了 16 个灰度级值,你实际上把图像转换成了仅 4 位的色深!注意,这种量子舍入问题在 IM Q8 版本中非常常见,只要做了超出基本调整大小和裁剪的多项图像处理任务就会出现。而更常用的 IM Q16 通过其额外的内存占用解决了这个问题。对 IM Q16 而言,只有在你使用真正重度的图像处理(例如 快速傅里叶变换(FFT),或合并具有不同曝光时间(光强)的图像以生成高动态范围图像)时,量子舍入才会成为问题。这毕竟正是当初把 HDRI 加入 ImageMagick 的原因。烧毁与裁切…… 这里我“拉伸”渐变,使原本的黑白颜色值远远超出 "Quantum Range",然后再恢复回来。 |
# 使用普通的非 HDRI 版 IM……
magick -size 20x600 gradient: -rotate 90 \
-level 20% +level 20% level_clipping.png
im_profile -s level_clipping.png level_clipping_pf.gif
你可以看到,普通 IM 在两端都丢失了信息。较低端的值随着值变为负数而被“烧毁”,较高端的值则随着超出用于存储这些值的整数的最大 'Quantum Range' 限制而被“裁切”。HDRI 版 ImageMagick 的结果……用 HDRI 版的 ImageMagick 重复这两个操作,不会产生上述任何舍入、烧毁或裁切的结果,但会在内存上有额外开销(doubles 比整数需要更多空间)。在速度上,开销不大,由于浮点加速器,在当今许多现代计算机硬件上甚至可能更快。
# 使用 HDRI 版的 IM……
magick -size 20x600 gradient: -rotate 90 \
+level 0,15 -level 0,15 level_rounding_hdri.png
magick -size 20x600 gradient: -rotate 90 \
-level 20% +level 20% level_clipping_hdri.png
im_profile -s level_rounding_hdri.png level_rounding_hdri_pf.gif
im_profile -s level_clipping_hdri.png level_clipping_hdri_pf.gif
如你所见,即便对图像做了重度压缩或拉伸再还原,渐变仍保持完好无损。
在 HDRI 中用 Clamp 强制图像边界
你可以在两个 level 选项之间使用 "[-clamp](https://imagemagick.org/command-line-options/#clamp)",强制把 HDRI 图像“裁切”到正常图像值范围内。例如…… |
# 使用 HDRI 版的 IM……
magick -size 20x600 gradient: -rotate 90 \
-level 20% -clamp +level 20% level_hdri_clamp.png
im_profile -s level_hdri_clamp.png level_hdri_clamp_pf.gif
上面对 "[-clamp](https://imagemagick.org/command-line-options/#clamp)" 的使用,基本上生成了与我用普通非 HDRI 版 ImageMagick 所得相同的图像。然而这幅图像不会与非 HDRI 的结果完全相同,因为虽然 "[-clamp](https://imagemagick.org/command-line-options/#clamp)" 会烧毁和裁切图像中的值,但它不会添加量子舍入效应。因此,这些值只在最终保存到非 HDRI 图像文件格式时才被舍入为整数。"[-clamp](https://imagemagick.org/command-line-options/#clamp)" 选项在使用 HDRI 时可能至关重要,以达成你想要的结果。
HDRI 文件格式
当然,把包含极小、极大或负值的图像保存到普通图像文件格式中,出于与上面相同的原因,也会被裁切、量化,甚至颜色被减少。因此,如果你需要保存尚未“归一化”回 0 到 'Quantum Range' 范围的图像,那么你需要使用少见的浮点图像文件格式之一。一些能处理浮点值(不裁切或舍入)的图像格式包括 NetPBM PFM。这是唯一一种不需要任何额外特殊选项的图像文件格式。
其他图像文件格式也可以使用,但需要一个特殊开关来指明该文件要保存浮点值。具体来说,你需要指定编码器选项 "**-define quantum:format=floating-point**" 以请求在这些文件格式中使用浮点值。"-depth" 设置也可用于定义所用浮点值的类型。如果使用 "-depth 32" 或更小(大多数 IM 版本中的默认值),则使用普通的 "floats"。但如果设定了 "-depth 64",则对写入或读取该图像文件格式的浮点数据使用 "doubles"。可以用这个特殊标志保存浮点值的图像文件格式包括…… TIFF、FITS 和 MIFF。原始数据文件格式 RGB 也会保存(和读取)浮点值,不过该格式不保存图像尺寸,读取时你也需要指定浮点设置。
另一个特殊的编码器选项是 "-define quantum:scale=65535.0"。它会与从图像文件读取的值相乘,从而把值从归一化的浮点值 0.0 到 1.0 缩放到内部值范围 0.0 到 65535.0。所以如果你在读取浮点图像时得到一幅近乎纯黑的图像,试着添加此选项,把所读取的值缩放到合适的范围。
内存到磁盘的直接文件格式 MPC 也会保存 HDRI 版 IM 所用的浮点值,并且不需要任何特殊标志。但与任何 MPC 图像文件一样,只有同一台机器上完全相同版本(特定编译)的 IM 才能正确读取这样的文件。因此它只适合用作脚本化图像处理的临时“快速读取”文件,而不适合长期存储。
我应该使用哪个 Q 级别
总之,我应该使用什么类型的 ImageMagick?Q8、Q16,还是 HDRI?Q8 内存占用较小,因为图像值像大多数图像文件格式那样以 8 位值保存在内存中。对于基本合成、图像格式转换、简单的“一次性调整大小”或在图像上绘制,Q8 就“足够好”了。Q16 内存占用翻倍,因为颜色值以 16 位值(更高精度)保存。但如果你打算做涉及多层操作的重度图像处理,例如对同一幅图像在同一条命令中做“色彩空间更改(哪怕只是 sRGB 与 RGB 互转)、调整大小、扭曲、模糊、阴影”等等(出于同样的原因这是推荐做法),那么有 16 位会更好,因为它会在处理步骤之间保留图像较低的精度。然后你还可以在命令之间以 16 位文件格式(PNG、MIFF、PbmPlus)保存,即便最终保存又回到 ICO 和 JPEG 之类的 8 位图像文件格式。(出于这个原因,这是默认设置)下一个级别是 Q16 HDRI,它把精度提升到 32 位浮点值,让你能够处理变得非常小或非常大的图像值,而没有图像的舍入和裁切效应。你甚至可以处理负值,尤其是在某些色彩空间中。本质上,它用于在以极端方式处理图像时防止图像数据丢失,例如使用 HDRI 图像、傅里叶变换,或者在对原始数据做数学处理时可能遇到的高水平压缩、扩展。这就是一言以蔽之的总结。对于大多数涉及扭曲、多图像合成和图像处理效果的操作,Q16 是不错的折中。如果内存紧张但你只做简单操作,就用 Q8;如果你在做极端操作,就用 HDRI。
图像密度或分辨率
图像的 密度(Density) 是图像的空间分辨率。也就是说,密度(一般表示为 dpi,即每英寸点数)定义了各个像素相距多远(或多大),从而定义了图像在现实世界中的整体尺寸,一般用于在现实世界设备上显示或打印图像。它只是随图像存储的一个数字,用于告诉打印机和显示器等输出设备应以每英寸多少点(或像素)来显示该图像;或者对于 postscript、PDF、MWF 和 SVG 之类的矢量格式,则是绘制图像中可能用到的任何现实世界坐标时所用的像素比例。它与图像实际的像素尺寸,或定义图像颜色“分辨率”的内存中 Quality 和保存文件格式 Depth 完全无关。你可以在图像被读入 IM 时,用 "[-density](https://imagemagick.org/command-line-options/#density)" 功能在读取或写入图像 之前 设定其分辨率或密度,或在读取图像 之后 用 "[-set](https://imagemagick.org/command-line-options/#set) density" 设定。可以用 "[-units](https://imagemagick.org/command-line-options/#units)" 设置来定义密度数值是以默认(传统印刷)术语 'PixelsPerInch' 还是更现代的公制单位 'PixelsPerCentimeter'(PNG 使用后者)表示。例如,一幅 200x200 像素、600 dpi 的图像,在现实世界中将显示为 1/3 英寸见方。另一方面,一幅小得多的 72x72 像素、72 dpi 的图像,在现实世界中将显示为 1 英寸见方,不过相比之下其空间质量不会很好。前者是“照片质量”,后者是“显示分辨率”。在实际中,72dpi 的图像在打印机上会显得“数字感”或“点状”。另一方面,一幅以 1200dpi 拍摄的大型现代数码照片,要在显示器上展示,可能需要 重采样,否则你可能只能看到图像的一小部分。关于图像分辨率和密度的更多信息,见 Resample 调整大小操作符 的说明。关于文本和字体的分辨率和密度的信息,见 Pointsize 与实际字体大小。
Photoshop 与密度
"Photoshop" 图像编辑器会把图像分辨率的一份额外副本保存到图像中一个单独的 profile(名为 '8BIM')里,IM 不会触碰它。因此,如果你用 IM 更改了图像的分辨率,你大概也应该在把它重新载入 "photoshop" 之前从图像中剥离这些 profile,否则你可能看不到任何密度变化。你可以用 "+profile 8bim" 仅从图像中移除该 profile。在一次 IM 论坛讨论 中,Jesper Nilsson(即 stroker)建议你使用程序 "[exiftool](http://www.sno.phy.queensu.ca/~phil/exiftool/)" 来直接修改图像的 Photoshop 标签。例如
exiftool -g -Photoshop:XResolution=300 -Photoshop:YResolution=300 file.tif
基于质量的速度测试
一些速度测试被提交到 IM 论坛,Q8 与 Q16 速度(及 HDRI)。上述文章的大致结果
- 每像素每通道所用的内存量正如你所料。Q8 - 1 字节,Q16 - 2 字节,Q32 及任何 HDRI - 4 字节,Q64(HDRI)- 8 字节。
- 64 位在浮点运算上有显著的精度提升,但任何其他 HDRI 版的 ImageMagick 也有同样的提升。
- 速度方面,Q8、Q16 和 HDRI 速度大致相同(假定计算机有浮点 MPU),Q32 约慢 25%,Q64(HDRI)约慢 50%。
| 注意,Q64 自动使用“双精度长浮点(double long floats)”,而非 64 位整数。它算是一种双精度 HDRI,虽然非常精确,却是所有内存质量设置中最慢的,也最耗内存。
---|---
| _实际速度将取决于你的计算机规格,以及你是否有数学协处理器。如果速度不重要,使用默认的 Q16 或标准 HDRI 大概是最好的。
如果速度重要,那么你应该在自己的设备上、用你在图像处理中通常预期使用的操作,做类似的速度测试。
_
---|---
ImageMagick 特殊控制
IM 还有几个特殊选项,用于控制其操作运行、信息报告,以及调试目的。 -version | 输出 IM 的版本、它所用的图像质量,以及它是何时构建的。输出此信息后 IM 会隐式退出。 | | 在 IMv7 中,如果 "[-version](https://imagemagick.org/command-line-options/#version)" 是命令行上的唯一选项,它会退出。也就是说,它会让最后的“隐式写出”参数变为可选。如果存在任何其他参数,或者它是从脚本(文件或管道)读取的,magick 命令将不会退出,而是继续。
---|---
-list | 这只是一个信息性选项,会列出所请求的项目,然后退出。也就是说,你不能把它与任何其他选项或图像处理一起使用。它纯粹出于信息目的而提供,尤其用于脚本中检查输入选项,以及 IM 是否实现了某些选项。给定的参数定义了你想列出什么信息。例如一份你可以使用的 'color' 名称列表(例如用于 "[-fill](https://imagemagick.org/command-line-options/#fill)"、"[-background](https://imagemagick.org/command-line-options/#background)"、"[-mattecolor](https://imagemagick.org/command-line-options/#mattecolor)"、"[-bordercolor](https://imagemagick.org/command-line-options/#bordercolor)")。而 'font' 则列出 IM 明确知道的字体。下面只是一些更有趣的列表…… | list | "[-list](https://imagemagick.org/command-line-options/#list)" 能列出什么!
---|---
font | 已知字体(IM 也了解 X 和 PS 字体)
type | 文件图像类型("[-type](https://imagemagick.org/command-line-options/#type)")(IM v6.3.5-7 之后)
或字体列表(在该 IM 版本之前)
color | 各种颜色选项的已知颜色名称。
dispose | 所有 GIF 处置设置("[-dispose](https://imagemagick.org/command-line-options/#dispose)")
compose | 可用的 alpha 合成(包括内部方法)
layers | 已实现了哪些多图 "[-layers](https://imagemagick.org/command-line-options/#layers)" 方法
distort | 可用的图像扭曲方法。
morphology | 可用的图像形态学方法。
kernel | 可用的形态学/卷积核。
command | 有哪些命令行选项(设置和操作符两者)可用
configure | 构建 ImageMagick 时所用的配置参数
最后那个“list”设置 'Configure' 非常重要,因为它会告诉你构建 IM 时有哪些库和 delegate 可用。它还包括“点”发布编号,这在旧版本正常的 "[-version](https://imagemagick.org/command-line-options/#version)" 输出中是缺失的。(使用此信息的一个示例见 脚本版本处理。)输出此信息后 IM 会隐式退出。 | 在 IMv7 中,如果 "[-list](https://imagemagick.org/command-line-options/#list)" 是命令行上的唯一选项,它会退出。也就是说,它会让最后的“隐式写出”参数变为可选。如果存在任何其他参数,或者它是从脚本(文件或管道)读取的,magick 命令将不会退出,而是继续。
---|---
-verbose | 报告关于某些更复杂操作的额外信息。
例如 "[-segment](https://imagemagick.org/command-line-options/#segment)",它会输出大量颜色量化细节。
以及 "[-distort](https://imagemagick.org/command-line-options/#distort)",输出额外信息以及所请求图像扭曲的 'FX' 等价形式。还会在迭代 "[-morphology](https://imagemagick.org/command-line-options/#morphology)" 操作时监控更改的次数。这对于从 "[info:](files.html#info)" 和 "[-identify](https://imagemagick.org/command-line-options/#identify)" 输出中生成更详细的图像信息尤其有用。你可以用该选项的“加号”形式 "[+verbose](https://imagemagick.org/command-line-options/#verbose)" 关闭此设置。
-regard
-warnings | '-regard-warnings' 会使某些关于某些图像文件格式的信息性警告变为致命错误。它还会使 IM 根据此类错误条件返回正确的退出状态。它可用于脚本中,以“净化”来自不受控来源的图像文件。也就是说,当 JPEG 或 TIFF 图像不正确、不完整或包含“未知” profile 时,此选项会使 IM 失败并退出。
-precision {number} | 控制有效数字的位数。
当 IM 响应各种调试、verbose 或格式化请求而输出浮点值时,此设置设定你希望该输出有多精确。默认情况下,它会把此类数字限制为 6 位有效数字,但此操作符会增加或减少这个默认值。默认值 6 也可以用 'MAGICK_PRECISION' 环境变量来修改。它影响来自以下方面的输出……
- verbose 的 "
[identify](#identify)" 命令,或 "[-identify](https://imagemagick.org/command-line-options/#identify)"、"[-print](https://imagemagick.org/command-line-options/#print)" 和 "[-format](https://imagemagick.org/command-line-options/#format)" 设置。 - 来自 "
[-fx](https://imagemagick.org/command-line-options/#fx)" 操作符的 'debug()' 输出,以及 '%[fx:...]' 字符串转义。(见 FX,DIY 图像处理操作符) - 当启用了 "
-set option:showkernel 1" 时,"[-morphology](https://imagemagick.org/command-line-options/#morphology)" 核的浮点值。见 显示核。
-quiet | 不报告信息性警告消息。只报告诸如 I/O 错误或错误选项等真正的错误。这对于 "[-crop](https://imagemagick.org/command-line-options/#crop)" 或 "[-trim](https://imagemagick.org/command-line-options/#trim)" 和 "[-layers](https://imagemagick.org/command-line-options/#layers) optimize" 尤其有用,它们在操作符不会产生“真实”图像结果时通常会报告“missed images”警告。它还会让某些复杂图像文件格式的编码器安静下来,这些格式可能包含 IM 通常会忽略的“未知块”。例如当 IM 读取 TIFF 图像,或奇怪的 MPEG(AVI)视频格式时。
-respect
-parenthesis | 使 圆括号 不仅保存和恢复当前图像列表,还保存和恢复所有当前的 操作设置。这意味着给出该选项后,圆括号内设定的任何设置,会在圆括号结束时被重置。见上文 圆括号与设置 中的示例。
-ping | 用于 "identify" 命令。IM 会尽量避免为了诸如图像尺寸之类的基本信息而完整地读取和解码完整的图像文件格式。
-monitor | 在图像处理的每个阶段报告处理百分比,尤其适用于非常大或非常长的图像处理任务。在更底层的 API 中,你会使用 SetImageInfoProgressMonitor() 或 SetImageProgressMonitor()
-debug | 详尽地报告 IM 在各个方面究竟在做什么。参数是逗号分隔的选项列表,例如…… | exception | IM 对该命令哪里不理解
---|---
cache | 查看 IM 缓存了多少磁盘空间
configure | 显示 IM 查找其配置文件的尝试。
trace | 在每个库函数开始处报告跟踪点
annotate | 当字体与 "[-annotate](https://imagemagick.org/command-line-options/#annotate)" 一起使用时,报告字体度量。
command | IMv7 -- 在命令行选项(或脚本)被处理时显示它们。例如:选项处理。
all | 在处理过程中显示每个跟踪点
这非常非常 VERY 冗长,不推荐
如果使用了 "[-debug](https://imagemagick.org/command-line-options/#debug)",日志输出的位置由 "log.xml" 文件控制。它默认设为 "console"。要让它保存到文件,把 <log output="console"/> 改为 <log output="file"/>。对于命令行和 API 用法,你也可以定义一个环境变量来设定 IM 所用动作的调试级别。
export MAGICK_DEBUG=all
限制图像尺寸(简短说明)
为防止内存使用过多,把你的内存限制设为比如 16GB。现在把
磁盘限制设为 4GB。如果超过磁盘限制,ImageMagick 将以
“cache resource exhausted”异常退出。
![[IM Output]](../static/img/basics/cmd_flip_legacy.gif)
![[IM Text]](../static/img/basics/gravity_error.txt.gif)
![[IM Text]](../static/img/basics/identify.txt.gif)
![[IM Text]](../static/img/basics/identify_colors.txt.gif)
![[IM Output]](../static/img/basics/rose.png)
![[IM Text]](../static/img/basics/identify_ping.txt.gif)
![[IM Text]](../static/img/basics/identify_no_ping.txt.gif)
![[IM Text]](../static/img/basics/identify_ping_off.txt.gif)
![[IM Text]](../static/img/basics/identify_maths.txt.gif)
![[IM Text]](../static/img/basics/output_info.txt.gif)
![[IM Text]](../static/img/basics/output_identify.txt.gif)
![[IM Text]](../static/img/basics/output_print.txt.gif)
![[IM Text]](../static/img/basics/output_html.txt.gif)
![[IM Output]](../static/img/basics/gold.gif)
![[IM Output]](../static/img/basics/orange.gif)
![[IM Output]](../static/img/basics/tomato.gif)
![[IM Output]](../static/img/images/eye.gif)
![[IM Output]](../static/img/images/news.gif)
![[IM Output]](../static/img/images/storm.gif)
![[IM Output]](../static/img/images/tree.gif)
![[IM Output]](../static/img/basics/circle.gif)
![[IM Output]](../static/img/basics/mogrify_eye.gif)
![[IM Output]](../static/img/basics/mogrify_news.gif)
![[IM Output]](../static/img/basics/mogrify_storm.gif)
![[IM Output]](../static/img/basics/mogrify_tree.gif)
![[IM Output]](../static/img/basics/cmd_settings_lots.gif)
![[IM Output]](../static/img/basics/seq_delete2.gif)
![[IM Output]](../static/img/basics/seq_swap3.gif)
![[IM Output]](../static/img/basics/seq_clone_reversed.gif)
![[IM Output]](../static/img/basics/seq_dup_list.gif)
![[IM Text]](../static/img/basics/comments.txt.gif)
![[IM Text]](../static/img/basics/comment_change.txt.gif)
![[IM Text]](../static/img/basics/properties.txt.gif)
![[IM Output]](../static/img/basics/property_label.gif)
![[IM Text]](../static/img/basics/property_label.txt.gif)
![[IM Text]](../static/img/basics/artifact_verbose.txt.gif)
![[IM Text]](../static/img/basics/rose_properties.txt.gif)
![[IM Output]](../static/img/basics/level_rounding_pf.gif)
![[IM Output]](../static/img/basics/level_rounding.png)
![[IM Output]](../static/img/basics/level_clipping_pf.gif)
![[IM Output]](../static/img/basics/level_clipping.png)
![[IM Output]](../static/img/basics/level_rounding_hdri_pf.gif)
![[IM Output]](../static/img/basics/level_clipping_hdri_pf.gif)
![[IM Output]](../static/img/basics/level_hdri_clamp_pf.gif)