⚠️ 这是一个非官方翻译网站,与 ImageMagick Studio LLC 无关。准确信息请参阅原文(https://usage.imagemagick.org/files/index.html)

ImageMagick 示例 -- 图像文件处理

ImageMagick 示例 前言与索引
图像格式概览
读取图像

图像格式概览

ImageMagick 最常见的用途之一,根本不是修改图像,而只是把图像从一种图像格式转换到另一种。事实上 IM 最初被创造出来的原因正是这种图像格式转换。这也是为什么 IM 的主命令叫做 "magick"。为此,ImageMagick 能够处理种类繁多到令人眼花缭乱的图像与文件格式。除此之外,还有大量用于内置测试图像、简单图像创建,以及专为 shell 脚本和程序编程而设的特殊输入输出格式。完整列表请参见 IM 网站上的 IM 图像格式页面。这些对 ImageMagick 的新用户来说可能会让人不知所措。我的最佳建议是:忽略掉绝大多数文件格式,因为你很可能永远都用不到它们。相反,专注于你想做的事,并设法去做。如果你不知道怎么做,就试着在这些页面和网络上寻找示例。关于 IM 示例中演示过的图像格式,请参见 参考索引:文件格式


读取图像

IM 默认会尝试通过文件内部的「magic」文件识别码来判定图像的格式类型。但如果这一步失败,你就需要用文件后缀来指定图像的文件格式,或者添加一个格式前缀。有些格式根本不会读取任何文件,并会忽略给出的任何文件名。下面是一些常见的内置图像……

  logo:      granite:     rose:

其中一些会根据作为文件名给出的参数来生成图像,可能还会用一个额外的 "[-size](https://imagemagick.org/command-line-options/#size)" 来控制最终图像的大小……

  -size 30x30  canvas:red
  -size 30x30  gradient:yellow-lime
  -size 30x30  pattern:fishscales
  magick import:

在某些情况下,你甚至可以使用多种格式……

  -size 30x30  tile:pattern:gray95

不过在这个例子里这样做有些多余,因为 'pattern:' 格式编码器本身已经内置了 'tile:' 编码器。但它确实能让你的意图更清晰。IM 也可以通过指定图像的 URL 来下载发布在「万维网」上的图像。这本质上提供了一个 'http:' 图像编码器,所以它才能工作。 |

  magick http://www.ict.griffith.edu.au/anthony/images/anthony_castle.gif \
          -resize 100x100 castle_logo.png

[IM Output]
如你所见,这条命令从 WWW 读取图像,调整其大小,然后最终把结果保存到磁盘。 | 当给出了文件格式前缀时,作为文件名一部分给出的任何后缀都不会影响文件被读取的方式。这一点在读取某些文件格式时其实非常关键,例如 "[text:](text.html#text)" 与 "[txt:](#txt)" 文件格式的处理就有区别。当然,如果某个图像生成器实际上会读入一个图像文件以特殊方式处理它(例如 "[tile:](canvas.html#tile)"),那么后缀(或前缀)文件格式就又变得重要了,正如上一个例子中那样。
---|---
有一个特殊的编码器前缀 "implicit::" 可用于「关闭」任何编码器的使用,从而允许在文件名中使用 ':'。文件名中可以嵌入特殊的「文件元字符」,例如 '*' 和 '?'。IM 会展开这些字符以生成要读入的文件名列表,从而避免需要外部 shell 来做这件事,也避免命令行长度限制带来的问题。例如……

  magick montage  '*.jpg' -geometry 50x50+2+2  image_index.gif

这会为当前目录中所有 JPEG 文件生成一张索引拼贴图。但请注意,我需要给参数加上引号,以防我的 UNIX shell(而不是 ImageMagick)来展开这些文件名。关于 "magick montage" 更完整的说明,请见下文。当然,Linux shell 也可以展开未加引号传给它们的 '*' 和 '?' 字符。然而在某些情况下,如果文件列表展开成数量极大的文件名,你可能会遇到「命令行限制」。以下是用 Linux shell 展开文件名的其他示例……

  magick image_[0-9].gif  image_[1-9][0-9].gif  animation.gif
  magick image_?.gif  image_??.gif  image_???.gif  animation.gif
  magick image_(?|??|???|????).gif  animation.gif

另请参见下文的 读取帧,读取修饰符,了解文件名中带格式化递增数字的用法。如果文件名仅仅是单字符字符串 '-',IM 会从标准输入读取图像。 |

  cat tree.gif | magick - -frame 5x5+2+2 read_stdin.gif

[IM Output]
请注意,有些图像文件格式允许你直接把多个图像文件追加在一起,形成一条长长的多图数据流。这些格式包括简单的 PbmPlus/NetPBM 图像格式,以及 IM 自己的特殊文件格式 MIFF: |

  for image in eye.gif news.gif storm.gif
  do
    magick $image  miff:-
  done |
    magick - -frame 5x5+2+2 +append read_multiple_stdin.gif

[IM Output]
文件名开头的特殊字符 '@' 意味着用给定文件的内容来替换该文件名。也就是说,你可以读入一个包含文件列表的文件! |

  echo "eye.gif news.gif storm.gif" > filelist.txt
  magick @filelist.txt  -frame 5x5+2+2 +append filelist.gif

[IM Output]
你也可以把 '@' 与特殊文件名 '-' 配合使用,从标准输入读取文件名。 |

  echo "eye.gif news.gif storm.gif" |\
    magick @- -frame 5x5+2+2 +append filelist_stdin.gif

[IM Output]
| 使用 '@' 语法从文件读取文件名列表的功能是在 IM v6.5.2-1 中加入的。
---|---
| 作为一项安全预防措施,这只对真正的图像文件有效。它不能用于 "rose:" 或 "label:string" 这类图像生成器。它也不能用来从文件中「包含」命令行选项。
---|---

读取修饰符或 Extract 设置

图像在被读入内存之后、但在实际加入当前图像序列之前,可以立即被修改。你可以指定一个 "[-extract](https://imagemagick.org/command-line-options/#extract)" 设置。例如,这里我裁剪 rose 图像…… |

  magick -extract 32x32+20+5 rose: +repage rose_extract.gif

[IM Output]
或者你可以用方括号 '[...]' 在文件名末尾追加一个读取修饰符。例如…… |

  magick 'rose:[32x32+20+5]' +repage  rose_read_modifier.gif

[IM Output]
但请注意,'[]' 字符通常也是特殊的 shell 元字符,所以如果你使用它们,最好给这个额外的修饰符加上引号,以阻止 UNIX shell 去解释它。"[-extract](https://imagemagick.org/command-line-options/#extract)" 设置和读取修饰符做的是同样的工作,不过后者会覆盖前者。另外,当你使用修饰符时,你必须让 IM 来处理任何特殊的文件展开元字符,例如 '*' 和 '?',因为由于带了修饰符,UNIX shell 将无法「找到」所请求的文件。在那种情况下它实际会做什么,取决于 shell 的实现。因此,使用读取修饰符时整个文件名都应加上引号。这些读取修饰符的真正用途,是通过在图像仍在被读入内存的过程中移除不需要的图像或缩小图像,来限制所需的内存量。例如读入整整一个目录的大 JPEG 图像时。下面列出所有特殊读取修饰符(以及 "[-extract](https://imagemagick.org/command-line-options/#extract)" 设置)及其效果。'#' 代表某个数字。

'[#]' '[#-#]' '[#,#,#]' [#,#-#,#]'。读取帧

将从已读入的、多图文件格式的图像中选取特定的子帧。给定的数字 '#' 索引指定要读取的帧号。可以用逗号顺序或索引范围来指定多个索引。图像索引从第一张图像的 0 开始,第二张为 1,依此类推。如果你指定负索引,则从图像序列末尾倒着计数,-1 为最后一张,-2 为倒数第二张。这与 图像列表操作符 所用的约定完全相同。例如

magick document.pdf'[0]' first_page_of_pdf.gif magick animation.gif'[1-3]' second_to_fourth_frames.gif magick animation.gif'[-1,2]' last_then_the_third_frame.gif


你也可以让 IM 基于一个数字列表来读取图像。例如……

  magick 'image_%03d.png[5-7]' ...

将会读入文件 "image_005.png"、"image_006.png" 和 "image_007.png"。用这种方法你不能使用负索引。

'[#x#]' 读取缩放

从 IM 版本 6.2.6-2 起新增了一个修饰符,帮助 IM 用户处理超级大的图像。这个修饰符会在刚读入的图像被加入到内存中已有的其他图像之前,立即对它进行缩放。这既可以缩小图像,也可以放大图像。例如…… |

magick pattern:gray95'[60x60]' enlarged_dots.gif


[IM Output]
警告:该读取修饰符目前不使用任何缩放标志,例如 '!'(不保持纵横比)或 '>'(仅缩小较大的图像)。(也许你提个请求就会加上?)你也可以把它作为指定纯色画布尺寸的另一种方式。其实背后发生的是它在缩放那个默认的单像素图像。例如…… |

      magick 'canvas:DodgerBlue[50x50]'  canvas_size.gif

[IM Output]
当你试图读入大量超级大的图像时,这个修饰符最为重要,因为每张图像会在读取下一张之前先被缩放,从而在处理这些图像所需的总内存上带来可观的节省。例如,与其用……

  magick montage '*.tiff'  -geometry 100x100+5+5 -frame 4  index.jpg

它会先把所有 tiff 文件读入,然后再调整它们的大小。你可以改为这样做……

  magick montage '*.tiff[100x100]'  -geometry 100x100+5+5 -frame 4  index.jpg

这会把每张图像读入并调整大小,然后再继续处理下一张图像。结果是内存占用大大降低,并且在达到内存限制时,可能避免磁盘交换(抖动 thrashing)。对于 JPEG 图像,我还建议你改用特殊的 "[-define](https://imagemagick.org/command-line-options/#define)" 设置,写成类似这样……

  magick montage -define jpeg:size=200x200 '*.jpg[100x100]' -strip \
          -geometry 100x100+5+5 -frame 4  index.png

该特殊设置会被传给 JPEG 库,用于在读取过程中限制 JPEG 图像的大小。但它并不精确,得到的图像大小会在该尺寸与该尺寸的两倍之间,并保持纵横比。详情请参见 读取 JPEG 图像。这种组合的结果是对 JPEG 图像而言读取快得多、内存占用也更低。在生成大量小缩略图时尤其如此。请参见 缩略图创建通论

'[#x#+#+#]' 读取裁剪

从 IM v6.3.1 起,如果你还加上一个偏移量,上面的操作就变成对正在读入的图像进行裁剪。例如,要从一张大得多的图像中取出一个较小的 600x400 像素子区域。

magick 'image.png[600x400+1900+2900]' tileimage.png


不过这仍然会把整张图像读入内存,然后再裁剪它,最后才加入当前图像序列。如果你想处理真正巨大的图像,我建议你看看 "[stream](basics.html#stream)" 命令,并把图像管道传给 "magick" 命令做进一步处理。请参见下文的 超大图像处理。 如果图像是 "gzip" 压缩过的,IM 会在尝试判定图像格式并解码图像文件格式之前,自动把它解压到一个临时文件中。因此你不仅可以以 gzip 压缩格式保存图像,还可以在后续 IM 处理中直接使用它们。对于大型的基于文本的图像,这能带来巨大的磁盘空间节省。 | PNG 格式把 "gzip" 压缩作为其格式规范的一部分。在这种情况下,两位数的 PNG "[-quality](https://imagemagick.org/command-line-options/#quality)" 设置中的第一位定义压缩级别。更多细节请参见 PNG 图像文件格式 示例。
---|---
以上只是读取图像到 ImageMagick 时可用的特殊输入选项的简短概览。完整的概述请见 ImageMagick 网站 上的 命令行剖析 页面。
如前所示,图像输入可以被一些 IM 设置修改,例如用于图像创建的 "[-size](https://imagemagick.org/command-line-options/#size)",以及用于 JPEG 读取的 "[-define](https://imagemagick.org/command-line-options/#define) jpeg:size=??"。其他选项也会影响图像输入的创建,包括 "[-page](https://imagemagick.org/command-line-options/#page)"、"[-type](https://imagemagick.org/command-line-options/#type)"、"[-dispose](https://imagemagick.org/command-line-options/#dispose)"、"[-delay](https://imagemagick.org/command-line-options/#delay)"。请参见 设置/更改图像元数据。 | 在脚本中把用户提供的参数传给 IM 时要非常小心,确保该参数就是你所预期的。比如你绝不希望一个网络图像处理脚本返回的是系统密码文件的图像。
---|---

输入文件名元字符处理

施工中

不仅 shell 会处理元字符(除非该参数被加了引号),IM 自己也会对文件名
做自己一套的元字符处理。

例如
  magick *.jpg ....

会在文件名传给 IM 之前由 shell 展开,而

  magick '*.jpg' ....

会让 shell 把 "*.jpg" 传给 ImageMagick,然后 ImageMagick 把它展开成
一个内部的文件名列表!这是为了支持 Windows Dos,并作为一种方法,
用以在 "magick mogrify" 和 "magick montage" 这类通常要处理长长图像
列表的命令中防止命令行长度溢出。

因此,要让 IM 实际读取磁盘上字面命名为 '*.jpg' 的文件,你需要使用
下列任意一种形式……

  magick '\*.jpg' ....
  magick "\*.jpg" ....
  magick "\\*.jpg" ....
  magick \\\*.jpg ....

注意:不推荐第二行,因为某些 shell(非 bash)和某些 API(C 程序,
也可能是 PHP)实际上可能会去掉那个单反斜杠,并把 '*.jpg' 传给 IM,
于是 IM 又会去展开它!

除了 '?' 和 '*',IM 还为读取修饰符处理增加了元字符 ':'、'%'
和 '[...]' 的处理。不过它们的含义(编解码器指定、场景号包含、读取修饰符)
与这些元字符在普通 shell 语法中的含义不同。

例如,DOS 用户在把文件路径传给 ImageMagick 时,需要对路径中的「盘符」
进行转义。例如……

  magick C\:\path\to\image.jpg ....

另一个例子是加载一个文件名中包含时间码的图像。例如……

  magick "time_10\:30.jpg" ....

会从磁盘读取文件名 "time_10:30.jpg"。没有那个反斜杠,IM 可能会认为
应该用一个不存在的图像文件格式(或委托(delegate))"time_10:" 来读取
图像,并以意想不到的方式失败。

另一种办法是使用问号……

  magick "time_10?30.jpg" ...

但这也可能匹配到另一个文件,比如 "time_10_30.jpg"!

压缩图像

施工中

只要给出合适的后缀或图像格式指定,IM 也会读取被压缩过的文件。

也就是说,保存为 "image.gif.gz" 的图像会先被解压,然后再从其 GIF
图像格式解码。

Gzip 压缩的 XPixmap (xpm) 和 NetPbm/PbmPlus (ppm) 图像也会被自动处理,
既由 Imagemagick 处理,也由这些格式的普通委托(delegate)库处理。因此,
你可以直接在 IM 中、或在其他理解这些文件格式的程序中使用其压缩形式。

请参见下文的 [保存压缩图像](#save_gzip)。

保存图像

处理图像固然好,但以正确方式保存结果同样重要。"magick"、"magick montage" 和 "magick composite" 的最后一个参数定义一个文件名和一个用于图像最终写出的图像格式(默认图像输出)。不过你也可以在图像序列中途用 "[-write](https://imagemagick.org/command-line-options/#write)" 保存图像(见下文)。要指定你希望以何种文件格式保存图像(或多张图像),你可以使用文件名后缀(就像我在几乎所有这些示例中所用的那样),也可以在文件名前加上字符串 "{format}:"。例如…… |

  magick tree.gif    GIF:tree_image

[IM Output]
如果你检查得到的图像,会发现实际创建的是一个 GIF 图像文件,即便文件名本身并没有 ".gif" 文件后缀。格式的大小写不敏感,所以你可以用小写或大写。当你想把图像保存到命令的标准输出(用 "-" 文件名)时,这种图像格式指定就尤为重要。这个特殊文件名没有后缀,所以你_必须_告诉 ImageMagick 用什么格式。如果不告诉,图像将默认采用其来源图像的原始图像格式(若已知)。例如,这里我们用 "-" 把结果输出到标准输出,从而把一份 IM 像素枚举写到屏幕上。

  magick tree.gif  -resize 1x3\!  txt:-

[IM Text]

它还用于把图像通过 shell「管道」传给另一个命令(例如 "magick identify"),而无需保存到临时文件。

  magick tree.gif -resize 200% miff:- | identify -

[IM Text]

在这个例子里你也可以看到,特殊文件名 "-" 同样被用来表示由 "magick identify" 命令从标准输入读取图像。更多信息请参见官方指南 命令行剖析,输出文件名

文件名百分号转义

保存文件名中可以包含若干特殊的百分号转义(%)序列。具体来说是 '%d'、'%x' 和 '%o'。它们用 C 语言 'printf()' 的格式把图像的「场景号」插入文件名。更多信息请参见下文的 写入多图序列。当然,这意味着如果你想在文件名中插入一个百分号字符,你需要把它写成双倍('%%')。从 IM v6.4.8-4 起,你现在还可以把特殊的预设设置(必须以 'filename:' 开头)插入最终文件名。例如…… |

  magick rose: -set filename:mysize "%wx%h" 'rose_%[filename:mysize].png'

[IM Output]
这会把内置的 rose 图像保存到一个文件中,文件名里包含该图像以像素计的尺寸。具体来说就是文件名 "rose_70x46.gif"。这能让你(稍加间接处理)把任意 图像属性百分号转义 用作输出文件名的一部分。请注意,只有 '%[filename:_label_]' 这种图像 属性 才能用于输出文件名中(连同普通的 '%d' 转义)。这个限制是出于安全原因,也因为合法的图像文件名本身可能包含 '%' 和 '[]'。警告:不要把文件后缀放进文件名设置里!IM 不会看到它,并会用原始文件格式而不是文件名设置里包含的格式来保存图像。也就是说,文件名会带上你指定的后缀,但图像格式可能不同!'filename:' 设置不必对每张图像都相同。你可以为每张使用的图像生成、甚至计算或设置不同的设置。下面是另一个例子,我修改一张图像,并把它写到一个新文件名中,该文件名是基于每张图像各自的原始文件名构建的。

  magick eye.gif news.gif storm.gif    -scale 200% \
          -set filename:f '%t_magnify.%e' +adjoin '%[filename:f]'

[IM Output] [IM Output] [IM Output]

这会放大每张图像(例如 "eye.gif"),并把它保存到当前目录中的文件 "eye_magnify.gif"。然而这三张图像都被读入内存,然后由这一条命令修改。对于若干大图像,或者非常大量的图像,这并不是推荐的方案,因为有可能触及内存限制,从而进入磁盘交换(抖动)。请注意,本例中的 "[+adjoin](https://imagemagick.org/command-line-options/#adjoin)" 至关重要,它用来防止 IM 把所有图像保存成一个多图 GIF 动画、且只用第一张图像的文件名。我也确保用 "%e" 转义序列保留了文件名的原始后缀。通常把后缀放进文件名设置里是个坏主意,因为当后缀来自转义序列时,IM 在判定输出文件格式时看不到它。不过在这个例子里格式并未改变,所以没有问题。需要小心。要得到图像确切的原始文件名,请用 '%d/%f' 或 '%d/%t.%e'。你也可以用 '%m' 代替 '%e',它是 IM 在原始图像文件中实际发现的格式(大写形式)(它可能与原始图像文件名的后缀不一致)。请注意,对于内置图像,许多这类转义序列字符串是空白的。另外,如果没有目录,则 '%d' 将为空白。这是 IMv7 的一个已知问题。使用「文件名转义序列」的另一个例子见 瓦片裁剪图像,其中该技术被用来基于每张结果图像计算出的瓦片位置来生成文件名。另请参见 用 Convert 代替 Mogrify 中的示例。

自动 GZip 后缀

如果给出 ".gz" 后缀,IM 还会自动对图像进行 "gzip" 压缩。例如,这里我把内置的 "rose:" 图像保存为一个 "gzip" 压缩的、未压缩的 GIF 文件。我关闭了 GIF 通常的 LZW 压缩,因为它会妨碍 "gzip" 压缩达到最佳压缩效果。 |

  magick rose: -compress none  rose.gif.gz


浏览器如何处理一张 gzip 压缩的图像,取决于 web 服务器返回的文件类型以及你的浏览器如何处理压缩图像。因此我没有直接显示上面的图像。点击那个「art」图标,看看你的浏览器如何处理来自此 web 服务器的这种图像。把它的大小与正常保存的 LZW 压缩 GIF 图像比较一下…… |

  magick rose: rose.gif

[IM Output]
"gzip" 压缩后的 rose 大小为 [IM Text] 字节,而正常 LZW 压缩的 rose 为 [IM Text] 字节。如你所见,GZIP 压缩实际上略优于 GIF 格式所用的 LZW 压缩,因此可能更适合归档目的。GZip 压缩的图像文件更常用于那些默认没有任何压缩的图像文件格式的长期存储。这包括 IM 文件格式 "MIFF:" 以及较简单的 NetPBM 图像文件格式。

保存的属性

施工中

其他专用于图像写入的设置……
    -depth  -quality  -compress -type  -loop
    -set label   -set comment
另请参见 [图像深度](basics.html#depth)、
[图像类型](basics.html#type)、
[JPEG 质量](formats.html#jpg_write)、
[PNG 质量](formats.html#png_quality)。
[GIF loop](anim_basics.html#loop)。

讨论文件压缩,它们是各种图像格式的一部分。

不同的图像格式使用不同的压缩方式。

尤其是所需的 JPEG 到 TIFF 压缩切换。

使用 "[-compress](https://imagemagick.org/command-line-options/#compress)
None" 以及 "[-compress](https://imagemagick.org/command-line-options/#compress)" 的 NetPBM 文本/二进制格式选择。

GIF 压缩与版权专利问题。

除了用 IM 来降低 -quality 或把格式改成别的之外,-compress 选项很少使用。
它通常只被 IM 内部使用,用来以读入图像时所用的相同压缩方式保存图像。

加密图像

IM 还允许你用一个口令短语对敏感图像进行加密保存,使用选项 "[-encipher](https://imagemagick.org/command-line-options/#encipher)" 和 "[-decipher](https://imagemagick.org/command-line-options/#decipher)"。请参见 加密图像

写入多张图像 - Adjoin 技巧

保存图像的一个主要问题是,ImageMagick 处理的是一个有序的图像序列(列表),而不是一次只处理一张图像。因此,IM 会尝试把当前图像序列中的所有图像写入给定的文件名。如果文件格式允许多张图像,IM 默认会把当前图像序列中的所有图像都保存进那个图像文件。例如,如果你查看 GIF 动画基础 示例页面,你会看到它会把多个图像帧保存进单个图像文件格式以生成动画。如果输出格式不允许你把多张图像保存进同一个文件,IM 则会生成多个文件。例如保存为 JPEGPNG 等图像格式时。你也可以用 "[+adjoin](https://imagemagick.org/command-line-options/#adjoin)" 输出文件处理设置,在那些确实允许每个文件包含多张图像的图像格式(如 GIFPS)上强制这种行为。

  magick eye.gif news.gif storm.gif  +adjoin  image.gif

[IM Output] [IM Output] [IM Output]

如果你仔细看上面生成的三张图像的文件名,你会发现 IM 生成的图像名为 "image-0.gif" 到 "image-2.gif"。 在 ImageMagick 6.2.0 版本之前,上述输出文件名会是 "image.gif.0" 到 "image.gif.2"。这会因丢失文件名后缀而导致许多问题,因此改成了在文件名后缀之前加上图像编号。
另一种办法是在输出文件名中加入一个「C 语言 printf()」构造 "%d"。这个特殊字符串会被替换为序列中每张图像的当前图像编号。
  magick eye.gif news.gif storm.gif  +adjoin  image_%d.gif

[IM Output] [IM Output] [IM Output]

这里我们生成了图像 "image_0.gif" 到 "image_2.gif",使用下划线而不是 IM 默认的短横线。 | _你不仅可以用 '%d' 表示十进制数,还可以用 '%x' 表示十六进制数(小写)、'%X' 表示十六进制数(大写)、或 '%o' 表示八进制数。

_
---|---
| _如果你真的想要一个百分号字符后面跟着这些字母之一,那么你需要把百分号字符写成双倍以转义其含义。也就是说,你需要用 '%%' 来确保真正生成一个百分号符号。


---|---
| _输出文件名中的 '%d' 实际上会自动启用 ImageMagick 的 "[+adjoin](https://imagemagick.org/command-line-options/#adjoin)" 设置。
不过虽然上面其实不需要 "[+adjoin](https://imagemagick.org/command-line-options/#adjoin)",但还是把它加上可能更好,这样能清楚表明你是在生成分开的图像。

---|---
这对少量图像效果不错,但如果你有超过十张图像,你就会得到一位数和两位数编号混杂的图像。而如果你有超过一百张,还会出现三位数编号。当那种情况发生时,目录列表将不再按序列出已保存的图像,因为 "image_15.gif" 会在字母序上排在 "image_5.gif" 之前。当然有办法解决这个问题。例如使用命令行 shell 表达式,如……

  magick image_[0-9].gif  image_[1-9][0-9].gif  animation.gif
  magick image_?.gif  image_??.gif  image_???.gif  animation.gif
  magick image_(?|??|???|????).gif  animation.gif
  magick 'image_%d.gif[0-123]'  animation.gif

最后一种方法是 IM 处理文件序列的正规方式,不过你需要知道你想使用的数字范围。'%d' 会格式化每个数字以匹配文件名(见下文)。无论如何,这都很笨拙且易出错,文件缺失时会产生错误,并且可能依赖于你所用计算机系统的类型。最好完全避免这个问题。如果你熟悉 'C' 语言(查一下 'printf' 的 UNIX 系统 man 手册页),那么你大概知道,如果你用类似 "%03d" 这样的写法,你总会得到三位数编号(带前导零)作为图像序列帧号。那种情况下图像名将是 "images_000.gif"、"images_001.gif",依此类推。

  magick eye.gif news.gif storm.gif  +adjoin  image_%03d.gif

[IM Output] [IM Output] [IM Output]

用这种方法,图像不仅会被编号,还会在字母序上正确排列,从而让图像文件处理变得轻松得多。因此我建议,每当你打算把多张图像写为单独的图像文件时,都给输出文件名加上 '%03d'(或其他合适的写法)。

写出的场景号

如果你想让图像序列从 '1' 而不是 '0' 开始,又不想重命名所有得到的图像文件,最简单的办法是在要写出的序列前面预先加上一张「垃圾」图像。

  magick null:  eye.gif news.gif storm.gif  +adjoin  image_%01d_of_3.gif
  rm image_0_of_3.gif

[IM Output] [IM Output] [IM Output]

当然,你也可以在图像处理之后用 "[+insert](https://imagemagick.org/command-line-options/#insert)" 来做这件事。这不是一个特别优雅的方案,但它有效、简单,并且与较旧的 IM 主要版本向后兼容。从 IM 版本 6.2 起,你可以用 "[-scene](https://imagemagick.org/command-line-options/#scene)" 设置来为当前图像序列设定起始编号。

  magick eye.gif news.gif storm.gif  +adjoin -scene 101 image_%03d.gif

[IM Output] [IM Output] [IM Output]

它生成了图像文件 "image_101.gif" 到 "image_103.gif"。

多次写入一张图像

既然说到写入图像,那么可以用特殊的 "[-write](https://imagemagick.org/command-line-options/#write)" 图像操作符,在一连串图像操作的中途写出一张图像。当你想在图像处理过程中的若干节点多次输出图像时,这非常有用。例如,参见 带调试的复杂图像处理。下面这个例子里我有一张 若干鹦鹉的照片,承蒙 Kodak Lossless True Color Image Suite(图像 23)提供,但我想用一条命令把它们保存为一系列不同尺寸……

  magick parrots_orig.png \
          \( +clone -resize x128  -write  parrots_lrg.jpg +delete \) \
          \( +clone -resize x96   -write  parrots_big.jpg +delete \) \
          \( +clone -resize x64   -write  parrots_med.jpg +delete \) \
                    -resize x32           parrots_sml.jpg

[IM Output] [IM Output] [IM Output] [IM Output]

如你所见,我们可以用 图像列表操作符 处理图像的一个「克隆」,写出结果,然后删除并回退到原始源图像,按需多次重复这个过程。在这个具体例子里,这意味着我不会反复对同一张图像缩放,从而避免累积缩放误差。它也意味着我同样可以轻松地先生成较小的图像、再生成较大的图像,不会有问题,或者为每个生成的图像文件以许多不同方式修改图像。也就是说,每张图像的顺序和修改是无关紧要的!请注意,"[+clone](https://imagemagick.org/command-line-options/#clone)" 实际上并不复制图像数据!IM 使用一种引用计数的克隆过程,只在像素被更新时才复制它们。因此在上述过程中,实际只用到了足以容纳原始图像和新生成图像的内存。这也使得 "[+clone](https://imagemagick.org/command-line-options/#clone)" 非常快且内存高效。
下面是做同样事情的另一种技巧,但用一个命名的图像寄存器 "[MPR:](#mpr)"(见下文)来保存原始图像,而不是用 "[-clone](https://imagemagick.org/command-line-options/#clone)"。

  magick scroll.gif  -background lightsteelblue -flatten  -alpha off \
          -write mpr:scroll  -resize x128  -write scroll_lrg.jpg +delete \
                 mpr:scroll  -resize x96   -write scroll_big.jpg +delete \
                 mpr:scroll  -resize x64   -write scroll_med.jpg +delete \
                 mpr:scroll  -resize x32          scroll_sml.jpg

[IM Output] [IM Output] [IM Output] [IM Output]

这里我们在写出之后修改仍在内存中的图像之前,先把原始图像的一份副本保存进 "mpr:scroll" 图像寄存器。请注意,一个 MPR 寄存器实际上可以保存一整个图像序列。一旦该操作的结果被写出并从内存删除,原始图像(或图像序列)就会被恢复,并按需多次重复这个过程。当然,和前面一样,对最后一张图像没必要用 "[-write](https://imagemagick.org/command-line-options/#write)",因为我们可以正常输出它。如果你确实对最后一张图像用了 "[-write](https://imagemagick.org/command-line-options/#write)",那你可以改用另一种特殊文件格式 "[NULL:](#null)"(见下文)把最后一张图像丢弃。关于 "[-write](https://imagemagick.org/command-line-options/#write)" 的一句警告:由于有些文件格式要求图像在写入时处于特殊格式,"[-write](https://imagemagick.org/command-line-options/#write)" 操作符可能会修改图像。例如 GIF 图像可能会被减色(见 量化与抖动)。但其他格式会原样保留源图像(见下文的 MIFFMPC)。如果你需要防范这些改动(因为你不是写完后就直接删除该图像),你可以用 "[+write](https://imagemagick.org/command-line-options/#write)",它会为写入制作一个图像的内部克隆,然后写完即删除它。但请记住,这可能导致内存占用翻倍,以保存写入时被修改的图像副本。至少在那一瞬间是这样。


特殊文件格式(IM 专有)

正如你上面所见(并将在下一节 常见图像文件格式 中探讨),ImageMagick 理解数量庞大的知名图像文件格式。它还包含相当数量的特殊图像生成器(如 画布创建 中所举的例子)。在这些之上,还有一些非常特殊的文件格式,可以实现对图像的一些非常特殊的处理。

miff:

是 ImageMagick 文件格式。整个图像序列以及与这些图像相关联的_所有_属性都会保存进这种文件格式。当然,只有 ImageMagick 命令才能读取此格式,所以它不适合在不同图像处理软件包之间传输。"miff:" 文件格式的主要用途,是在以漫长而复杂的方式处理图像时作为中间保存格式。它也适合把图像从一个 IM 命令「管道传送」到另一个命令,同时传递与图像相关联的图像元数据和其他属性。我建议在写出 "miff:" 时加上一个 "[+depth](https://imagemagick.org/command-line-options/#depth)" 选项。这会把图像的「输入深度」重置为 IM 的内存质量,以便为中间图像的保存使用尽可能最佳的质量。当然,你也可以用 "-depth 8" 来「裁剪」保存图像的深度,从而减小磁盘上的图像大小,但这同样会强制产生 量化舍入 效应(除非也启用了 HDRI 浮点保存)。对于有兴趣解析此格式的人来说,它以一段包含所有图像属性的纯文本头部开始。该头部以一行只含单个换页符的行结束。这个头部本身就是在各种图像处理脚本中提取基本图像信息的一种有用方式。例如,这里我用一条 GNU-sed 命令列出 "miff:" 头部直到换页符分隔符为止,显示内置 "rose:" 图像的所有属性。

magick rose: miff:- | sed -n '/^\f$/q; p'


[IM Text]

这其实非常有用,因为它揭示了 IM 所知道的关于该图像的所有当前设置标志和元数据。不过还有统计信息,这些信息是由 "magick identify" 命令、"[-identify](https://imagemagick.org/command-line-options/#identify)" 操作符或特殊的 "info:" 格式生成的;前提是配合 "[-verbose](https://imagemagick.org/command-line-options/#verbose)" 选项请求(见下文)。该图像文件格式的解析要求非常低,虽然不压缩,但能处理 IM 所知道的任何类型的图像。它几乎是用于临时图像和管道化图像命令的最理想格式,尽管只有 ImageMagick 程序才能读取它。另请参见下文的 "[MPR](#mpr)" 图像内存寄存器,以及 "[MPC](#mpc)" 内存磁盘映射格式。 | _原始图像数据(二进制)实际上前缀有四字符序列 "\n\f\n:"(单独成行的换页符,加一个冒号)。这些数据应如何读取被编码在头部数据中,但通常由 RGB 三元组形式的二进制整数组成。但也可以有更多通道,甚至可以由浮点数乃至双精度数据值组成。

在许多方面,它实际上几乎等同于一个二进制 PbmPlus 图像文件格式,只是带有一个大为扩展的头部以容纳图像元数据,以及在通道数量和数据类型上有更多变化。_
---|---

MIFF 图像流

"miff:" 格式是一种「流式」图像文件格式。也就是说,处理多张图像只需简单地把图像一张接一张地追加或拼接在一起。这意味着你可以仅通过把图像写到同一个目的地(例如一个管道)来生成多张图像的「数据流」。即使各张图像是由不同命令生成的也可以。例如,下面先生成一个以字母 'b' 开头的颜色列表,然后用一个 "magick" 命令循环来逐个生成带标签的颜色色块。这些随后被「管道传送」给一个 "magick montage" 来生成一张简单的颜色表。

magick -list color | egrep '^b' | \ while read color junk; do \ magick -label $color -size 70x20 xc:$color +depth miff:-; \ done |\ magick montage - -frame 5 -tile 6x -geometry +2+2 \ -background none color_table.png


[IM Text]

上述这个具体示例已被编入一个脚本 "show_colors ",你可以用它来搜索、查找并显示颜色,供你在图像处理中使用。上面是一个「流式图像管道」的例子,它对于生成多图序列非常有用。这种技术的其他例子包括 分层图像的程序化定位地图上的图钉按名称的颜色 中的「命名颜色图像」,以及如 随机涟漪 中所示的动画。这种技术也可以与 "-write miff:-" 这类操作一起使用,从而在一条命令的多个位置输出一张 miff 格式图像。每张图像都会在最终输出流中自动追加在一起。这对于调试复杂的图像处理命令尤其有用。另一种方法(在 PHP 脚本中常用)是使用「生成命令」技术,即用一个 shell 脚本生成一条很长的 "magick" 命令来运行。图像扭曲动画 中的脚本就使用了这种技术。

info:

"info:" 文件格式(在 IM v6.2.4 中加入)_不_输出实际的图像!这个格式基本上输出与 ImageMagick "magick identify" 命令所输出的相同信息。和 "magick identify" 一样,这个输出格式由 "[-format](https://imagemagick.org/command-line-options/#format)" 和 "[-verbose](https://imagemagick.org/command-line-options/#verbose)" 选项控制,让你只输出你感兴趣的特定信息,由 图像属性转义 页面所定义。例如,与其像上面那样把一张 MIFF 图像管道传给 "magick identify"(见 保存图像),我们本可以使用下面这种方式来获取所得图像格式的单行标识。

magick granite: info:-


[IM Text]

当然,你可以用 "[-format](https://imagemagick.org/command-line-options/#format)" 设置以一种特定且更易解析的方式输出所需信息。"info:" 之所以如此有用,是因为你现在可以在生成图像的同时,提取关于它的额外信息。这通过用 "[-write](https://imagemagick.org/command-line-options/#write)" 操作符把这种特殊图像格式保存到文件(或命令的正常标准输出)来实现。 | |

  magick rose: -shave 12x0 -repage 64x64+9+9 \
          -format '%wx%h %g'  -write info:info_paged.txt    paged.gif

[IM Output]
| | [IM Text]


还有一个 "[-identify](https://imagemagick.org/command-line-options/#identify)" 操作符,等价于用 "[-write](https://imagemagick.org/command-line-options/#write) info:" 把图像标识信息输出到标准输出。这让你在调试 IM 命令时更容易监控图像发生了什么。例如…… | |

  magick logo:           -identify \
          -trim           -identify \
          +repage         -identify \
          -resize 80x80\! -identify \
          logo_thumbnail.gif

[IM Output]
| | [IM Text]


在这里你可以看到 "[-trim](https://imagemagick.org/command-line-options/#trim)" 如何缩小了图像的尺寸,却保留了图像哪部分被修剪掉的「裁剪」信息,然后 "[+repage](https://imagemagick.org/command-line-options/#repage)" 移除了那个额外的「画布」或「页面」信息。依此类推。另外,和 "magick identify" 命令一样,如果打开 "[-verbose](https://imagemagick.org/command-line-options/#verbose)" 设置,"[info:](#info)" 和 "[-identify](https://imagemagick.org/command-line-options/#identify)" 都会变得啰嗦得多。这里我把那长长的输出限制到只取前几行,只是让你对它有点概念。

  magick rose: -verbose  info:  | head

[IM Text]

| _"[-verbose](https://imagemagick.org/command-line-options/#verbose)" 设置还会导致关于正在读入或写出的图像的额外信息被打印到标准错误("info:" 格式除外)。它也会导致某些操作符(如 "[-colors](https://imagemagick.org/command-line-options/#colors)")输出额外信息。因此,在与 "[-identify](https://imagemagick.org/command-line-options/#identify)" 或 "info:" 格式一起使用之后,你可能会想再把它关闭。

例如 _ "-verbose -write info:image_info.txt +verbose" "-verbose -identify +verbose"
---|---
| 脚本化读取任何形式的 "[identify](basics.html#identify)" 的输出时,都应以大小写不敏感的方式进行。这能确保不同 ImageMagick 版本之间更好的向后兼容性。
---|---
注意:"info:"(以及 "[-identify](https://imagemagick.org/command-line-options/#identify)")只是一个输出格式,产生与 "[identify](basics.html#identify)" 命令相同的输出。你不能用 "info:" 文件格式读取或创建图像。你也可以用 "[-print](https://imagemagick.org/command-line-options/#print)" 来打印信息,但它只对整个图像序列应用一次。这意味着你可以用这个操作符来计算涉及多张图像的、复杂得多的 '%[fx:...]' 表达式。但请记住,与上面的其他方法不同,它在所有图像上只应用一次。

null:

作为输出格式,它会直接「丢弃」图像结果。因此,如果在 "magick"、"magick montage" 或 "magick composite" 命令中把它用作最后一个参数,最终结果将不会被保存!为什么?嗯,可能是因为你更关心图像处理过程中生成的特定图像,而不是整体结果,尤其是在调试时。例如,这里我们从一个图像序列中提取并保存一张图像,然后用 "null:" 丢弃所有其他图像。 |

magick eye.gif news.gif storm.gif tree.gif rose: logo: \ ( -clone 2 -write write_storm.gif ) null:


[IM Output]
这比试图一张张删除所有其他图像要简单得多。不过作为输入图像格式,"null:" 会在当前图像序列中生成一张特殊的占位图像,它是单个透明像素,带有一个特殊的「null 源」标志。这种特殊图像对于 在拼贴图中留出空缺 尤为重要,并可作为多图 图层合成 的列表分隔符。它与另一种被称为「缺失图像」的特殊图像格式密切相关,后者可由 "[-crop](https://imagemagick.org/command-line-options/#crop)" 等操作生成。当某个操作产生空的或无意义的结果时,就会产生这种图像格式。这两种图像都是单个透明像素,因此 "null:" 图像也会被当作「缺失图像」对待。目前还没有办法从当前图像序列中移除任何 "null:" 或「缺失图像」。不过这样一种方法已被提出。如果你发现需要这样一种方法,请给我发邮件。

txt:

这是一个简单的 ASCII 文本文件,它基本上把图像中的每个像素逐行列出,一行一个。它不是一个通用的文本到图像转换器,那个请参见 多行文本文件示例。如果「像素枚举」未被识别,图像会被传给 "[text:](text.html#text)" 格式编码器,渲染为纯文本文件。例如,这里把一张 "netscape:" 图像缩放为 2x2 像素的图像,然后用 "txt:" 图像格式列出。

magick netscape: -scale 2x2! txt_netscape.txt


[IM Text]

图像的第一行(头部)塞满了关于图像的基本信息。这些信息包括…… File Magic: 图像头部把这个文件定义为特殊的 IM 文本图像格式(例如 "ImageMagick pixel enumeration" 文件),这在计算机界被称为文件的「magic」,即把这个文件标识为这种特定文件格式的代码字符串。 Image Size: 接下来的两个数字定义此文件中所含图像的大小。把这两个数字相乘还会告诉你头部之后应有多少行才能完整定义该图像。IM 总会输出这么多行,不过你稍后会看到,读取时你并不需要定义所有的像素。 MaxValue: 头部中最后一个数字定义图像数据可能达到的「最大值」。在上面的例子里这是 '255',这是使用 8 位深度的结果。它之所以以这个深度输出内置的 "netscape:" 图像,是因为该图像在内部是用 8 位值定义的,因此 IM 为该图像保留了这个深度级别。更多信息请参见关于 深度设置 的章节。但你可以覆盖深度设置(最高到你的 IM 的 Q 值或 编译期质量 设置的上限),方法是更改图像的 "[-depth](https://imagemagick.org/command-line-options/#depth)"。例如,这里我把颜色值输出为 16 位值(从 0 到 65535)……

  magick netscape: -scale 2x2\! -depth 16 txt_netscape_16.txt

[IM Text]

| 目前你无法为输出文件格式设置一个特定的「最大值」。你只能依据当前的 "[-depth](https://imagemagick.org/command-line-options/#depth)" 设置来定义一个不同的值,使最大值等于 2^depth-1
---|---
Colorspace: 头部中的最后一项定义随后数据的 色彩空间。如果图像包含任何透明度,会再附加一个末尾字母 'a'(表示 alpha)到色彩空间名称上,并在括号之间增加一列额外的数字。灰度图像会把图像输出为 'grey',但会定义至少三个数字,每个像素的这些数字都相同。例如,这里是用 'LAB' 色彩空间 并添加了 alpha 通道的同一张图像!

  magick netscape: -scale 2x2\! -colorspace LAB -alpha set txt_cspace_lab.txt

[IM Text]

在初始头部之后是 Pixel Data 行,图像中每个像素一行。 Coordinates: 直到冒号 ':' 为止的前两个数字是像素位置,从 0 开始。 Color Values: 在此之后,像素的颜色值(从 0 到头部中给出的 MaxValue)写在括号中,根据图像当前的色彩空间,括号里有 3 到 5 个数字不等。空格是可选的,因此在解析括号内的数字时需谨慎。 这些值通常是整数。但从 IM v6.9.2-1 起,如果给出特殊的 define "[-define](https://imagemagick.org/command-line-options/#define) txt:compliance=css" 并配合 "[-depth](https://imagemagick.org/command-line-options/#depth) 16",这些值将以带 '%' 号的百分比值表示。这是 SVG、CSS 合规性的一部分。
Color Comments: 跟在括号内数字之后的任何内容都被视为注释。IM 会用它能作为颜色参数解析的格式填入关于该像素颜色的额外信息(这些颜色规格的细节见 "[-fill](https://imagemagick.org/command-line-options/#fill)" 手册条目)。不过这些颜色注释是可变的,通常它会以一个井号('#')十六进制颜色值开头,之后可能根据给定的像素数据输出 RGB() 值或颜色名称。这些颜色名称应能被 ImageMagick 理解,但仅作参考之用,因为它纯粹是注释。具体提供哪些颜色高度依赖于你所用的 IM 版本,尤其是在早期的 IM v6 版本及之前。无法保证这个注释区域将来不会再次更改,所以最好不要依赖它。IM 在读取像素枚举图像时就不依赖它。下面是一个在 shell 脚本中正确读取像素枚举的例子。TXT 图像的确切格式由 convert 命令定义,然后用 'tail' 丢弃头部,用 'tr' 把每个非数字字符替换成单个空格,以便后面的 'while' 能轻松读取这些数字,丢弃可能残留下来的后面的注释数字。
  magick rose: -resize 3x2\! -depth 8 -colorspace RGB -alpha off txt:- |
    tail -n +2 | tr -cs '0-9.\n'  ' ' |
      while read x y r g b junk; do
        echo "$x,$y = rgb($r,$g,$b)"
      done

[IM Text]

读取 TXT 图像 也是有效的。你不需要定义图像中的所有像素。事实上你甚至不需要让像素按正确顺序排列!ImageMagick 会依次读取每一行像素定义行,并把它「绘制」到一张空白的图像画布上。每行只用括号中的数字来做这件事,而不用颜色名称。初始的空白画布会被清空并设为当前背景色。因此,任何未由 "txt:" 图像提供的像素,都将保持为这个颜色。关于 "txt:" 图像的有趣用法,请看 正向像素映射,在那里我输出一张枚举像素图像,然后更改每个像素位置以旋转(扭曲)图像,再把枚举像素图像重新读回 IM。在得到的图像中,有些像素位置没有被定义,而另一些位置则添加了多个像素。IM 处理这些情况没有问题。
"txt:" 格式与 "[-unique-colors](https://imagemagick.org/command-line-options/#unique-colors)" 操作符配合使用尤为有用,该操作符会用一张新图像替换当前图像序列中的每张图像,新图像为所找到的每种独特颜色各含一个像素。当把它输出到 "txt:" 格式文件时,你会得到图像中所含颜色的基本汇总(不过不含它们的计数或直方图)。例如,这里是 tree 图像所用的颜色。由于 GIF 只能使用 8 位数字,所以颜色也以相同的 深度 输出。 | |

  magick tree.gif -unique-colors txt:-

[IM Output]
| [IM Text]


除了 IM 的 "txt:" 格式,还有另一种替代方案,即使用各种 NetPBM 图像文件格式。IM 默认以二进制输出这种格式,但你可以关闭 "[-compress](https://imagemagick.org/command-line-options/#compress)" 来输出 NetPBM 格式的 ASCII 文本版本。例如。

    magick tree.gif -unique-colors -compress None -depth 8 tree_netpbm.ppm

[IM Text]

你可能会注意到,上面的数字与 IM 的枚举像素("txt:")格式中的数字一致。关于生成供 IM 读取的 NetPBM 格式图像的一些示例,请参见 缩放后的渐变。如果你只想要某个特定像素的颜色,你可以把图像裁剪到一个像素,然后把它输出为 "txt:" 图像。

  magick rose: -crop 1x1+12+26 txt:

[IM Text]

或者你可以用一个特殊的 FX 转义格式 以可直接被 IM 使用的形式输出颜色。

  magick rose: -format '%[pixel:u.p{12,26}]' info:

[IM Text]

另请参见 提取图像颜色

sparse-color:

这是一种特殊的输出图像格式,它会返回一个简单的、以逗号分隔的坐标和颜色列表,对应每个非透明像素。该输出字符串适合直接输入给 稀疏颜色操作符。例如,这会在 "rose:" 图像中找出最「接近」纯红色的那几个像素。

magick rose: -alpha set -fuzz 13% +transparent red sparse-color:


[IM Text]

在许多方面,这比上面展示的 "[txt:](#txt)" 格式更有用,但只有在涉及的像素只有寥寥几个时才如此。但请注意,在撰写本文时,输出全部在一行内。Shell 脚本可能想把输出中的空格转换成换行符。

histogram:

这其实就是 "[miff:](#miff)" 图像格式,但带有一个非常大的图像注释,其中包含图像内所有颜色的完整计数。也就是说,在 "[miff:](#miff)" 文本头部的 'Comment={...}' 属性中。例如,这里我们再次列出 "tree" 图像中存在的颜色,但这次包含每种颜色的像素计数。文本直方图注释通过一次二次的、用 "[info:](#info)" 格式化的 magick identify 从 "histogram:" 图像中提取。 | |

magick tree.gif -define histogram:unique-colors=true \ -format %c histogram:info:-


[IM Output]
| [IM Text]


| _"info:" 输出格式是在 IM v6.2.4 中加入的。对于之前的 IM 版本,请用…… |

  magick tree.gif histogram:- | identify -format %c -

你会注意到,这个格式与之前的 TXT(即 IM 像素枚举图像格式)几乎完全相同,包括关于颜色值的注释。唯一的区别是 X,Y 位置被替换成了该颜色像素数量的计数。 这个注释可能需要很长时间才能生成。从 IM v6.6.1-5 起,如果你不需要它,你可以加上特殊设置 "[-define](https://imagemagick.org/command-line-options/#define) histogram:unique-colors=false" 来关闭这个注释的生成。
图像本身是一张直方图图表,大小为 256x200 像素。x 轴是颜色值(0-255),y 轴是像素计数(归一化到像素总数)。每个通道的直方图以它所代表的颜色显示,并叠加在一起。因此,红色和蓝色重叠形成洋红色。换句话说,每个颜色通道都有它自己单独的直方图。如果你想把图像转换成其他某种格式,只要把它保存成那种格式即可。"histogram:" 是一种特殊的图像处理格式。它会先转换图像,然后以文件名后缀或进一步的 "_format_:" 代码所指定的格式输出。
  magick rose: \
          -define histogram:unique-colors=false \
          histogram:histogram.gif

[IM Output]
非常暗的图像会严重偏向左侧,而明亮的图像会严重偏向右侧。中间调同样位于中间。为了更好地看清这一点,这里我把各个颜色通道的直方图分离开。我还去除了直方图的文本注释(如果仍然存在),并调整图像大小以便显示。

  magick histogram.gif -strip -resize 50% -separate  histogram-%d.gif

---

[IM Output]
红 | [IM Output]
绿 | [IM Output]

对于上面的 "rose:" 图像,你会看到红色分布得更开,显示了它在图像中的至关重要。另一方面,绿色和蓝色在左侧出现尖峰,表明它对图像几乎没有影响。如果你对图像的亮度比对它的颜色更感兴趣,那就在生成 "histogram:" 图像之前先把图像转换为灰度。 |

  magick rose: -colorspace Gray \
          -define histogram:unique-colors=false \
          histogram:histogram_gray.gif

[IM Output]
如你所见,灰度图像的直方图略有不同。由于占主导的红色变成了更偏中间调的灰色,从而在直方图中央产生一个尖峰。另外,图像中那一小块近白色的区域现在在图表最右端产生了一个明显的尖峰。最左端那片完全空白的区域也表明图像中根本没有暗块。另一方面,只需把原始图像中所有颜色通道分离并追加在一起,就能生成一个更好的「全局」直方图。得到的直方图表示了所有颜色值,而不论该值来自哪个通道。 |

  magick rose: -separate -append \
          -define histogram:unique-colors=false \
          histogram:histogram_values.gif

[IM Output]
遗憾的是,由于 "histogram:" 是一个输出格式,如果你想进一步处理这张图像,你需要把它「管道」传给另一个命令、保存到磁盘、或使用特殊的 "[mpr:](#mpr)" 保存/读取。请参见下文 "[mpr:](#mpr)" 中的示例。如果有某种生成直方图(以及其他图表)的方法能作为操作符而不是特殊输出格式提供,那就好了。

mpr:_{label}_

(内存程序寄存器,Memory Program Register)会把整个图像序列保存进一个命名的内存寄存器,之后你可以从中读取图像数据。因此,如果你想保存一张图像以备后用、用于某个复杂的图像操作,你可以这么做。在处理结束时写入 "mpr:" 是没用的,因为程序内存会在程序结束时归还给系统。因此,如果你需要在另一个进程中使用这些图像,你需要用 Write 操作在处理步骤中途把图像保存到文件。给 "mpr:" 的「label」可以是你喜欢的任何东西,它只是图像保存在内存中位置的一个标签。对于那些做脚本编程、不想处理名称的人来说,它甚至可以只是一个简单的数字,不过名称能让你的脚本更易于理解。在你保存一张图像之后(见下文),你就可以从同一个「带标签的」内存位置再次读入该图像,想读多少次都行。例如…… |

magick tree.gif -write mpr:tree +delete \ \ mpr:tree mpr:tree mpr:tree +append mpr.gif


[IM Output]
请注意上面图像处理中 "[+delete](https://imagemagick.org/command-line-options/#delete)" 的用法。在上例中它并非必需(只要把 "mpr:tree" 读两次而不是三次即可),但在把图像保存进 "mpr:" 寄存器后,删除 当前图像序列中的所有图像是很常见的做法。基本上,上面的两行可以看作两条完全独立的 "magick" 命令,只是用一个命名的内存寄存器而不是磁盘空间来存放中间图像。在许多方面,用 "mpr:" 就像用 克隆复制(在上例中我们本可以用它们),但用 "mpr:" 允许我们完全移除所有图像,以清空当前图像列表去做其他工作。这种方法最大的特点是,它还允许你使用那些只对图像输入起作用的设置和操作。例如,把它与输入图像操作符 "[tile:](canvas.html#tile)" 一起使用,以在更大的区域上平铺一张图像。 |

  magick tree.gif -flip   -write mpr:tree  +delete \
          -size 64x64 tile:mpr:tree   mpr_tile.gif

[IM Output]
你也可以用 "mpr:" 来抓取某些特殊输出图像格式过滤器的输出,以便进一步处理。例如,这里我们保存来自 "[histogram:](#histogram)" 的输出图像,然后把它读回,在同一条命令中继续处理它, |

  magick rose: -define histogram:unique-colors=false \
          -write histogram:mpr:hgram  +delete \
          mpr:hgram  -strip  -resize 50%  histogram_resized.gif

[IM Output]
"mpr:" 这种内存内保存,实际上是你能够通过特殊 I/O 过滤器(如输出文件格式 "[histogram:](#histogram)" 或输入文件格式 "[tile:](canvas.html#tile_memory)")重新使用内存中已有图像的唯一方式。对于那些接受实际输入图像的特殊选项也是如此,例如 "[-tile](https://imagemagick.org/command-line-options/#tile)",或用另一张图像作为源的 颜色映射 图像。请参见 多图像颜色映射。请注意,在 IMv7 中,这类选项正被替换为不需要从文件读取图像的版本。它也是用 -draw 'image' 方法用一个生成的内存内图像来叠加图像的唯一方式,不过还有许多其他技术可以做到这一点。"mpr:" 图像实际保存的是_整个图像序列_,而不只是一张图像。这有点像给当前图像序列拍一张快照,以便你之后重新加载它做进一步处理。例如,这能让你给整个动画序列拍副本,用于复制或克隆,而无需知道实际涉及多少张图像。关于这样做的一个例子,请参见 图层合成。当你的 "mpr:" 中确实有多张图像时,你实际上仍然可以从该序列中提取出单张图像!用 "mpr:image'[2]'" 会从用 "-write mpr:image" 保存的多图序列中取出第三张图像。例如,这里我从一组四张图像中提取出 'storm' 图像。 |

  magick eye.gif news.gif storm.gif tree.gif \
          -write mpr:images  -delete 0--1 \
          \
          mpr:images'[2]'   mpr_extract.gif

[IM Output]
图像克隆 操作符通常无法处理数量未知、可变的图像,事实上,在 克隆 操作符被加入之前,"mpr:" 是唯一可用于复制内存内图像、而无需使用中间磁盘文件的方法。 | 从 IM v6.8.2 起,你还可以把图像存储在一个远程的 IM 缓存守护进程中。这允许图像(及其元数据)在分别运行的 IM 命令之间传递,而无需磁盘空间。请参见 分布式像素缓存守护进程
---|---

mpc:
是一种 IM 专有的特殊磁盘保存格式,最初是为真正巨大的图像而设计的。基本上,它是程序内存的一个内存映射磁盘文件,作为两个二进制文件保存到磁盘:一个保存图像元数据的 ".mpc",和一个保存图像像素缓存的 ".cache"。

"MPC:" 格式创建两个文件来保存一张图像

这类文件在 IM 被重新编译或升级后就无法使用,并且只适用于为某台特定机器编译的 IM。因此它只适合作为临时的「快速读取」文件,例如用于保存脚本化图像处理所用的临时图像,而不适合长期存储。例如……

  magick very_big_image.tif  very_big_image.mpc

会在磁盘上创建两个文件:一个小的 "very_big_image.mpc" 文件,和一个名为 "very_big_image.cache" 的特殊内存转储文件。第二个文件的大小很可能比任何其他图像文件格式都要大得多,因为它只是一份原始的、未压缩的内存转储。然而该文件不需要被「读入」或「解码」,而是可以直接「分页」进计算机内存并原样使用,没有任何处理开销。只需要大量的磁盘空间和磁盘 IO。换句话说,它只需要磁盘访问时间来读取,没有任何文件格式处理。也就是说,不需要对数据进行解码。由于该图像是「内存就绪」的,它对各种大小的临时图像都尤为有用,因为你接下来发出的 IM 命令可以立即使用它。但请记住,会生成两个文件,而且它们会比正常图像文件大小更大,所以要小心你的磁盘使用和脚本清理。我自己的 IM 脚本就很好地利用了这个特性。例如参见脚本 "de-pixelate" 和 "divide_vert",它们在图像处理操作中使用了相当多的临时图像文件。对于那些需要一遍又一遍反复读取同一张图像的脚本或 Mogrify Alpha 合成 而言,这会极其有用,因为 IM 不必解码图像,也不必仅仅为了存储它而占用大量内存。这对处理一张非常大的图像也非常有用,那时你必须为实际处理而提取或 裁剪 图像的较小一部分。不过,由于大多数图像操作实际上在处理期间会制作图像的克隆副本,所以仍可能制作一份新的内存内副本。因此仍需一些谨慎。把图像 裁剪缩放 到小得多的尺寸,是 MPC 大图像处理中最安全的操作。更多信息请参见下文的 超大图像处理

fd:{file_descriptor}
这个特殊文件名允许你指定图像要从中读取或写入的某个特定「文件描述符」。名称 'fd:0' 是程序的「标准输入」,'fd:1' 是「标准输出」。它们等价于用 '-' 作为文件名。不过你可以指定任意「文件描述符」来读写图像。包括用 'fd:2' 表示「标准错误」,或父程序可能已安排好的任何其他先前打开的文件句柄。它最常见的用途是在非常高级的 shell 脚本中,那里你可能有多条图像文件流。或者用于可能同时打开多条文件流的网络守护进程。

inline:{base64_file|data:base64_data}
内联图像让你读入一张以特殊 base64 编码定义的图像。例如,要读入一张 base64 编码的图像,请用……

inline:base64_image.txt

这个编码可以来自一个文件,但更典型的是直接作为读取参数给出(而不是作为来自某个外部图像源的文件名)。这更典型地用作命令行上「blob」的替代方案,或用于 API 图像处理。或者把图像数据直接放在命令行上……

inline:data:mime-type;base64,/9j/4AAQSk...knrn//2Q==

例如,让我们对一张很小的图像进行 base64 编码(有许多程序能让你做这个转换)……

  openssl enc -base64 -in noseguy.gif

[IM Text]

请注意,base64 数据可以包含任意数量的空白字符,例如回车和换行符。这些会被该格式简单地忽略。它也只使用普通的 ASCII 字符,这正是它被用来为电子邮件和网页编码二进制数据的原因。它还允许二进制数据被无障碍地存储在程序和脚本中。例如,我可以在一个 shell 脚本中放入下面这条命令,这样脚本本身就内置了图像,从而不需要单独的外部图像源。 |

  magick 'inline:data:image/gif;base64,
      R0lGODlhIAAgAPIEAAAAAB6Q/76+vvXes////wAAAAAAAAAAACH5BAEAAAUALAAA
      AAAgACAAAAOBWLrc/jDKCYG1NBcwegeaxHkeGD4j+Z1OWl4Yu6mAYAu1ebpwL/OE
      YCDA0YWAQuJqRwsSeEyaRTUwTlxUqjUymmZpmeI3u62Mv+XWmUzBrpeit7YtB1/r
      pTAefv942UcXVX9+MjNVfheGCl18i4ddjwwpPjEslFKDUWeRGj2fnw0JADs=
    '  b64_noseguy.gif

[IM Output]
请记住,有了这个,图像就可以用在你的脚本中(shell 或 API)。你不需要拥有一个单独的外部图像文件,这就使得一个本应简单的脚本在安装时不会变得更复杂。那么,"[inline:](#inline)" 为什么要采用这种相当复杂的形式呢? 基本上是因为这正是 HTML 网页中用于内联图像的格式。例如,下面这段里右侧的图像就是直接内联包含在网页上的,而不是作为一个单独的外部文件,使用如下形式的 HTML 标签…… |

  <IMG SRC="data:image/gif;base64,
        R0lGODlhIAAgAPIEAAAAAB6Q/76+vvXes////wAAAAAAAAAAACH5BAEAAAUALAAA
        AAAgACAAAAOBWLrc/jDKCYG1NBcwegeaxHkeGD4j+Z1OWl4Yu6mAYAu1ebpwL/OE
        YCDA0YWAQuJqRwsSeEyaRTUwTlxUqjUymmZpmeI3u62Mv+XWmUzBrpeit7YtB1/r
        pTAefv942UcXVX9+MjNVfheGCl18i4ddjwwpPjEslFKDUWeRGj2fnw0JADs="
      ALT="Nose Guy" WIDTH=32  HEIGHT=32  VSPACE=5 HSPACE=5 BORDER=0 >

Nose Guy
这并不能在所有 web 浏览器中工作,例如它在 IE7 及更早版本中不工作,但在 IE8 中可以工作。基本上,绝大多数现代 web 浏览器都理解它。
同类的内联数据格式也用于电子邮件头部中的「face」图像,可能还有许多其他文件类型。旁注:得益于 ImageMagick 的「magic」部分,大多数图像文件格式都不需要包含 mime 类型(那长字符串中的 'image/gif' 部分。事实上无论如何它都会被 IM 完全忽略)。不过,逗号 ',' 仍然是必需的,用来标记内联图像数据字符串中那一部分的结束。 |

  magick 'inline:data:,R0lGODlhEAAOALMAAOazToeHh0tLS/7LZv/0jvb29t/f3//U
       b//ge8WSLf/rhf/3kdbW1mxsbP//mf///yH5BAAAAAAALAAAAAAQAA4AAARe8L1Ek
       yky67QZ1hLnjM5UUde0ECwLJoExKcppV0aCcGCmTIHEIUEqjgaORCMxIC6e0CcguW
       w6aFjsVMkkIr7g77ZKPJjPZqIyd7sJAgVGoEGv2xsBxqNgYPj/gAwXEQA7
    '  b64_folder.gif

[IM Output]
警告:命令行选项输入被限制为 5000 个字符。此外,许多 shell(特别是 PC-DOS 输入)也有总的命令行长度限制。因此这并不适合非常大的 base64 图像。

clipboard:
从 Windows 剪贴板读取图像或把图像写入 Windows 剪贴板。(仅限 Windows)。
ephemeral:{image_file}

读取然后删除此图像文件。这是一种特殊的图像读取文件格式,它会导致 IM 在给定的图像文件被读入内存之后删除它。请注意,当被读取的文件被移除时,内存中的图像还未被处理、甚至未被保存。这非常危险,应在极度谨慎下使用。它主要用于 委托(delegate)派生。在那里,后台委托(delegate)会读取输入图像,然后在拿到数据后删除它。这进而通知前台的「父」进程,「子」进程已准备好独立继续,因为它已读完所提供的图像。主程序随后可以清理并继续单独进行它的图像处理,或者视情况直接退出。"show:" 图像输出委托(delegate)就用这种方式配合 "magick display" 命令,在主命令继续或退出之前自动把图像 magick 显示放到后台。(见下文)例如,我在一个调用 "[flicker_cmp](../static/img/scripts/flicker_cmp)" 的 shell 脚本中用过它来显示某些中间结果,但随后在 IM 通过删除所给的第二张图像发出「程序已读完其输入图像」的信号时,自动继续(或退出)。如果你既需要那个反馈,又需要保留正被读取的图像,那就给原始图像制作一份副本、硬链接或符号链接,并把那个文件作为 "ephemeral:" 传入。这样当它被删除时,原始图像就得以保留。注意:目前没有办法让 "animate" 或 "display" 在它完成一段动画、或实际把图像放上去 magick 显示时发出信号。:-( 不过你可以让 "magick" 读取一张单独的 "ephemeral:" 图像,以通知一个控制脚本它已到达其图像处理中的某个特定节点。

# 对图像进行模糊处理,并在自动删除并退出之前 # 显示一份屏幕上的对比。 magick rose: input_image.png magick input_image.png -blur 0x5 blurred.png flicker_cmp input_image.png ephemeral:blurred.png &

# 等待第二张图像被读取并删除! while [ -f blurred.png ]; do usleep 100; done

# 此时我们可以继续(或退出)而不会有问题, # 同时屏幕上的显示在后台继续。 rm -f input_image.png


我也在其他后台程序中用过它,作为该后台程序已准备好继续的信号。

show:win:x: -- 直接在屏幕上显示图像

这些是特殊的输出格式,它们会把图像结果直接显示到你的屏幕上。它不是把图像保存进文件,而只是显示结果。这对于快速测试 IM 命令、看看结果会是什么样非常有用,并为此目的而被强烈推荐。不过它们只是 "[display](basics.html#display)" 和 "[animate](basics.html#animate)" 命令的非常简单的版本。例如,快速获取一个目录中图像的概览……

magick montage *.jpg show:


查看两张图像之间不同的区域……

  magick compare image1.png image2.png show:

这里列出的所有格式,实际上都调用 "[display](basics.html#display)" 程序来完成它们的任务。不过它们各自以不同方式处理这项工作。例如 'show:' 会用一个 派生委托(delegate) 来运行一个单独的 "[display](basics.html#display)" 程序。这意味着一旦图像被显示,原始命令就会继续它的处理(通常是退出,除非你用 "-write show:")。另一方面,使用 'x:' 或 'win:' 则会等你退出显示窗口后,才允许原始命令继续(并退出)。遗憾的是,这些方法都不能很好地显示动画。对于动画,你最好把它(以 MIFF 格式)管道传给 "[animate](basics.html#animate)" 命令。

x:(作为输入) - 读取一个 X 窗口显示

你也可以用 "x:" 操作符读取当前的 X 窗口显示,方式与你用 "import 命令大致相同。事实上,不带选项时它的表现与 "import" 命令完全一样。用鼠标左键选择要抓取副本的窗口,或用中键标出一个区域。例如,用鼠标选择一个窗口,然后把刚抓取的窗口显示到另一个窗口中(被抓取的窗口显示出来时退出)……

magick x: show:


警告。如果你抓取的窗口是未映射(图标化)的,或者上面盖着另一个窗口,那么图像内容将包含一块空白区域,或者包含上层窗口的内容!!!所以抓取窗口时,务必让那个窗口在屏幕上完全可见。要抓取整个显示,请用 'root' 作为窗口名。

  magick x:'root'  full_screen_dump.jpg

或者使用 读取修饰符 来抓取显示的某个特定区域。

  magick x:'root[300x400+879+122]'  part_screen_dump.jpg

提供一个窗口名,你可以抓取某个特定窗口。例如,这会抓取标题为 'MailEd' 的窗口……

  magick x:'MailEd'  window.jpg

不过那其实效果不太好,因为你常常有多个同名窗口,或者窗口的名称就是无法确定。更好的办法是用一个「X Window ID」来告诉 IM 确切想要的窗口,那是 X 显示用来唯一标识某个特定窗口(或子窗口)的数字。X Window ID 通常用 "xwininfo" 命令查找,但也可以用 "xdotool"、"xwit" 等其他程序,以及 "xprop" 这类工具来查找关于窗口的信息。例如窗口类、名称、标题、它的大小和位置、子窗口,以及窗口管理器的装饰等信息。例如,找出标题或名称中含有 "Mozilla Firefox" 的所有窗口……

  xwininfo -root -all | grep "Mozilla Firefox"

然后我可以从上面的输出中提取出我想要的窗口的 X Window ID。下面是一个我放在我窗口管理器里、稍复杂一点的 bash 脚本。当我按下一个按钮时,它会查找当前「焦点」窗口的 ID,捕获它,然后根据之前所做的任何捕获,用下一个捕获编号把文件命名为当前目录中的一个 PNG。

  bash -c "
    id=$(xprop -root _NET_ACTIVE_WINDOW | sed 's/.* //')
    magick x:$id capture-tmp-$$.png
    num=$( ls capture-[0-9]*.png 2>/dev/null | sed -n '$ s/[^0-9]//gp' )
    num=$( printf %03d $(expr $num + 1) )
    mv capture-tmp-$$.png capture-$num.png
  "

大多数终端程序会通过环境变量 "WINDOWID" 告诉你它们用来 magick 显示文本所用的 X Window ID。因此,如果你从 XTerm 或 Gnome Terminal 的命令行运行这个,你会抓取到当前终端窗口的一份副本。

  magick x:$WINDOWID  this_terminal.png

现在来点好玩的……这里我抓取我当前终端的内容,往里面画一些东西,然后用 "[display](basics.html#display)" 把它重新画回到同一个终端窗口里!

  window=`xwininfo -children -id $WINDOWID |\
                  sed -n 's/^ *\(0x[^ ]*\).*/\1/p'`; \
  window="${window:-$WINDOWID}"; \
  magick x:$window -background black \
          -draw 'fill black         rectangle 40,40 160,160' \
          -draw 'stroke red         line 50,50 50,150 line 50,150 150,150' \
          -draw 'fill lime          circle 110,100 80,100' \
          -draw 'stroke dodgerblue  line 50,150 150,50' \
          rose: -geometry +180+60 -composite \
          png:- |\
    magick display -window $window -

上面的第一条命令是为 "XTerm" 窗口设计的,它要求你要 "magick display" 进去的窗口是所提供的 "WINDOWID" 的子窗口。第二行在找不到「子」窗口时回退到 "WINDOWID" 的原始值,对于 "Gnome-Terminal" 窗口就是这种情况。一旦确定了要使用的窗口,就抓取它、在上面绘画,再把它恢复进终端窗口!于是你就得到了直接输出到当前终端窗口的即时图形输出。这里是一个更简单的例子,它每次运行都会让窗口内容变暗一些。试着在一个真正的 "xterm" 窗口里运行这个几次,你会发现终端窗口里越早的命令变得越暗!

  window=`xwininfo -children -id $WINDOWID |\
                  sed -n 's/^ *\(0x[^ ]*\).*/\1/p'`; \
  window="${window:-$WINDOWID}"; \
  magick x:$window -background black -colorize 20% png:- |\
    magick display -window $window -

这里是一张「屏幕捕获」,展示了我在自己的 "xterm" 窗口里重复运行上述命令时所发生的情况……

[snapshot]

请注意,虽然终端的内容被修改了,但这只是临时的。如果你把它图标化、遮挡、或切换桌面屏幕,然后回到终端,这些修改就会丢失,因为终端程序会重绘窗口,抹掉你自己的「绘画」。上面对 "Gnome-Terminal" 的效果远不如对 "XTerm" 那样好,因为前者每次滚动时都喜欢「重绘」它的窗口,而 "XTerm" 不会。想象一下,IM 脚本作为某个更大的客户端程序的一部分,把图表和其他东西的结果直接显示在各个窗口中。事实上,这正是许多 postscript 查看器、甚至许多 web 浏览器显示来自特殊子程序的输出的方式。也就是说,它们让那个子程序接管并直接绘制到所提供的子窗口里。去试验吧,并请通过邮件或 IM 用户论坛 把你的发现告诉我(以及其他人)。


图像格式的编码器与委托(delegate)

编码器 是动态库模块(通常用 C 编程语言编写),处理图像输入和输出的「format:」方面。用户也可以用它们来创建特殊用途的过滤器。它们可能需要安装额外的外部库,这些库常被称为「委托(delegate)库」。它们只在需要时才作为动态模块加载,这意味着除非你真的想使用某个编码器,否则与该编码器关联的库不需要被安装。这些示例不会深入编写编码器所需的 C 编程,但源码中有一个示例编码器,可用于创建你自己的编码器模块。
一个 委托(delegate) 只是 IM 所知道的、能让它在不同格式之间进行 magick 转换的一条命令。这让 IM 可以使用那条「更简单」且预先写好的命令,而不必依赖一个更复杂的二进制编码器来处理某种图像文件格式。要获取有哪些委托(delegate)可用的列表,请使用这个特殊命令……

  magick -list delegate

IM 所使用的最有名的「委托(delegate)」程序是 "ghostscript",它能让 IM 读取、并把非常复杂的 Postscript 和 PDF 格式矢量图像 magick 转换成某种 IM 能读取的其他光栅图像文件格式。然而「委托(delegate)命令」对用户也非常有用,因为它让你能够扩展 IM,使它能处理特殊类型的图像,或为读写这些图像提供替代方法。这些「命令」本身列在一个名为 "delegates.xml" 的文件中,该文件位于 IM 的系统配置目录内。但它也会读取位于用户 Linux/UNIX 主目录下个人的 ".magick" 子目录中的 "delegates.xml"。用户应当把他们的「命令委托(delegate)」放在这第二个文件中。

输入委托(delegate)命令示例

例如,我可以在我的 Linux/UNIX 主目录下的 ".magick" 子目录中创建一个个人的 "delegates.xml" 文件,形如……

<?xml version="1.0" encoding="UTF-8"?>
<delegatemap>
  <delegate decode="flip" command="magick '%i' -flip 'miff:%o'"/>
</delegatemap>

这是一个完整的「委托(delegate)」配置文件,但只有中间那一行才是真正的委托(delegate)。一个非常简单的委托(delegate),它告诉 IM:如果它看到一张图像带有 '.flip' 后缀或 'flip:' 格式前缀,它应该调用上面的命令来读取这张 'flip' 格式图像。例如…… |

  magick flip:tree.gif   delegate_tree_flip.gif

[IM Output]
在这个例子里,该委托(delegate)命令所做的只是使用一个单独的 IM "magick" 命令,在原始 IM 命令真正读取和处理该图像之前,把图像「翻转」成上下颠倒!该委托(delegate)假定该命令能理解所给的图像文件格式,并且它会返回任何 IM 本身能理解和处理的图像文件格式(在这个例子里是一个 MIFF 图像文件格式)。委托(delegate)中的 '%i' 和 '%o' 部分代表临时文件名,是委托(delegate)应当使用的、所提供的输入和输出文件名。这些文件名由 IM 生成,并将位于一个临时目录中。这些临时文件名也不带任何图像后缀,所以重要的是:如有必要,你要给所需的图像格式类型加上前缀。这样做是出于安全原因,也因为 IM 本身可能只是在读取一串数据流,而不是一个实际文件。这也意味着委托(delegate)命令不必处理诸如完成后清理这些文件之类的事。还有其他 '%' 替换,用于诸如供中间临时文件使用的第二个临时文件名、图像密度、尺寸等。关于这些转义及其他委托(delegate)选项的更多细节,在 IM 安装的「系统」"delegate.xml" 文件顶部的注释中提供。现在,这看起来可能像是一个相当无聊和琐碎的例子,但它基本上意味着,你现在可以用一个次级命令把任何数据文件 magick 转换成 IM 能理解的任何图像。IM 随后就会知道如何根据图像后缀或格式前缀自动处理那种数据类型,而无需你记住所有细节。许多这种类型的委托(delegate)已经被加入系统文件,所以值得一看。 | _出于安全原因,个人 "delegates.xml" 文件中的委托(delegate)不会覆盖系统安装的 "delegates.xml" 文件中所定义的委托(delegate)。你只能在你主目录的 ".magick/delegates.xml" 中添加新的、独特的委托(delegate)格式,后来重复的委托(delegate)会被忽略。

当然,如果输入格式已经在内部已知,那么系统委托(delegate)根本不会被查看。

另外一如既往,要对任何用户(尤其是 web 用户)输入进行消毒,因为你不希望用户在你不知情的情况下使用某个委托(delegate)。

_
---|---
例如,从 IM v6.4.2-6 起,系统委托(delegate)文件中加入了一个 "autotrace:" 委托(delegate),它会在读取任何输入图像时运行 "[AutoTrace](http://autotrace.sourceforge.net/)" 命令。IM 把输入图像转换成委托(delegate)程序所需的 PNG 图像格式,让它过一遍委托(delegate),然后读取得到的 SVG(通常通过外部 RSVG 库),以生成原始输入位图图像的平滑边缘版本。请参见 光栅转矢量转换器示例。如果某个转换器生成多个图像文件(例如 PNG),你需要把所有这些分开的图像合并进一个单一的多图格式(如 MIFF),以便 IM 能从这一个输出文件中读取多张图像。有时 IM 会把多个委托(delegate)程序串接起来以读入一张图像。例如,要把一个 'HTML' 页面读取为图像,它会先调用委托(delegate) "html2ps" 把它 magick 转换成 postscript。然后它用特殊的 "ghostscript" 程序委托(delegate)把生成的 postscript 文件转换成一组多张图像。当然,像这样使用两个或更多委托(delegate),可能会因为委托(delegate)程序中可能存在的复杂交互、安装错误和 bug 而产生其他问题。但总体而言它能工作,并且是构成 ImageMagick「魔力」的一个关键方面。

输出委托(delegate)示例

在保存为 IM 不直接理解的特定图像文件格式时,会做类似的事情。例如,通过把这个委托(delegate)加入你个人的 ".magick/delegates.xml" 文件,你可以告诉 IM 如何创建一个 '.xyzzy' 图像文件。

  <delegate decode="gif" encode="xyzzy" command='mv "%i" "%o"'/>