ImageMagick 示例 -
图像文件处理

索引
ImageMagick 示例前言和索引
图像格式摘要
读取图像
保存图像
特殊输出文件格式 (特定于 IM)
miff:   info:   null:   txt:   sparse-color:   histogram:   mpr:   mpc:   fd:   inline:  
clipboard: - 读写到/从 Windows 剪贴板
ephemeral: - 读取后自动删除
show:, win:x: - 直接显示图像
x: (作为输入) - 显示捕获和重新绘制
图像格式的委托和编码器
真正的大型图像处理
大量图像的长流,视频序列
要处理图像,您不仅需要对图像进行操作的运算符,还需要能够以尽可能多的不同文件格式读取和写入图像。在本节中,我们总体介绍 IM 文件格式。

图像格式摘要

ImageMagick 最常见的用途之一不是修改图像,而是将图像从一种图像格式转换为另一种格式。实际上,IM 创建的最初原因就是这种图像格式转换。这就是为什么主要的 IM 命令被称为“magick”。为此,ImageMagick 可以处理各种各样的图像和文件格式。添加到这个数组中的是大量的特殊输入和输出格式,用于内置测试图像、简单图像创建以及专门用于编程 shell 脚本和程序的图像格式。有关完整列表,请参阅 IM 网站上的 IM 图像格式页面。对于 ImageMagick 的新用户来说,所有这些都可能令人望而生畏。我最好的建议是忽略大多数文件格式,因为您可能永远不会用到它们。相反,专注于您想要做什么,并尝试去做。如果您不知道怎么做,请尝试在这些页面和网络上寻找示例。对于 IM 示例中演示的图像格式,请参阅 参考索引,文件格式

读取图像

默认情况下,IM 会尝试根据文件本身内的“magic”文件标识代码确定图像格式类型。但是,如果失败,您需要使用文件后缀或添加前缀格式来指定图像文件格式。某些格式不会读取任何文件,并会忽略任何给定的文件名。以下是一些常见的内置图像...

  logo:      granite:     rose:
其中一些将根据作为文件名给出的参数生成图像,并可能附加一个额外的“-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:”与“txt:”文件格式处理。当然,如果图像生成器实际上读取图像文件以以特殊方式处理它(例如“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”设置。例如,这里我裁剪玫瑰图像...

  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”设置和读取修饰符都执行相同的任务,尽管后者会覆盖前者。此外,当您使用修饰符时,您必须让 IM 处理任何特殊的 shell 文件扩展元字符(如“*”和“?”),因为 UNIX shell 由于修饰符的存在而无法“找到”所需的文件。它在那种情况下实际做的事情是 shell 依赖的。因此,在使用读取修饰符时,应引用整个文件名。这些读取修饰符的真正目的是通过删除不需要的图像或使图像更小来减少所需的内存量,而图像仍在被读入内存中。例如,当读入整个目录的大型 JPEG 图像时。以下是所有特殊读取修饰符(和“-extract”设置)及其效果的列表。 '#' 代表某个数字。
'[#]' '[#-#]' '[#,#,#]' [#,#-#,#]'. 读取帧
将从已读入图像中的多图像文件格式中选择特定子帧。给定的数字“#”索引指定要读取的帧编号。可以在逗号顺序或索引范围内指定多个索引。图像索引从第一个图像的零开始,第二个图像的 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
这将读取每个图像并调整它们的大小,然后再继续处理下一个图像。这将导致更少的内存使用,并且可能在内存限制达到时防止磁盘交换 (抖动)。对于 JPEG 图像,我还建议您使用特殊的“-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”命令,并将你的图像输入到“magick”命令中以进行进一步处理。请参阅下面的大型图像处理
如果图像被“gzip”压缩,IM 会自动将其解压缩到一个临时文件中,然后尝试确定图像格式并解码图像文件格式。因此,你不仅可以将图像保存为 gzip 压缩格式,还可以直接在之后的 IM 处理中使用它们。对于大型文本图像,这可以节省大量的磁盘空间。
PNG 格式在其格式规范中包含“gzip”压缩。在这种情况下,两位数 PNG“-quality”设置的第一位数字定义了压缩级别。有关更多详细信息,请参阅PNG 图像文件格式示例。
以上只是将图像读入 ImageMagick 时可用的特殊输入选项的简要概述。在ImageMagick 网站上的命令行剖析页面上给出了完整的概述。
如前所述,图像输入可以通过一些 IM 设置进行修改,例如用于图像创建的“-size”和用于 JPEG 读取的“-define jpeg:size=??”。其他选项也影响图像输入创建,包括“-page”、“-type”、“-dispose”、“-delay”。请参阅设置/更改图像元数据
在脚本中将用户提供的参数传递给 IM 时要格外小心,确保参数符合你的预期。例如,你不想让一个 Web 图像处理脚本返回系统密码文件的图像。

输入文件名元字符处理

正在建设中
Not only does the shell handle meta-characters (unless that argument is
quoted) but IM also does its own form of meta-character handling in filenames.

For example
  magick *.jpg ....

is expanded by the shell BEFORE passing the filenames to IM, while

  magick '*.jpg' ....

will have the shell pass "*.jpg" to ImageMagick, which then expands into
an internal list of filenames!  This was provided for Windows Dos support, and
as a method to preventing command line limit overflows in command such as
"magick mogrify" and "magick montage", which typically process long lists of images.

As such to actually get IM to read a file names literially named on disk as
'*.jpg'  you need to use any of the following forms...

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

NOTE; the second line is NOT recommended as some shells (not bash) and some
APIs (C programs, possibly PHP) may actually remove the single backslash, and
pass '*.jpg' to IM which it will again expand!

On top of '?' and '*',  IM also adds the meta-character handling of  ':', '%'
and '[...]' for read modifier handling.  These however have a different
meaning  (codec specification, scene number inclusion, and read modifiers) to
normal shell syntax of those meta-characters.

For example DOS uses will need to escape a 'drive-letter' in filename paths
being passed to ImageMagick.  For example...

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

Another example is when loading an image containg a time code.  For example..

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

will read the filename "time_10:30.jpg" from disk.  Without the backslash, IM
may think that the image should be read with a non-existant image file format
(or delegate) "time_10:", and fail in an unexpected way.

An alternative is to use a question mark...

  magick "time_10?30.jpg" ...

However that may also match another file such as "time_10_30.jpg" as well!

压缩图像

正在建设中
IM will also read files that have been compressed, and given the appropriate
suffix, or image format specification.

That is, an image saved as "image.gif.gz"  will first be uncomressed, before
being decoded from its GIF image format.

Gzipped XPixmap (xpm) and NetPbm/PbmPlus (ppm) images is also automatically
handled, both by Imagemagick, and the formats normal delegate library.  As
such you can use the compressed forms directly either in IM, or in other
programs that understand these file formats.

See  Saving Compressed Images below.

保存图像

处理图像很好,但以正确的方式保存结果同样重要。“magick”、“magick montage”和“magick composite”的最后一个参数定义了一个文件名和图像格式,用于最终写入图像(默认图像输出)。虽然你也可以使用“-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_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”对于防止 IM 将所有图像保存到一个多图像 GIF 动画中至关重要,只使用第一个图像的文件名。我还确保使用“%e”转义序列保留了文件名的原始后缀。通常,在文件名设置中包含后缀是一个坏主意,因为当它来自转义序列时,IM 不会将其用于确定输出文件格式。但是,在这种情况下,格式没有改变,因此没有问题。需要谨慎。要获取图像的精确原始文件名,请使用 '%d/%f' 或 '%d/%t.%e'。你也可以使用 '%m' 代替 '%e',它实际上是 IM 在原始图像文件中找到的格式(以大写字母表示)(可能与原始图像的文件名后缀不匹配)。请注意,对于内置图像,这些转义序列字符串中的许多都是空白的。此外,如果没有目录,'%d' 将为空白。这是 IMv7 的一个已知问题。使用“文件名转义序列”的另一个示例在平铺裁剪图像中,其中该技术用于生成基于计算的平铺位置的每个结果图像的文件名。另请参阅使用 Convert 代替 Morgify中的示例。

自动 GZip 后缀

如果给定“.gz”后缀,IM 也会自动“gzip”图像。例如,这里我们将内置的“rose:”图像保存为“gzip”压缩的未压缩 GIF 文件。我们将 GIF 的正常 LZW 压缩关闭,因为它会阻止“gzip”压缩达到最佳压缩效果。

  magick rose: -compress none  rose.gif.gz
[IM Output]
浏览器如何处理 gzip 压缩的图像取决于 Web 服务器返回的文件类型以及你的浏览器如何处理压缩图像。因此,我没有直接显示上面的图像。单击“艺术”图标以查看你的浏览器使用此 Web 服务器上的此类图像时的行为。将此大小与正常保存的 LZW 压缩 GIF 图像的大小进行比较…

  magick rose: rose.gif
[IM Output]
gzip”压缩的玫瑰的大小为 [IM 文本] 字节,而正常的 LZW 压缩玫瑰的大小为 [IM 文本] 字节。如你所见,GZIP 压缩实际上比 GIF 格式使用的 LZW 压缩略好,因此可能更适合存档目的。GZIP 压缩的图像文件更常用于长期存储默认情况下没有压缩的图像文件格式。这包括 IM 文件格式“MIFF:”和更简单的NetPBM 图像文件格式。

保存的属性

正在建设中
Other Settings specific to image writing....
    -depth  -quality  -compress -type  -loop
    -set label   -set comment
Also see Image Depth,
Image Type,
JPEG Quality,
PNG Quality.
GIF loop.

Talk about file compressions, which are part of various image formats.

Different compressions are used for different image formats.

Especially the JPEG to TIFF compression change needed.

Using or "-compress
None" and "-compress" NetPBM text/binary format selection.

The GIF compression and the copyright patent.

Other than using IM to reduce -quality or changing the format to something
else the -compression option is rarely used.  Often it is only used internally
by IM to save images using the same compression the image was read with.

加密图像

IM 还允许你使用“-encipher”和“-decipher”选项,将敏感图像保存为使用密码短语加密的图像。请参阅加密图像

写入多个图像 - 拼接技术

保存图像的一个主要问题是,ImageMagick 使用的是有序的图像序列(列表),而不是一次只处理一个图像。因此,IM 会尝试将当前图像序列中的所有图像写入给定的文件名。如果文件格式允许多个图像,IM 会默认将当前图像序列中的所有图像保存到该图像文件中。例如,如果你查看GIF 动画基础示例页面,你会发现它会将多个图像帧保存到单个图像文件中以生成动画。如果输出格式不允许你将多个图像保存到一个文件中,IM 将改为生成多个文件。例如,将图像保存为 JPEGPNG 等格式时。你也可以使用“+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”设置。
但是,虽然我实际上不需要上述中的“+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' 语言(查找 UNIX 系统手册中的 'printf'),那么您可能知道,如果您使用类似“%03d”的东西,您将始终获得 3 位数(带有前导零)用于图像序列帧号。在这种情况下,图像名称将是“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”在图像处理之后执行此操作。这不是一个特别好的解决方案,但它有效,而且简单,并且与旧版本的 IM 向后兼容。从 IM 6.2 版本开始,您可以使用“-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”图像运算符从图像操作序列的中间写入图像。当您希望在图像处理过程中的不同点多次输出图像时,这非常有用。例如,请参阅 使用调试的复杂图像处理。以下是一个示例,我有一张 鹦鹉照片,由 柯达无损真彩色图像套件 提供(图像 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' 实际上并没有复制图像数据!IM 使用引用计数克隆过程,该过程仅在更新图像像素时才复制图像像素。因此,在上述过程中,实际上只使用了保存原始图像和新生成图像的足够内存。它还使 '+clone' 非常快且内存效率高。
以下是另一种执行相同操作的技术,但使用“MPR:”(见下文)而不是“-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”,因为我们可以像往常一样输出它。如果您确实使用了“-write”,您可以使用另一个特殊文件格式“NULL:”(见下文)将最终图像丢弃。关于“-write”的警告:由于某些文件格式要求图像处于特殊格式才能写入,“-write”运算符可能会修改图像。例如,GIF 图像可能会进行颜色缩减(请参阅 量化和抖动)。但是,其他格式将保留源图像(请参阅下面的 MIFFMPC)。如果您需要避免这些更改(因为您不只是在之后删除图像),可以使用“+write”,它将为写入创建一个内部克隆的图像,然后将其删除。但是请记住,这会导致使用两倍的内存来保存写入的修改副本。至少在一段时间内。

特殊文件格式(特定于 IM)

如您在上面看到的(并在下一节 常用图像文件格式 中探讨),ImageMagick 理解大量众所周知的图像文件格式。它还包括一些非常特殊的图像生成器(如 画布创建 中所示)。除了这些之外,还有一些非常特殊的文件格式,允许对图像进行一些非常特殊的处理。
miff:
是 ImageMagick 文件格式。整个图像序列和与图像关联的所有属性都保存在此文件格式中。当然,只有 ImageMagick 命令可以读取此格式,因此它不适合在不同的图像处理程序包之间传输。“miff:”文件格式的主要目的是在以长而复杂的方式处理图像时用作中间保存格式。它也适用于将图像从一个 IM 命令管道到另一个 IM 命令,同时传递与图像关联的图像元数据和其他属性。我建议在写入“miff:”时包含“+depth”选项。这会将图像的 '输入深度' 重置为 IM 内存质量,以便为中间图像保存使用尽可能高的质量。当然,您可以使用“-depth 8”来 '裁剪' 保存图像深度,以便减少磁盘上的图像大小,但是这也将强制 量子舍入 效果(除非还启用了 HDRI 浮点数保存)。对于那些有兴趣解析此格式的人来说,它从包含所有图像属性的纯文本标题开始。标题以包含单个换页符的行结束。此标题本身是提取各种图像处理脚本中基本图像信息的一种有用方法。例如,以下是我使用 GNU-sed 命令来列出“miff:”标题,直到换页符分隔符,显示内置“rose:”图像的所有属性。


magick rose: miff:- | sed -n '/^\f$/q; p'
[IM Text]
这实际上非常有用,因为它揭示了 IM 了解的关于图像的所有当前设置标志和元数据。但是,还有统计信息,因为这些信息是由“magick identify”命令、“-identify”运算符或特殊的“info:”格式生成的;如果使用“-verbose”选项请求。(见下文)图像文件格式具有非常低的解析要求,虽然没有压缩,但可以处理 IM 了解的任何类型的图像。它几乎是用于临时图像和管道图像命令的理想格式,您可以使用它,尽管 ImageMagick 程序是唯一可以读取它的程序。另请参阅下面的“MPR”图像内存寄存器和“MPC”内存磁盘映射格式。
原始图像数据(二进制)实际上以四字符序列 "\n\f\n:" 为前缀(换页符位于单独一行,后面是一个冒号)。如何读取此数据是在标题数据中编码的,但通常包括 RGB 元组中的二进制整数。但可以有更多通道,甚至可以包含浮点数或甚至双精度数据值。

从很多方面来说,它实际上与二进制 PbmPlus 图像文件格式相同,只是扩展了标题以保存图像元数据,并且通道数量和数据类型变化更多。
MIFF 图像流
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” 和 “-verbose” 选项控制,允许您输出仅您感兴趣的特定信息,如 图像属性转义 页面中所定义的那样。例如,我们可以使用以下方法来检索生成图像格式的单行标识,而不是像上面那样(参见 保存图像)将 MIFF 图像传递到 “magick identify”。

  magick granite:  info:-
[IM Text]
当然,您可以使用 “-format” 设置以特定且更易解析的方式输出所需的信息。关于 “info:” 的有用之处在于,您现在可以在生成图像的同时提取有关它的额外信息。这可以通过使用 “-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” 运算符,它等同于使用 “-write info:” 将图像识别信息输出到标准输出。这使得在调试 IM 命令时监控图像的发生情况变得更加容易。例如...

  magick logo:           -identify \
          -trim           -identify \
          +repage         -identify \
          -resize 80x80\! -identify \
          logo_thumbnail.gif
[IM Output]
[IM Text]
在这里,您可以看到 “-trim” 如何减小图像大小,但保留了对图像被裁剪部分的“裁剪”信息,然后 “+repage” 删除了额外的“画布”或“页面”信息。等等。与 “magick identify” 命令一样,如果启用了 “-verbose” 设置,则 “info:” 和 “-identify” 都将变得更加详细。在这里,我将较长的输出限制为前几行,以便您可以了解一下。

  magick rose: -verbose  info:  | head
[IM Text]
-verbose” 设置还会导致有关读取或写入图像的额外信息打印到标准错误(“info:” 格式除外)。它还会导致一些运算符(如 “-colors”)输出附加信息。因此,您可能希望在使用 “-identify” 或 “info:” 格式后再次将其关闭。

例如   
-verbose -write info:image_info.txt +verbose   或   -verbose -identify +verbose
对任何形式的 “identify” 输出的脚本读取应该以不区分大小写的方式进行。这确保了不同 ImageMagick 版本之间的更好向后兼容性。
注意:“info:”(和 “-identify”)只是一种输出格式,它产生与 “identify” 命令相同的输出。您无法使用 “info:” 文件格式读取或创建图像。您也可以使用 “-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:” 将在当前图像序列中生成一个特殊占位符图像,该图像包含一个透明像素,并具有特殊的“空源”标志。此特殊图像对 在蒙太奇中留出间隙 特别重要,并且用作多图像 层合成 的列表分隔符。它与另一种称为 '丢失图像' 的特殊图像格式密切相关,该格式可以为 “-crop” 等操作生成。当操作产生空结果或无意义结果时,会生成此图像格式。这两种图像都是一个透明像素,因此 “null:” 图像也将被视为 '丢失图像'。目前还没有方法可以从当前图像序列中删除任何 “null:” 甚至 '丢失图像'。但是,已经提出了这种方法。如果您发现需要这种方法,请给我发邮件。
txt:
这是一个简单的 ASCII 文本文件,它基本上列出了图像中的每个像素,每行一个。它不是通用的文本到图像转换器,为此请参见 多行文本文件示例。如果“像素枚举”未被识别,则该图像将传递到 “text:” 格式编码器,以将其呈现为纯文本文件。例如,这里有一个 “netscape:” 图像缩放到 2x2 像素的图像,然后使用 “txt:” 图像格式列出。

  magick netscape: -scale 2x2\! txt_netscape.txt
[IM Text]
图像的第一行(标题)包含有关图像的基本信息。信息包括... 文件魔数:图像标题将此文件定义为特殊的 IM 文本图像格式(例如“ImageMagick 像素枚举”文件),这在计算领域被称为文件的“魔数”或代码字符串,它标识此文件为特定的文件格式。图像大小:接下来的两个数字定义了此文件中包含的图像的大小。将这些数字相乘也会告诉您标题后面应该有多少行才能完全定义图像。IM 将始终输出这么多行,但正如您将在后面看到的,在读取时,您不需要定义所有像素。最大值:标题中的最后一个数字定义了图像数据可能的“最大值”。在上面的示例中,这是 '255',这是使用 8 位深度导致的结果。它输出内置的 “netscape:” 图像的原因是它是在内部使用 8 位值定义的,因此 IM 为图像保留了此深度级别。有关更多信息,请参见有关 深度设置 的部分。但是,您可以通过更改图像的 “-depth” 来覆盖深度设置(直到您的 IM 的 Q 或 编译时质量 设置的限制)。例如,这里我将颜色值输出为 16 位值(从 0 到 65535)...

  magick netscape: -scale 2x2\! -depth 16 txt_netscape_16.txt
[IM Text]
目前,您无法在输出文件格式中设置特定的“最大值”。您只能根据当前的 “-depth” 设置定义不同的值,使最大值等于 2^depth-1
颜色空间:标题中的最后一项定义了图像数据的 颜色空间。如果图像包含任何透明度,则还会将最后一个字母 'a'(表示 alpha)附加到颜色空间名称,并在括号之间添加一列额外的数字。灰度图像将输出图像为 'grey',但至少会定义三个数字,这些数字在每个像素中将具有相同的值。例如,这里使用 'LAB' 的 颜色空间 以及添加的 alpha 通道展示了同一图像!

  magick netscape: -scale 2x2\! -colorspace LAB -alpha set txt_cspace_lab.txt
[IM Text]
在初始标题之后是像素数据行,图像中每个像素一行。坐标:直到冒号 ':' 的前两个数字是像素位置,从 0 开始。颜色值:在此之后,像素的颜色值(从 0 到标题中给出的最大值)在括号中给出,根据图像的当前颜色空间,从 3 到 5 个数字不等。空格是可选的,因此在解析括号中的数字时,请注意。
这些值通常是整数。但是,从 IM v6.9.2-1 开始,如果使用 “-define txt:compliance=css” 特殊定义以及 “-depth 16”,则这些值将以带有 '%' 符号的百分比值表示。这是 SVG、CSS 兼容性的一部分。
颜色注释:括号中的数字之后的任何内容都被视为注释。IM 将使用它可以解析为颜色参数的格式来填充有关像素颜色的额外信息(有关这些颜色规范的详细信息,请参见 “-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” 运算符中特别有用,该运算符将当前图像序列中的每个图像替换为包含每个唯一颜色的一个像素的新图像。当将其输出到 “txt:” 格式文件时,您会获得图像中包含的颜色基本摘要(尽管没有它们的计数或直方图)。例如,以下是树图像使用的颜色。由于 GIF 只能使用 8 位数字,因此颜色也以相同的 深度 输出。

  magick tree.gif -unique-colors txt:-
[IM Output]
[IM Text]
使用 IM “txt:” 格式的另一种方法是使用各种 NetPBM 图像文件格式。IM 默认情况下将此格式输出为二进制,但您可以关闭 “-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:" 格式更有用,但仅在涉及几个像素时才有用。但请注意,在撰写本文时,输出是单行。Shell 脚本可能需要将输出中的空格转换为换行符。
histogram:
这实际上是 "miff:" 图像格式,但它包含一个非常大的图像注释,其中包含图像中所有颜色的完整计数。也就是说,在 "miff:" 文本标题中 'Comment={...}' 属性。例如,这里我们再次列出 "tree" 图像中存在的颜色,但这次还包括每种颜色的像素计数。文本直方图注释是从 "histogram:" 图像中提取的,使用辅助 "info:" 格式的 magick identify。

  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 histogram:unique-colors=false",如果不需要,此设置将关闭注释生成。
图像本身是一个直方图,大小为 256x200 像素。x 轴是颜色值(0-255),y 轴是像素计数(归一化为像素数量)。每个通道的直方图都以其代表的颜色显示,并相加在一起。因此,红色和蓝色重叠会产生洋红色。换句话说,每个颜色通道都有自己的独立直方图。
如果您希望将图像转换为其他格式,只需将其保存到该格式即可。"histogram:" 是一种特殊的图像处理格式。它会对图像进行 magick 处理,然后以文件名后缀或其他 "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 处理以转换为灰度。

  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:{label}
(内存程序寄存器)将整个图像序列保存到一个命名的内存寄存器中,您可以稍后从该寄存器中读取图像数据。因此,如果您想保存一个图像以便以后使用(在一个复杂的图像操作中),您可以这样做。在处理结束时写入 "mpr:" 是没有用的,因为程序内存会在程序结束后返回给系统。因此,如果您需要在不同的进程中使用图像,您将需要使用 写入 操作将图像保存到文件中。给 "mpr:" 的 'label' 可以是任何您喜欢的,它只是一个标签,用于指示图像在内存中的保存位置。它甚至可以只是一个简单的数字,适合进行脚本编写的人员,他们不想处理名称,尽管名称可以使您的脚本更易于理解。在保存图像后(见下文),您可以从同一个 '带标签' 的内存位置中读取图像,次数不限。例如…

  magick tree.gif -write mpr:tree  +delete \
          \
          mpr:tree  mpr:tree  mpr:tree   +append  mpr.gif
[IM Output]
请注意上面图像处理中使用了 "+delete"。在上面,这不是必需的(只需重新读取 "mpr:tree" 两次而不是三次),但通常在将图像保存到 "mpr:" 寄存器后,会将当前图像序列中的所有图像 删除。基本上,上面的两行可以被认为是两个完全独立的 "magick" 命令,但使用命名的内存寄存器来保存中间图像,而不是磁盘空间。在许多方面,使用 "mpr:" 就像使用 克隆复制(我们可以在上面的示例中使用),但使用 "mpr:" 允许我们完全删除所有图像,以清除当前图像列表以便进行其他工作。这种方法的最佳特性是,它还允许您使用仅对图像输入有效的设置和操作。例如,将它与输入图像 "tile:" 运算符一起使用,将图像平铺到更大的区域。

  magick tree.gif -flip   -write mpr:tree  +delete \
          -size 64x64 tile:mpr:tree   mpr_tile.gif
[IM Output]
您还可以使用 "mpr:" 来获取某些特殊输出图像格式过滤器的输出,以便进一步处理。例如,这里我们将 "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:" 之类的输出文件格式或 "tile:" 之类的输入文件格式。对于使用另一个图像作为源的特殊选项,情况也是如此,例如 "-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 Compositing非常有用,因为IM不需要解码图像或使用大量内存来存储它。这对于处理非常大的图像也非常有用,在这种情况下,您必须提取或裁剪图像的较小部分以进行实际处理。但是,由于大多数图像操作实际上在处理期间会创建图像的克隆副本,因此仍然会创建一个新的内存副本。因此,仍然需要小心。对更小的图像尺寸进行裁剪调整大小是MPC大型图像处理中最安全的操作。有关更多信息,请参阅下面的真正的大型图像处理
fd:{file_descriptor}
这个特殊的文件名允许您指定一个特定的“文件描述符”,图像将从该文件描述符中读取或写入。名称“fd:0”是程序的“标准输入”,而“fd:1”是程序的“标准输出”。这些等效于使用“-”作为文件名。但是,您可以指定任何“文件描述符”来读取/写入图像。包括“fd:2”用于“标准错误”,或父程序可能已安排的任何其他以前打开的文件句柄。这在非常高级的shell脚本中最为常用,您可能有多个图像文件流。或者对于可能同时打开多个文件流的网络守护程序。
inline:{base64_file|data:base64_data}
内联图像允许您读取以特殊Base64编码定义的图像。例如,要读取Base64编码的图像,请使用...
inline:base64_image.txt
此编码可以来自文件,但更典型的是直接作为读取参数给出,而不是作为来自某些外部图像源的文件名。这更典型地用作命令行或API图像处理中“blob”的替代方案。或者将图像数据直接放在命令行上...
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:”会有如此复杂的形式呢?基本上是因为这是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
这并非适用于所有网络浏览器,例如,它不适用于IE7及更早版本,但适用于IE8。基本上,最现代的网络浏览器都支持它。
相同的内联数据格式也用于电子邮件标题中的“人脸”图像,以及可能的其他许多文件类型。旁注:由于ImageMagick的“魔术”部分,大多数图像文件格式不需要包含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)。
ephemeral:{image_file}
读取并删除此图像文件。这是一个特殊的图像读取文件格式,它将导致IM在将给定图像文件读入内存后删除该文件。请注意,内存中的图像在读取文件被删除后不会被处理或保存。这非常危险,应该谨慎使用。它主要用于委托生成。在这里,后台委托将读取输入图像,然后在获取数据后将其删除。这反过来又通知前台“父”进程,“子”进程已准备好自行执行,因为它已完成提供的图像的读取。主程序然后可以清理并继续其图像处理,或者简单地退出,具体情况视情况而定。输出委托“show:”使用“magick display”命令和“ephemeral:”来自动将图像Magick显示置于后台,然后再继续或退出主命令。(见下文)例如,我在shell脚本中使用它,该脚本调用“flicker_cmp”来显示一些中间结果,然后在IM发出信号表示程序已完成读取其输入图像(通过删除给定的第二个图像)后自动继续(或退出)。如果您需要该反馈,但还需要保留正在读取的图像,那么对原始图像进行复制、硬链接或符号链接,并将该文件作为“ephemeral:”传递。这样,当它被删除时,原始图像就会被保留。注意:目前没有办法让“animate”或“display”发出信号表示它已完成动画,或已将图像实际显示出来。:-( 但是,您可以让“magick”读取一个单独的“ephemeral:”图像,以通知控制脚本它已在其图像处理中到达一个特定点。

  # Blur an image, and show an on screen comparision before
  # auto-deleting and exiting.
  magick rose: input_image.png
  magick input_image.png -blur 0x5  blurred.png
  flicker_cmp input_image.png ephemeral:blurred.png &

  # wait for the second image to have been read and deleted!
  while [ -f blurred.png ]; do usleep 100; done

  # At this point we can continue (or exit) without problems.
  # while the on screen display continues in background.
  rm -f input_image.png
我还将其用于其他后台程序,作为该后台程序已准备好继续的信号。
show:, win:x: -- 直接在屏幕上显示图像
这些是特殊的输出格式,它们将直接将图像结果显示到您的屏幕上。它不会将图像保存到文件,而是只显示结果。这对于快速测试IM命令以查看结果将是什么非常有用,并且强烈建议为此目的使用它。但是,它们只是“display”和“animate”命令的非常简单的版本。例如,快速查看目录中的图像摘要...

  magick montage *.jpg show:
查看两个图像之间不同的区域...

  magick compare image1.png image2.png show:
此处列出的所有格式实际上都调用“display”程序来执行其任务。但是,它们各自以不同的方式处理任务。例如,“show:”将使用生成委托来运行一个单独的“display”程序。这意味着,一旦图像被显示,原始命令将继续其处理(通常退出,除非您使用“-write show:”)。另一方面,使用“x:”或“win:”将等待您退出显示窗口,然后再允许原始命令继续(并退出)。不幸的是,这些方法都无法很好地显示动画。为此,您最好将动画(以MIFF格式)管道到“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
但是,这并不太好,因为通常您有多个具有相同名称的窗口,或者无法确定窗口的名称。更好的方法是告诉IM您想要的特定窗口使用“X窗口ID”,它是X显示器用于唯一识别特定窗口(或子窗口)的数字。“X窗口ID”通常使用“xwininfo”命令查找,但其他程序(如“xdotool”和“xwit”)以及其他工具(如“xprop”)也可以用来查找有关窗口的信息。例如,查找标题或名称中包含“Mozilla Firefox”的所有窗口...

  xwininfo -root -all | grep "Mozilla Firefox"
然后我可以从上述输出中提取出我想要的窗口的“X窗口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窗口ID”。因此,如果您从XTerm或Gnome Terminal的命令行运行它,您将抓取当前终端窗口的副本。

  magick x:$WINDOWID  this_terminal.png
现在来点有趣的... 我会获取当前终端的内容,在其中绘制一些东西,然后使用 "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 用户论坛

图像格式的编码器和委托

编码器 是动态库模块(通常用 C 语言编写),它们处理图像输入和输出的 "format:" 方面。用户也可以使用它们来创建特殊用途的过滤器。它们可能需要安装额外的外部库,这些库通常被称为 "委托库"。它们仅在需要时作为动态模块加载,这意味着编码器使用的相关库不需要安装,除非你确实想要使用该编码器。这些示例不会深入介绍编写编码器所需的 C 编程知识,但源代码中有一个示例编码器,可用于创建自己的编码器模块。
委托 只是一个命令,IM 知道这个命令可以使它在不同格式之间进行 magick 操作。这允许 IM 使用更简单且预先编写的命令,而不是要求更复杂的二进制编码器来处理某些图像文件格式。要获取可用委托的列表,请使用以下特殊命令...

  magick -list delegate
Im 使用的最著名的 "委托" 程序是 "ghostscript",它允许 IM 将非常复杂的 Postscript 和 PDF 格式的矢量图像读取并转化为 IM 可以读取的其他光栅图像文件格式。但是,"委托命令" 对用户也非常有用,因为它允许你扩展 IM,使其能够处理特殊类型的图像,或者提供读取和写入这些图像的替代方法。这些 "命令" 本身列在一个名为 "delegates.xml" 的文件中,该文件位于 IM 的系统配置目录中。但它也会读取位于用户个人 Linux/UNIX 主目录的 ".magick" 子目录中的 "delegates.xml"。用户应该将他们的 "命令委托" 放置在这个第二个文件中。

输入委托命令示例

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

<?xml version="1.0" encoding="UTF-8"?>
<delegatemap>
  <delegate decode="flip" command="magick '%i' -flip 'miff:%o'"/>
</delegatemap>
这是一个完整的 "委托" 配置文件,但只有中间一行是实际的委托。这是一个非常简单的委托,它告诉 IM 如果它看到一个后缀为 '.flip' 或格式前缀为 'flip:' 的图像,它应该调用上面的命令来读取 "flip" 格式的图像。例如..

  magick flip:tree.gif   delegate_tree_flip.gif
[IM Output]
在这种情况下,委托命令所做的只是使用一个独立的 IM "magick" 命令将图像上下翻转,然后再由原始 IM 命令读取和处理图像!委托假设命令将理解给定的图像文件格式,并且它将返回任何 IM 本身可以理解和处理的图像文件格式(在本例中为 MIFF 图像文件格式)。委托中的 '%i' 和 '%o' 部分分别代表命令提供的输入文件名和输出文件名,委托应该使用这些文件名。这些文件名由 IM 生成,并将位于临时目录中。这些临时文件名也不包含任何图像后缀,因此重要的是,如果有必要,你应该在图像格式类型前添加前缀。这样做是为了安全原因,也是因为 IM 本身可能只读取数据流,而不是实际文件。这也意味着委托命令不必处理完成后的文件清理等问题。还有其他 '%' 替换,用于诸如用于中间临时文件的第二个临时文件名、图像密度、大小等等。有关这些转义字符和其他委托选项的更多详细信息,请参阅 IM 安装的 "系统" "delegate.xml" 文件顶部的注释。现在这可能看起来是一个相当愚蠢和微不足道的例子,但它基本上意味着你现在可以使用一个辅助命令将任何数据文件转化为 IM 理解的任何图像。然后,IM 将根据图像后缀或格式前缀自动知道如何处理该数据类型,而无需你记住所有细节。系统文件中已经添加了许多此类型的委托,所以值得一看。
出于安全原因,个人 "delegates.xml" 文件中的委托不会覆盖系统安装的 "delegates.xml" 文件中定义的委托。你只能在主目录的 ".magick/delegates.xml" 中添加新的唯一委托格式,以后的重复委托将被忽略。

当然,如果输入格式已经在内部知道,那么当然不会查看系统委托。

此外,像往常一样,对任何用户(尤其是 Web 用户)的输入进行清理,因为你不想让用户在不知情的情况下使用委托。

例如,从 IM v6.4.2-6 开始,系统委托文件中添加了一个 "autotrace:' 委托,它将在读取任何输入图像时运行 "AutoTrace" 命令。IM 将输入图像转换为委托程序所需的 PNG 图像格式,通过委托过滤它,然后读取生成的 SVG(通常通过外部 RSVG 库),以生成原始输入位图图像的平滑边缘版本。请参见 光栅到矢量转换器示例。如果转换器生成多个图像文件(例如 PNG),则需要将所有这些独立图像合并到一个多图像格式(例如 MIFF)中,以便 IM 可以从一个输出文件中读取多个图像。有时,IM 会将多个委托程序串联起来以读取图像。例如,要将 "HTML" 页面作为图像读取,它首先调用委托 "html2ps" 将其转化为 Postscript。然后,它使用特殊的 "ghostscript" 程序委托将生成的 Postscript 文件转换为一组多个图像。当然,像这样使用两个或多个委托可能会产生其他问题,因为委托程序之间可能存在复杂的交互、错误安装和错误。但总的来说它能工作,也是 ImageMagick 变得神奇的关键因素。

输出委托示例

当保存到 IM 不直接理解的特定图像文件格式时,也会做类似的事情。例如,通过将此委托添加到你的个人 ".magick/delegates.xml" 文件中,你可以告诉 IM 如何创建 ".xyzzy" 图像文件。

  <delegate decode="gif" encode="xyzzy" command='mv "%i" "%o"'/>
当然,这只是快速地将 GIF 文件格式的图像复制为 TMP 文件格式,但该命令可以是任何类型的图像转换器、脚本或 shell 命令序列。有了那个个人委托,IM 现在可以创建你的 ".xyzzy" 图像,因为它至少提供了一种执行该操作的方法。

  magick rose: -negate   rose.xyzzy
  magick identify rose.xyzzy
请注意,上面的 identify 不理解 ".xyzzy" 后缀(没有提供输入委托)。但是,由于没有提供特定的委托,所以文件 "magic"(文件本身内部的识别字符串)告诉 IM 它实际上是 GIF 图像格式,所以 IM 仍然会正确地处理它,而无需特殊的输入委托或编码器。这实际上是 "ImageMagick" 中的 "MAGIC" 部分。

委托列表

IM 可以用于转换图像格式的外部委托的完整列表是从一个名为 "delegates.xml" 的特殊系统文件中读取的,以及一个个人 "delegates.xml" 文件(见下文)。如果你能找到这个文件,它会很有趣。但是,这个文件的格式过于复杂,不适合在这里介绍,尽管在系统文件中和随 ImageMagick 安装提供的文档(文档区域)中都有解释。可以使用 "-list delegate" 选项打印 IM 从这些文件中读取的委托和转换的简化摘要...

  magick -list delegate
但是请注意,用 'stealth="True"' 声明的委托不会被 "-list delegate" 选项列出。所有委托都是可选的,并且可以为特定的转换创建多个委托。如果一个委托不可用(或它出错且图像未创建),那么 IM 将尝试下一个委托,直到找到一个有效的委托,或者它用完要尝试的委托,此时将产生一个错误,指示它无法读取该图像。

打印委托

我创建的最有用的委托之一是让我可以轻松地将图像打印到 Postscript 打印机上。打印机已经使用 Linux 的 "lpr" 命令设置好,并且它可以接受 PNG 格式的图像或 Postscript 文件。这是我决定创建的简单的 "PRT: 委托。
[IM Output]

  <delegate decode="ps" encode="prt" command='lpr "%i"'/>
请注意,我决定使用 Postscript 格式 ("decode="ps"") 来表示传递到系统上的 "lpr" 命令的图像。我选择它是因为我可以使用诸如 "-density" 这样的选项来调整输出图像的大小。例如,我可以创建一个命令来从我的屏幕上抓取一个窗口,修改图像,以适合打印页面(如我所愿),然后将其打印出来。

  magick x:Loopy -shave 6 -chop 0x24 -modulate 220,0 \
          -bordercolor white -border 50x150 -density 130   prt:
我也可以使用 "decode="png"",但是我的系统会将图像放大或缩小,使其始终完全填充 A4 页面。但是,你可能喜欢这样。

  <delegate decode="png" encode="prt" command='lpr "%i"'/>

生成外部命令

外部命令委托不必只是用于将图像从文件转换到文件,还可以用作在后台运行(或 "生成")复杂命令的快速方法。此类委托将添加 "spawn="True"" 属性,它将启动命令,等待它删除其输入图像,然后 IM 将继续正常执行,并将命令在后台运行。例如,两个输出委托 "show" 和 "win" 都提供了在 IM "display" 程序中简单地显示命令结果的方法。例如..

  magick rose: label:rose -append   show:
这将在内置的“rose”图像上附加一个标签,并将其显示在屏幕上。当生成委托读取其输入图像并将其删除(通常使用特殊的“ephemeral:”输入格式,见上文)时,启动的 IM 将继续(并退出),并将“display”程序留在后台运行以显示结果。以下是“show”生成委托,展示了在“display”命令中使用“ephemeral:”。

  magick -list delegate | grep show
不幸的是,“list”选项不会显示委托的“spawn="True"”标志,但它为该委托定义了。这比尝试记住脚本化的“display”命令所需的所有特殊选项要方便得多。也许您有一些经常运行的复杂命令。

Postscript 和 PDF 委托

通过使用委托,ImageMagick 可以利用外部程序来执行一些更复杂和更专业的图像格式转换。例如,虽然 ImageMagick 可以直接写入 Postscript (PS:) 和 Encapsulated Postscript (EPS:)。但 IM 无法读取这些文件格式。Postscript 是一种完整的计算机语言,需要一个非常复杂的解释器才能从它创建图像。因此,它远远超出了 IM 处理此文件格式读取的范围。为了解决这个问题,IM 会寻找一个名为“ghostscript”的外部委托程序来完成将 PS 或 EPS 格式文件转换为 IM 可以轻松读取的其他图像格式的工作。当然,这意味着如果您遇到类似这样的错误...
convert: no decode delegate for this image format `...'
基本上意味着 IM 无法找到合适的外部程序将您的给定图像格式转换为 IM 自身可以处理的图像格式。对于 Postscript 图像,通常意味着“ghostscript”未安装、配置错误或位于系统未知位置。
[IM Output]
PDF/PS“ghostscript”委托采用内部使用的特殊格式。IM 在内部检查 postscript 格式的图像,以尝试确定如何通过给定的委托精确地光栅化文件。

事实上,存在多个 PS 委托,IM 根据情况选择它们。例如,使用的 ghostscript 设备(“bmpsep8”与“pngalpha”)的选择取决于是否之前设置了“-colorspace RGB”。

对于 PDF,我们使用“ps:color”委托而不是“ps:alpha”,因为“pngalpha”ghostscript 设备只支持一对一的页面到图像转换,而 PDF 通常是多页面的。

直接委托格式转换(污染)

委托系统还允许 IM 调用外部程序将图像从一种格式转换为另一种格式,而无需 ImageMagick 本身对图像进行任何处理。但前提是目标图像可以被 IM 识别为图像,并且“magick”的最终结果是图像的“未污染”副本。例如,如果您尝试使用此命令将“Adobe Illustrator”文件(“.ai”)(一种 Postscript 类型)转换为 EPS(封装的 Postscript)...

  magick -density 300   map.ai  map.eps
那么 IM 会将“map.ai”转换为 EPS 文件(在“/tmp”中),这是它理解的格式。然后在读取到内存后(在使用“eps”委托后),它会发现实际上不需要修改它(它保持“未污染”)。因为图像没有发生任何变化,并且图像已经转换为“eps”文件格式,所以 IM 会自行绕过,直接将它生成的“eps”文件复制到“map.eps”。也就是说,EPS 文件只是原始未更改的 Adobe Illustrator 文件的副本!换句话说,IM 只使用了其内部委托来对文件进行魔法处理(实际上只是重命名它)。它从未真正处理过图像本身,因此图像仍然是纯矢量图像。这实际上是“magick”作为程序在 ImageMagick 第 1 版中的最初目的。所有其他操作和设置是在很长一段时间后才添加的。但是,您可以使用特殊的“-taint”操作符强制 IM 实际读取和写入图像,使其成为光栅,将其标记为已修改,而实际上并没有修改它。

  magick -density 300 map.ai  -taint  map.eps
在这里,IM 读取的图像确实被“修改”或“污染”,因此它会将内存中的图像版本写入最终的 EPS 文件,而不是简单地复制输入文件。

其他委托示例

修改 CMYK postscript 的 Postscript 委托

参见John 的博客

DCRaw 8 位处理后的相机图像委托

用于读取 8 位完全处理过的“原始”数码相机图像(CRW、CR2、NEF 等)的另一种委托是...

  <delegate decode="dcraw8" command='dcraw -v -w -O "%o" "%i"'/>
这将读取“原始”相机图像,并将其转换为 PNG 文件格式(虽然您也可以轻松地添加“-T”标志并使用 TIFF 图像格式)。该输出图像可以被 ImageMagick 读取。通过添加此委托,就可以简单地使用它,用于任何 ImageMagick 图像读取操作(任何 API,不仅仅是命令行),而 IM 将处理所有文件 I/O 和清理。例如...

  magick dcraw8:image.crw  image.png
如果您没有定义“dcraw”可执行文件的路径,IM 将沿着用户当前的 PATH 环境变量搜索该程序,但这可能会造成安全问题。系统安装的委托通常会完全定义命令路径。请参阅此 IM 用户论坛讨论 中的注释。

使用“ffmpeg”的视频解码器委托

例如,以下是由 Mikko Koppanen 在其 Mikko 的博客 网站上发布的委托。将其添加到您主目录中“.magick”目录中的个人“delegates.xml”文件中...

  <delegate decode="ffmpeg" command="'ffmpeg' -i '%i' -y -vcodec png -ss %s -vframes 1 -an -f rawvideo '%o'" />
现在 IM 可以使用“ffmpeg”程序从 MPEG 视频图像中解码帧。例如。

  magick "ffmpeg:test1.mpg[40]"  frame_40.png

真正的大型图像处理

对于处理任何类型的图像,您最好使用 Q8 版本的 ImageMagick,它比更高质量的 Q16 版本的内存需求低一半。使用“identify -version”检查您的 IM 的编译 Q 级别。对于中等大小的图像,您可以尝试使用“-limit”来提高处理限制(例如,处理“-limit area 8192 -limit memory 8192”),以便尝试避免 IM 将图像数据缓存到磁盘。但是,您的系统可能会拒绝大型内存请求,并仍然强制 IM 将图像缓存到磁盘(大约慢 1000 倍)。要查看 IM 是否正在使用磁盘缓存进行图像处理,您可以使用“-debug cache”来监控该操作。另请参阅 IM 论坛讨论.

内存/磁盘管理

如果您打算处理真正的大型图像,您可能需要确保 IM 不会耗尽计算机的所有内存,并且不会减慢其他程序的处理速度(通过将所有时间都花在内存和磁盘交换之间),只需要求它立即使用临时交换磁盘文件即可。例如,这是一种不错的方法,可以在很长一段时间内处理非常大的图像,而不会阻止您使用计算机进行其他操作。基本上,它强制 IM 将所有内容缓存到磁盘。

  env MAGICK_TMPDIR=/data nice -5 \
    magick -limit memory 32 -limit map 32 \
            huge_9Gb_file.psd  -scene 1 +adjoin layer_%d.png
当然,这假设“/data”有足够的存储空间来处理图像的内存需求。

内存映射磁盘文件

如果您对同一个源图像执行许多操作,并且有充足的磁盘空间,您可以使用 MPC 图像格式,这种格式创建成本很高,但在加载时几乎没有开销...

  magick mybigassimage.jpg mybigassimage.mpc
  magick mybigassimage.mpc   -resize 50%  resized.jpg
  magick mybigassimage.mpc   -rotate 90   rotated.jpg
  ...etc...
  rm -f mybigassimage.mpc mybigassimage.cache
这将使您能够以最小的成本和内存使用量多次读取非常大的图像。在 IM 论坛讨论中,提供了一个使用此方法进行平铺的脚本化示例 将大型图像切成块,并在 裁剪非常大的图像 中进行了重新讨论。基本上,MPC 图像格式文件由两个实际文件组成,一个信息“.mpc”文件和图像在“.cache”中的直接内存分页副本。当然,在您完成操作后需要清理这两个文件。此方法的设计是为了让 IM 无需在每次运行新的“magick”命令时重新解析图像格式并将其缓存到磁盘。此外,如果您只访问输入图像的某些部分,则每个命令无需处理整个图像,而现在可以根据需要从缓存的磁盘文件中读取该较小的部分。如果您打算处理非常大的 MPC 副本的图像,最好提取或 裁剪 图像的较小部分以进行实际处理。这是因为,对图像执行的任何操作,通常会导致结果的新内存副本,因此初始裁剪是一个非常好的主意。如果您有内存,您也可以尝试使用“内存磁盘”,例如“TMPFS”或 RamDisk 类型的文件系统。但是请注意,填充这种类型的磁盘也会直接填充计算机的内存。因此,实际上您只是将一种内存使用方式替换为另一种内存使用方式。

处理小段图像

虽然您可以使用上面的 MPC 方法从源图像中裁剪出各种部分以供进一步处理,但您仍然需要读取和写入整个图像,对于巨大的图像,这仍然需要花费很多时间。IM 还为图像开发了一个更简单的管道处理器,称为“stream”。该程序具有一组有限的图像操作,这些操作旨在一次只处理图像的一行扫描(像素行)。因此,使用这种方法处理图像时,只使用足够的内存来保存一行像素。例如,这使您能够从非常大的图像中提取较小的区域以供进一步处理,而无需先将整个图像读入内存。但是, “stream”的输出是原始 RGB 图像值,因此建议进行一些后处理。

  magick stream -map rgb -storage-type char -extract 600x400+1900+2900 image.png - |\
    magick -depth 8 -size 600x400 rgb:- tileimage.png
您无需将输出保存到文件,而是可以继续直接处理较小的图像。例如...

  magick stream -map rgb -storage-type char -extract 600x400+1900+2900 image.png - |\
    magick -depth 8 -size 600x400 rgb:-  ...more_processing_here...  tile.png
这将只处理提取的600x400像素图像,而不会先读取整个更大的图像。速度问题...Peter V <peter.v@pv2c.com> 指出...根据我的经验,使用“”来切割 800MB 的 PNM 文件与使用 MPC 文件或使用“magick -crop”相比,是速度最快的。哪些格式有效...Paul Heckbert(图像失真领域的大牛)指出,“流”命令适用于某些文件格式(尤其是 JPEG),但不适用于其他格式,例如可能交错的 PSB。我认为这取决于特定文件格式的“编码器”是否支持逐行像素流。这可能是因为生成文件格式“编码器”的程序员没有实现或需要“流”。在这种情况下,可能需要熟悉该图像文件格式的程序员做一些额外的工作才能完成“编码器”模块。此外,像 SVG 或 WMV 这样的矢量图像文件格式,或者由某些“委托人”预处理的图像,例如数码相机图像文件格式,不可能被“流化”,因为图像中没有实际的像素行,只有绘制的物体(线条、多边形和渐变色)。JPEG 图像部分根据 IM 论坛的讨论 提取巨大 JPEG 的区域,您可以使用专门的 JPEG 程序,例如由 JPEG Club 开发的“jpegtran”和“jpegcrop”,从 JPEG 图像中提取区域,而无需实际解码数据。也就是说,从 JPEG 到另一个 JPEG 图像的无损裁剪。例如...

  jpegtran -crop 100x100+0+0 -copy none huge.jpeg  crop.jpg
但是,有一些注意事项。左上角的起点将移动到较小的 8 或 16 的倍数,最终图像大小也会相应增加。也就是说,因为 JPEG 图像使用“频率编码块”,这些块通常是 8x8 像素或 16x16 像素大小(由 JPEG 采样因子决定,1 = 8 像素,2 = 16 像素)。如果要进行无损复制,则需要保留这些块。对于“+0+0”偏移,它已经位于适当的边界,因此上述操作应该生成一个精确的 100x100 像素裁剪。但是对于其他偏移,您需要对提取的区域进行一些最终清理。例如...

  jpegtran -crop 100x100+123+425 -copy none huge.jpeg  crop.jpg
  magick crop.jpg -gravity SouthEast -crop 100x100+0+0 +repage crop_fixed.png

分块处理图像 (PbmPlus)

分块处理大型图像,而无需将整个图像存储在内存中,是一个更难的问题。基本上,在分割图像时,您需要要么保存一整行的图像,要么打开多个流(每个图像列一个),同时对大型图像进行分割,或稍后将其重新组合。最常见的技术是简单地将每个图像块作为单独的图像文件保存到磁盘。事实上,这通常是存储超大型图像的更好方法,因为程序可以随时只读取处理时需要的“块”,从而产生一种“基于磁盘的”随机访问图像。这种大型图像存储方法,结合金字塔型多级分辨率结构,实际上就是“谷歌地图”的工作原理。虽然 IM 没有任何工具可以利用少量内存分割(分块裁剪)大型图像,但 PbmPlus/NetPBM 可以做到。Pbmpus 处理一小部分例如,这里我使用 PbmPlus 工具裁剪(裁剪)大型图像的一小部分,对其进行处理,然后将该部分重新组合到原始图像中。

  tifftopnm INPUT.tif input.pam

  pamcut {left} {top} {width} {height} input.pam  part.pam
  # process smaller "part.pam" image here
  pamcomp -xoff={left} -yoff={top} - input.pam output.pam

  pamtotiff output.pam OUTPUT.tif

tifftopnm”将图像数据流转换为图像数据流,并执行类似于 ImageMagick 的“”命令的工作。 “pamcut”相当于 裁剪操作,它将从输入图像中提取较小的区域。您也可以指定裁剪的边界。您可以用“magick stream”命令替换“magick”,中间部分可以使用普通的 ImageMagick 进行处理,或者如果您喜欢痛苦,可以使用一系列等效的 PbmPlus 工具。 “pamcomp”应该将修改后的图像部分覆盖到 PbmPlus 版本的原始图像中。其他可能替代“pamcomp”的方法是“pnmpaste”,但它没有透明度处理,会导致像素溢出。请注意,通过使用分块合成,应该可以对较小的图像块进行扭曲,然后将它们重新组合成更大的图像。Pbmpus 分块(分块裁剪)处理我们可以使用“pamdice”和“pamundice”或其他替代方案来生成和合并可以单独处理的较小图像块,但是由于“每行多个图像块问题”,这必须将文件保存到单独的磁盘文件(或命名管道)中。由 bugbear 提供了一个示例脚本“pam_diced_flip.pl”来执行此操作,以“翻转”或“旋转”(仅 90 度)使用较小图像块的非常大的 PbmPlus 图像。这通常需要您将整个图像读入内存。请注意,它确实使用了大量临时文件,但它的内存占用非常小。

VIPS 和 NIP,一个大型图像 TIFF 处理器

Jenny Drake < jennydrake @ lineone.net > 报告...您可能还想看看“Vips”和“nip”这种非 IM 替代方案,它由伦敦国家肖像馆开发,旨在用于低配置计算机上的超大型图像文件(通常是 TIFF)。“Vips”是底层引擎,而“nip”是 GUI。适用于 Linux、Windows 和有时适用于 Mac。

大量图像的长流,视频序列

图像流是另一个问题领域。这里关注的不是图像的大小,而是所涉及的图像数量。数量如此之多,您通常不希望将它们全部加载到内存中,甚至不希望将它们作为普通图像单独保存到磁盘。这种图像的最大罪魁祸首当然是视频处理和动画。处理此类图像的关键是流图像文件格式,这些格式可以简单地将图像一个接一个地连接到一个文件流中。我们上面在 MIFF 图像流 中简要地提到了这一点。与 ImageMagick 自己的 MIFF 格式一样,PbmPlus/NetPBM 也是一种流格式(几乎相同,只是更简单),但它在视频图像流处理中更广为人知和更常用。在一个论坛讨论中,读取多个图像,一个用户希望处理由“ffmpeg”视频处理程序生成的多个 PPM 图像的“流”。 Pbmplus 图像(如 MIFF 图像)可以简单地连接在一起以生成多图像流。目前,IM 不允许您只从这样的流中读取一个图像,对其进行处理,然后读取另一个单一图像。所有 IM 命令都将始终读取整个流,然后将其关闭。这将在 IMv7 脚本处理中得到修复。一种解决方案是一个小型 Perl 脚本“process_ppm_pipeline”,它将接受一系列 PPM 图像,并在每个图像到达时对其运行一个单独的“magick”命令。输出也是一系列 PPM 图像,它生成一个新的图像流。例如,读取视频并将每一帧逐一“翻转”...

  ffmpeg input.mpg -f image2pipe -vcodec ppm | pnmtopnm -plain |
    process_ppm_pipeline -flip |
      ffmpeg -f image2pipe -vcodec jpeg output.mpg
pnmtopnm -plain”至关重要,因为该脚本目前只处理 ASCII-PPM 图像流,尽管通过一些额外的智能,它也可以处理任何二进制(原始)Pbmplus 图像流,甚至 MIFF 图像流。这种工具甚至可以用于处理大量图像的多个流(列)。尽管这可能需要对所涉及命令的内部处理有更深入的了解。如果能找到一种方法将此类图像细分为一系列块,然后在最后重新构建大型图像。最终,我希望包含一些机制,您可以通过该机制要求编码器从多图像文件流中读取并返回一个图像,而无需关闭该流,以便稍后可以再次读取另一个图像。这样,Im 就可以一次处理一个图像来处理图像流。更新:IMv7 可以一次读取流中的一个图像。使用循环或使用管道命令,应该可以生成流图像过滤器。需要更多实验。