ImageMagick 示例 -
Windows 下使用

索引
简介
使用 Cygwin
使用 DOS Shell 和批处理文件
Visual Basic Script (VBS)
更多信息
IM 示例中的大多数命令都是专门针对 LINUX 和 UNIX shell 脚本编写的,因为这些系统是为批处理和网络服务器而设计的。然而,越来越多的 ImageMagick 用户希望从 Windows 环境中使用它。本节提供有关如何在该环境中使用 IM 的详细信息和示例,更重要的是,如何将 UNIX shell 命令(如 IM 示例中的其他部分所使用的那样)转换为其 Windows DOS 等效项。我要特别感谢 Wolfgang Hugemann <ImageMagick_AT_Hugemann.de>,他完全重写了原始笔记,并扩展了它们以涵盖更广泛的主题,这些主题特别针对窗口用户。您在这里看到的是他的工作,IM 用户对他付出的时间和耐心表示感谢。

简介

在我的 Windows PC 上使用 IM 脚本有什么用?

以下示例基本上假设您在 Windows 桌面计算机上运行 IM,可能连接到网络。好吧,有很多现成的图像处理程序,比如 Adobe Photoshop、Corel 的 Paint Shop Pro、IrfanView (http://www.irfanview.com/) 甚至 GIMP (http://www.gimp.org/)。那么为什么您还要费心使用 IM 的命令行程序和脚本进行图像处理呢?使用 ImageMagick 而不是鼠标驱动界面的真正优势在于您可以完全自动化例行操作,无论是针对单个文件还是针对大量文件。例如,以下任务:
批量格式转换
这由许多 Windows 程序提供,例如 IrfanView。但是,IM 在图像格式方面的多功能性是无与伦比的。例如,您可以将 PDF 的所有页面转换成一系列 JPEG(如果您的计算机上安装了 GhostScript)。
缩小和预处理数码照片
将数码照片嵌入文字处理文档时,通常应降低其分辨率,以便更快地打印文档。如果您通过 FreePDF 等 PDF 打印机驱动程序将文档转换为 PDF,则情况也是如此。预处理还可以包括颜色和镜头校正例程。
将您的徽标放置到大量数码照片中

对大量数码照片应用一系列操作
通过使用鼠标驱动的程序,您可能希望自动化这些步骤,以便将来进行批量处理。但是,脚本语言(如 Adobe 的 Action Script)在 Windows 图像处理程序中并不常见。
将多个图像组合成一个目录图像

虽然一些任务(尤其是批量缩小)也由其他免费软件程序(特别是 IrfanView 的批处理)提供,但您始终无法自由选择要应用的处理步骤:您必须忍受程序提供的那些步骤。例如,IrfanView 的批处理提供将文本字符串放置到大量照片中,但不能放置徽标。它还提供更改伽马值,但照片的直方图不能在其末端被剪裁(如 IM 中的“-contrast-stretch”所示,请参阅 规范化和对比度拉伸)。IM 脚本特别适合在公司网络中进行生产性使用,因为任何人都可以应用现成的脚本——最终用户不一定要了解后台发生了什么。因此,图像上的标准工作流程步骤可以完全自动化(并且真正标准化)。以下列出的几个脚本是为我们的小公司(从事事故重建领域)的生产性使用而设计的。我不是一个优秀的 Windows 脚本程序员,也不熟悉 IM 的命令行工具。可能还有更优雅的方法来解决以下问题。我想说的是
  • 演示一些使用 IM 命令行工具的 Windows 脚本编程的基本技术。
  • 证明基于 IM 的脚本的使用既不是为了艺术而艺术,也不是学术消遣。
  • 展示 IM 的命令行工具可以在本地网络中(而不仅仅是在 Web 服务器上)完成实际工作。
与 IM 示例页面的其他部分一样,我们将只使用 IM 的命令行工具,并省略其各种编程接口。这些脚本旨在在本地网络中运行,每个网络驱动器都分配有驱动器号。大多数脚本旨在运行在该网络的客户端计算机上,只有少数脚本针对网络(文件)服务器。

IM 命令行工具的可能环境

在 Windows 下,简单的 IM 命令通常在 Windows 命令 Shell(一个“DOS Shell”,通过启动 cmd.exe 运行)中运行。对于在长命令行中或一系列命令行中执行的复杂操作,您最好编写一个脚本。对于一系列简单的命令,这很可能是一个 DOS 批处理文件,在 Windows 命令 Shell 中执行。但是,这种方法有其缺点,因为与常见的 UNIX 命令 shell 相比,批处理文件命令集相当有限。在 Windows 下运行 IM 时,您基本上有以下几种选择
Windows 命令 shell(“DOS 窗口”)
这由 Windows NT 4.0、Windows XP 及更高版本上的 cmd.exe(32 位模式)运行,并且存在于任何 Windows 计算机上。请参阅 使用 DOS Shell 和批处理文件,以及有关 Convert 问题 的特别说明。
Cygwin
一个类似 bash 的命令 shell (http://www.cygwin.com/)。使用此 shell 时,本使用部分其余部分介绍的 IM 示例可以完全按照给定的方式运行,因为您可以访问 UNIX 风格的命令行 shell。请参阅下面的 使用 Cygwin
Windows 脚本宿主
Windows 脚本宿主基于 .COM 技术。它存在于任何当代 Windows 计算机上,WSH 脚本比简单的 DOS 批处理文件强大得多。Windows 脚本宿主提供多个编程接口,其中 VBScript(Visual Basic Script)和 JScript(Java Script)是最常见的。可以使用 Shell 对象的 DOS shell 命令 RunExec 来调用 IM 命令行工具。请参阅下面的 Visual Basic Script (VBS)
Windows Powershell
古老 DOS shell 的更强大的继任者,基于 .NET 2.0 技术。Powershell 附带 Windows 7,由 powershell.exe 运行。它可以从 Microsoft 网站下载用于 Windows XP 和 Vista。

有效运行脚本

假设您有一个完美的 Windows 脚本(DOS 批处理文件、VBScript 或其他),它将输入文件的名(称)作为命令行参数,执行一些操作并将结果作为单个图像或一系列图像输出。您肯定不喜欢每次都启动 DOS 命令 shell(或替代方案)并通过输入文件名来提供脚本。为了避免这种繁琐的操作方式,您基本上可以使用 **拖放** 或 **发送到**:使用 **拖放** 时,您将 DOS 批处理文件或 VBScript(或其他)放置在易于访问的位置,例如桌面或保存要处理的图像文件的目录中。然后,您在 Windows 资源管理器中选择要处理的文件,并将它们拖放到脚本文件上。文件名将作为命令行参数传递给脚本,并且可以在脚本中引用。或者,您可以将您的脚本(或指向它的链接)放置在 **发送到** 文件夹中。此文件夹中的程序出现在 Windows 资源管理器中右键单击文件窗格时的上下文菜单中。同样,所选文件的名(称)作为命令行参数传递给脚本。SendTo 文件夹名为 SendTo。它的位置似乎随着每个新 Windows 版本而移动。一个万无一失的查找方法是在运行框中键入 shell:sendto。Windows XP 或更高版本中的单个命令行最多可以有 8192 (= 213) 个字符。因此,如果您直接从命令行调用 IM 工具(无论是直接调用还是通过一个直接命名所有所需文件的批处理文件调用),您几乎不会遇到此限制。但是,拖放使用 ExecShell 例程,它仅限于“仅”2048 (= 211) 个字符的字符串。由于所有文件都通过完全限定文件名(即驱动器 + 路径 + 名(称))传递,因此当路径名过长时,这可能成为批处理文件和通过 WSH 运行的 VBScript 的问题。一旦出现此错误,脚本就无法正确处理它,因为该错误发生在 **脚本实际运行之前**。在 Windows XP 下,解决方案通常是将文件放置在路径名较短的位置。

Convert 问题

IM 的 Windows 安装程序会将 IM 的程序目录添加到搜索路径中,这样你就可以直接从命令提示符调用 IM 的命令行工具,而无需提供路径名。默认情况下,你将使用 `magick` 作为你的命令行工具。但是,如果你选择使用旧的程序名称,IM 的命令行工具的名称就相当不具体(例如 convert、identify、compare ...),这会导致与其他程序发生名称冲突。特别是 convert 是一个 Windows 系统工具,位于 Windows 系统目录 (c:\Windows\system32\convert.exe) 中,它将 FAT32 文件系统转换为现在常用的 NTFS。但是,也有一些其他程序名为“convert.exe”,例如 Delphi 报告转换实用程序。FAT → NTFS magick 工具首次随 Windows XP 发布,并与 IM 的命令行工具“convert”发生名称冲突,因为 IM 的程序目录被 **附加** 到 DOS 搜索路径(即 PATH 环境变量)中,系统工具首先被找到,而旧脚本中对“magick”的简单调用无法正确解析。然而,当前版本的 IM Windows 安装程序会将 IM 的程序目录放置在搜索路径的开头,从而确保在发生名称冲突的情况下,IM 的命令行工具通常会首先被找到。但是,其他具有相同名称的实用程序(例如 Deplhi 的报告转换器)也遇到了同样的问题,并采用了相同的解决方案,即将其程序路径放置在路径变量的开头,这意味着这种解决方案并不完美:如果 Delphi 在 IM 之后安装,对 Convert 的简单调用将调用报告转换器工具,而不是 IM 的 Convert。Windows XP 中引入 Convert 工具导致许多旧脚本崩溃。常见的解决方案是将 IM 的 Convert 工具重命名为其他名称,例如“IMconvert”(注意你不能重命名系统命令,因为下一个 Windows 服务包可能会恢复它,忽略重命名的版本)。这种解决方案虽然现在不再需要,但仍然可以在互联网上随处可见。为了避免将来可能发生的名称冲突,最好的解决方案是在任何脚本中通过完整路径名调用 IM 的命令行工具。也就是说,将其位置存储在一个变量或一个常量中。因此,每个批处理文件都应该以类似下面的行开头

  SETLOCAL EnableDelayedExpansion
  SET IMCONV="%PROGRAMFILES%\ImageMagick\Convert"
  ...
  %IMCONV% -size 128x128 xc:white test.gif
这段代码假设 IM 安装在一个名为“ImageMagick”的文件夹中,该文件夹位于程序文件夹的下面,**不是** 它的安装文件夹的标准命名。(有关详细信息,请参阅 在 Windows 下安装 ImageMagick。)%PROGRAMFILES% 是一个环境变量,它扩展为程序目录的名称,例如英文版 Windows 中的“Program Files”和德文版 Windows 中的“Programme”。SETLOCAL 将限制新环境变量(例如 IMCONV)的定义范围,使其仅限于批处理文件的范围。EnableDelayedExpansion 在这里并不真正需要,但每次使用 SETLOCAL 时都使用这个选项是一个好习惯;有关详细信息,请参阅 批处理编程指南。还有更复杂、更可靠的方法来找出 IM 的安装文件夹,这些方法将在 编辑、调试和运行时错误测试 中介绍。等效的 VB-Script 代码如下所示

  Set wsh = WScript.CreateObject("WScript.Shell")
  IMconv = wsh.ExpandEnvironmentStrings("%PROGRAMFILES%") & "\ImageMagick\Convert"
为了简单起见,我们将在接下来的内容中不会每次都使用这段代码,但你应该将其作为一种好习惯铭记于心。有关此问题的良好替代总结和解决方案,请参阅 Ron Savage: MS Windows 和 convert.exe

字符编码

ImageMagick 使用 Unicode 对字符串进行编码,更准确地说,使用 UTF-8。相反,DOS 使用代码页来对字符进行编码(大部分使用 8 位)。这在将字符串写入图像时会产生问题,例如在使用“label”或“-title”时:当使用非 ASCII 字符时,简单的做法会出现问题。例如,尝试创建带有德语变音符的标签,例如“ä”、“ö”、“ü”,你可以在 Linux 下简单地使用以下命令...

  magick label:äöü test.png
但这不会在 Windows 下创建所需的字符串。然而,你可以从文本文件中读取 UTF-8 编码的字符串

  magick label:umlauts.txt test.png
你甚至可以使用“echo”创建这个文本文件,前提是先将代码页切换到 UTF-8

  CHCP 65001
  ECHO äöü > umlauts.txt
  magick label:umlauts.txt test.png
但是,如果你想处理 DOS 命令的输出,例如当尝试使用该目录的名称来为特定目录中包含的 JPEG 的索引打印添加标题时,就会遇到麻烦。切换到代码页 65001 无法与大多数 DOS 命令配合使用,尤其是当遍历目录树时。而且在代码页之间来回切换,例如从 1252(西欧拉丁语)切换到 65001,通常也不起作用,或者至少会变得相当棘手。最安全的方法是使用外部命令行程序(例如“Iconv.exe”,一个也适用于 Windows 的 UNIX 工具)在需要时对字符串进行操作。从 SourgeForge 下载安装文件,并将文件安装到标准目录 C:\Program Files\GnuWin32 中。然后将 DOS 命令的输出转储到你的脚本中的文本文件中,并使用以下命令将该文件转换成 UTF-8

  CHCP 1252
  DIR /B äöü.jpg > temp.txt
  "C:\Program Files\Gnuwin32\bin\iconv.exe" -f ISO-8859-1 -t UTF-8 temp.txt > title.txt
  magick label:@title.txt äöü.jpg -append äöü_labelled.jpg
这些参数告诉 Iconv 将编码从 ISO-8859-1(代码页 1252)转换为 UTF-8。Iconv 将其输出写入 stdout,因此你必须将其重定向到一个文件才能与“label”一起使用。请注意,无论如何将输出转储到文本文件都是可取的,因为它告诉 ImageMagick 按字面解释文件内容,而不将 Windows 反斜杠(“\”)视为转义字符。当然,上述示例中的代码本身并没有太多意义,这里只是为了演示目的。在实际的 DOS 批处理文件中,文件名可能是在 FOR 循环中生成的。下面是一个实际的例子(参见 批处理(子)目录树)。有关 UTF 处理的更多信息,请参阅其他 IM 示例以及 Unicode 或 UTF8 格式文本处理 中的信息。

在 Windows 下安装 ImageMagick

ImageMagick 不断发展,新版本大约每月发布一次。强烈建议使用最新版本的 IM,尤其是在 IM 似乎无法按预期完成任务时。在大多数情况下,安装当前版本可以解决问题。当前二进制版本的安装程序可以在 https://imagemagick.org.cn/script/binary-releases.php#windows 找到。你也可以从 天文和天文摄影博客 下载支持 HDRI(浮点质量)和 FFT(快速傅里叶变换)的 ImageMagick 版本。默认情况下,IM 会将自身安装到一个名为 C:\Program Files\ImageMagick x.x.x-x 的程序目录中,其中“x.x.x-x”代表其版本号。默认情况下,安装程序建议在首次安装 IM 时扩展 PATH 环境变量(即“将应用程序路径添加到系统路径”已选中)。如果你忘记卸载旧版本,你会很快拥有各种 ImageMagick 版本及其相应的 PATH 扩展的集合。因此,在我们办公室,我们养成了将 IM 安装到 C:\Program Files\ImageMagick 中的习惯,将较新的版本直接安装在较旧的版本之上,并保持 PATH 环境变量不变。多年来,我们没有发现这种做法有任何问题。如果你真的想知道 IM 版本号,你始终可以调用“convert -version”,并且一个防呆脚本可以评估版本号,以防它依赖于某个最小版本号。有关此方面的更多信息,请参阅“编辑、调试和运行时错误测试”部分。ImageMagick 会在 HKEY Local Machine\Software\ImageMagick 中写入一些注册表项。如果你确实处理多个已安装的 IM 版本,最重要的键是 HKEY Local Machine\Software\ImageMagick\Current,你可以在其中找到 IM 二进制文件的路径,称为 BinPath。你可以在任何脚本的开头查询此注册表项,从而确定程序路径,而无需依赖 PATH 环境变量。有关此方面的更多信息,请参阅“编辑、调试和运行时错误测试”部分。IM 的安装程序提供了一个选项,可以通过选项“为 VBscript、Visual Basic 和 WSH 安装 ImageMagickObject OLE 控件”来安装 COM+ 对象。该选项默认情况下未选中,安装 COM+ 对象 **不是** 使用 IM 在 VBScript 中的先决条件,这一点将在后面的内容中得到证明。无论如何,你不应该依赖 COM+ 对象安装在除你自己的计算机以外的其他脚本目标计算机上。在使用 PostScript 文件时,ImageMagick 依赖另一个程序“Ghostscript”来读取和转换 PostScript 和 PDF 文件,以便将其转换为它可以使用的图像格式。也就是说,要读取这些文档,必须在你的计算机上安装 Ghostscript。它的最新版本可以在 SourceForge 下载。你安装 GhostScript 和 ImageMagick 的顺序无关紧要。你无需在安装 ImageMagick 之前安装 GhostScript,ImageMagick 即使没有安装 GhostScript 也能正常运行。它仅在你需要处理 Postscript 或 PDF 文件时才需要。IM 会在运行时确定 GhostScript 的位置,并从注册表中查询它。

特点和陷阱

对于 Windows 程序来说,IM 允许将图像写入 stdout 并从 stdin 读取,从而使用管道级联图像处理任务。操作

  magick -size 128x128 xc:white gif:- | magick - test.gif
等效于

  magick -size 128x128 xc:white test.gif
在管道中的第一个命令中,减号运算符告诉 IM 将图像写入 stdout,而在管道中的第二个命令中,减号运算符告诉 IM 从 stdin 读取图像。这种操作方式可以避免显式使用临时文件。如果某些命令没有提供某些操作,例如修剪,则它特别有用

  montage -tile 2x2 -geometry 400x300+60+60 1.png 2.png 3.png 4.png miff:- | magick - -trim montage.png
由于此功能,文本输出通常写入 stderr 而不是 stdout。例如:如果你想将 Compare 的文本输出重定向到一个文本文件中,你需要编写

  magick compare -metric PSNR 1.png 2.png dif_1_2.png 2>result.txt
因此,你必须将 stderr(“2>”)重定向到文本文件,而不是 stdout(“1>”或“>”)。

获取帮助

命令行选项在 IM 网站 上有详细的文档,但真正演示如何使它们生效的是其网站上的 使用部分。网站的这一部分结构良好,可以根据你想要执行的任务进行面向问题的处理。然而,快速简便的方法是在网站的这一部分中针对你所想到的命令行选项进行 Google 搜索。如果你想对多个图像进行蒙太奇,并想知道 -tile 选项,你可以在 Google 上搜索以下内容你很快就会了解到要点。请记住,这将显示在 UNIX / LINUX 环境中应用的代码,需要稍微调整才能在 Windows 下应用。另一个非常有用的信息来源是 IM 讨论板,也称为 Discourse Server 用户论坛,你应该将其添加到浏览器的书签/收藏夹中。成为会员后,你可以提出问题,这些问题通常会被知识渊博的用户快速解答。

辅助程序和替代方案

是的,这是真的。确实有一些任务是其他程序比 ImageMagick 更好地完成。通常情况下,这些程序是针对特定格式设计的,而不是 ImageMagick 提供的通用图像操作。
  • IrfanView 可能是 Windows 下最常见的图像查看器,它也允许进行一些基本的图像操作。
  • 类似 Adobe Photoshop 或 Gimp 这样的 GUI 程序更适合直接编辑和测试复杂的图像操作步骤。
  • 对于数字照片的 EXIF 头信息操作,JheadExifTool 比 ImageMagick 更通用。
  • 从 PDF 中提取 JPEG 流应使用 xPDF 进行。
  • 视频处理最好使用 VirtualDub 进行,最好与 AviSynth 及其编辑器 AvsP 结合使用。
这并不是说 ImageMagick 应该被忽略,它在这些图像工作中仍然非常有用。但你可以通过将它们结合在一起来实现更多功能。

使用 Cygwin

如上所述,ImageMagick 是针对 UNIX 和 Linux 设计的,因此最简单的方法可能是,在你的 Windows 系统上安装一个 Bash shell 并运行已经为该系统编写的各种 IM 脚本,例如 Fred Weinhaus 的脚本Cygwin 是——正如其开发人员所说,它提供了一个“适用于 Windows 的类似 Linux 的环境”。它包含了 Linux shell 中通常可用的所有工具。我已经在 Cygwin 的 Bash shell 下测试了 Fred Weinhaus 的一些 bash 脚本,发现它们都完全正常。在 Cygwin 网站根页面的底部,你会找到一个名为 立即安装或更新! 的链接,它会下载一个名为 Setup.exe 的安装存根。当你启动这个程序时,它会提供一个站点镜像列表。在你选择其中一个之后,程序将提供一个树状视图,显示它将要安装的工具。标准选择对我来说似乎很合理,所以你可能可以直接进行。安装程序将下载所需的软件包,并在你的电脑上安装 Cygwin。
安装时,确保包含 “bc” 软件包,该软件包默认情况下未启用。它可以作为 Cygwin 安装面板中的一个选项安装。这是一个浮点数学实用程序,在 IM 脚本中至关重要,例如 Fred Weinhaus 使用的那些。
当你启动 Cygwin 时,它的 Bash shell 看起来很像一个 DOS 框,即一个带有黑色背景的文本窗口。与 DOS 窗口一样,可以通过点击位于标题栏左边的窗口系统菜单来选择字体。基本命令是
  • 你可以使用 CD 命令更改当前目录,这与 DOS 中的操作几乎一样。但是,反斜杠 (“\”) 必须替换为正斜杠 (“/”)。驱动器也通过 CD 更改,就像在 DOS 下一样。因此,CD w: 将切换到驱动器 w: 与普通 Unix 环境不同,路径名不区分大小写。可以使用特殊字符,例如变音符号。对于一些命令,驱动器名必须以特殊语法传递,避免使用冒号。例如,/cygdrive/w/test
  • Cywin 读取 Windows PATH 环境变量,并相应地设置自己的 PATH。你可以通过在 Bash shell 中输入 echo $PATH 来检查这一点。注意:与 Windows 下不同的是,环境变量名区分大小写,因此你在引用 PATH 时必须使用大写字母。
  • 与 Windows 下不同的是,默认情况下,将当前目录包含在搜索路径中!例如,如果 shell 脚本 “autolevel1” 位于 W:\scripts 中,你不能只是切换到该目录并调用 shell 脚本。你必须在脚本开头至少添加一个最小的目录位置,例如:./autolevel1(对于位于当前目录中的脚本)。或者脚本的完整路径,例如:/cygdrive/w/scripts
  • 或者,你可以使用 PATH=$PATH:/cygdrive/w/scripts 明确将该脚本目录追加到搜索路径中。由于冒号用作路径分隔符,因此你必须使用这种特殊的命名法,例如 /cygdrive/w/scripts 而不是 w:/scripts
本页面的未来版本将扩展对 Cygwin shell 的描述。目前,以上信息应该足以让你入门。

使用 DOS shell 和批处理文件

转换脚本:UNIX Shell 到 Windows DOS

当直接从 DOS 命令 shell(使用 cmd.exe)调用 IM 命令时,你必须修改 IM 示例站点上提供的脚本(如果它们不是来自本节),因为提供的大多数示例(在其他部分中)通常用于在 UNIX 或 LINUX 命令 shell 中运行。为了从 DOS 命令 shell 运行它们,你必须执行以下修改
  • 通常,双引号 '"' 必须用于代替单引号 ''',以使命令参数保持正确。注意引号中的引号,例如在 -draw 操作符中。你可以在 DOS 双引号引用的参数中使用单引号,因为这些引号会被传递给 IM 处理,而不是被脚本处理。
  • 显示的示例行末尾出现的反斜杠 '\' 表示“行延续”,它将下一行追加到相同的命令行序列中。在 DOS 批处理文件中,用 '^' 字符替换它们,表示行延续。对于 DOS,下一行还需要以空格开头,但这是一种相当标准的做法,因此不会造成太多问题。你也可以将所有行追加到一行上,并删除这些反斜杠,但这会使编辑和后续阅读命令变得更加困难。因此,不建议这种做法。
  • 如果在字面上使用,所有不在双引号中的保留 shell 字符必须用 '^'(插入符号或脱字符)转义(即不执行其通常的用途)。这些保留的 shell 字符是:'&'、'|'、'('、')'、'<'、'>'、'^'。这意味着
    • 特殊字符 '>'(用于调整大小几何形状)需要使用 '^' 转义。例如 “-resize 100x100^>
    • 类似地,'内部拟合调整大小' 标志 '^' 需要加倍变为 '^^'。
  • UNIX shell 转义反斜杠 '\' 不需要转义括号 '()' 或感叹号 '!'。
  • 否则,UNIX shell 转义反斜杠 '\' 需要替换为脱字符 '^' 字符,当使用这些转义字符时,例如 '<' 和 '>'。
    例如:“-resize 100x100\>” 将变为 “-resize 100x100^>”。
  • 在 DOS 批处理文件中,百分号 '%' 字符也具有特殊含义,因为它引用了命令行参数。例如 %1, %2, ...(在 UNIX shell 中,'$' 符号用于表示相同的通用含义)。在 DOS 批处理文件中,单百分号(因为它们出现在“FOR 命令”中)需要加倍变为 '%%' ImageMagick 本身通常只查看是否存在百分号,并不关心是否给出了多个百分号。因此,除非它是文本标签或注释字符串的一部分,否则加倍所有百分号通常不会造成伤害。
  • 请记住,Windows 文件名可以包含空格字符。空格也可以在 UNIX 下使用,但并不常见。包含空格的此类文件名必须包含在双引号 "file name.jpg""file name".jpg 中。通过拖放或“发送到”作为命令行参数传递给脚本或批处理文件的文件名需要特别注意,因为如果它不包含空格字符,则会将其不带引号传递给脚本,如果包含空格字符,则会带引号传递给脚本。
  • UNIX shell 脚本中的注释以未加引号的 '#' 开头,位于任何一行中,并一直延续到该行末尾。颜色设置(例如,红色颜色的“#FF0000”)通常会被引起来,以去除这种特殊含义。这种引号在 DOS 下不需要,但使用双引号 '"' 括起来并不重要,应该保留。在 DOS 中,注释只能使用 'REM'、'@REM' 或 '::' 前缀出现在一行的开头。虽然它们也一直延续到该行末尾。你可以选择使用哪种注释方法。但是,在任何批处理文件中都建议进行良好的注释,这样你就可以知道在每一步中命令试图做什么,当你几个月或几年后返回到脚本时。这样也让其他人更容易理解。所有脚本都应该以一个较大的注释开头,解释脚本的功能以及如何使用它。这只是一个良好的编程实践。
  • 当执行 DOS 批处理文件时,默认情况下会回显各个命令。也就是说,命令会显示在输出 DOS 框中。在 UNIX 下,你将需要添加一个特殊的命令或选项才能以这种方式打印正在执行的命令。你可以通过在脚本开头添加“@ECHO OFF” 来关闭这种“回显”输出。在 UNIX shell 脚本中,特殊的开头注释 “#!/path/to/shell” 在 DOS 批处理文件中不需要。因此,可以使用“@ECHO OFF” 命令代替 DOS 批处理文件中的这一行。
例如,遵循上述规则,这个 UNIX shell 脚本……

  #!/bin/sh
  # Create a negated rose image and overlay a comment
  magick -background none -fill red -gravity center \
          -font Candice -size 140x92 caption:'A Rose by any Name' \
          \( rose: -negate -resize 200% \) +swap -composite \
          output.gif
作为 Windows DOS 批处理文件,将变成类似下面的内容……

  @ECHO OFF
  :: Create a negated rose image and overlay a comment
  magick -background none -fill red -gravity center  ^
          -font "C:\path\to the\font\candice.ttf"  ^
          -size 140x92   caption:"A Rose by any Name"  ^
          ( rose: -negate -resize 200%% ) +swap -composite  ^
          C:\where\to\save\output.gif
我使用 SED(Streaming EDitor)编写了一个基本的 Linux shell 到 DOS 批处理文件转换器。SED 是一个通用的 UNIX/Linux 文本文件操作程序,它也适用于 Windows,可以在 http://sed.sourceforge.net/ 获取。就像 IM 是一个命令驱动的图像操作器一样,SED 是一个命令驱动的编辑器。执行所需操作的 SED 脚本 cim.txt 看起来像这样(当去除任何注释时)

  s/'/\"/g
  s/%/%%/g
  s/\\\([()!]\)/\1/g
  s/\([&|<>]\)/^\1/g
  s/^[ ]*#/::/
  s/\(^.*\)\( #.*$\)/\2\n\1/
  s/\(.:.*\.[a-z,A-Z]*\)[ ]/\"\1\" /g
  s/\\[ ]*$/^/
  s/^[ ][ ]//
你可以下载完整注释版本的 sed_script.zip 文件。如果你将 SED 脚本 cim.txt 放置在要转换的 Linux shell 脚本所在的同一个文件夹中,你可以通过以下方式调用转换

  %programfiles%\GnuWin32\bin\SED -f  cim.txt linux.scr > windows.bat
你也可以使用以下批处理文件,通过“发送到”或拖放来调用转换

SET SP=%programfiles%\GnuWin32\bin
%SP%\SED -f %SP%\cim.txt "%~1"> "%~dpn1.bat"
此批处理文件假设你已将 SED 脚本 cim.txt 放置在 SED 程序文件夹中。它将 Linux shell 脚本的文件名作为唯一的命令行参数,并在同一个文件夹中生成一个具有相同名称但扩展名为 '.bat' 的批处理文件。(在下一节中将解释神秘的文件名操作“%~dpn1.bat”。)请注意:上述 SED 脚本只会执行上面提到的基本替换。它不会将复杂的 Linux shell 脚本(例如 Fred Weinhaus 的网站 上提供的那些)转换为等效的批处理文件!

批处理文件中的文件名处理

如上所述,当将一组标准的处理步骤应用于图像文件时,IM 特别有用。在这种情况下,文件名将作为命令行参数传递给脚本,可以通过拖放或“发送到”来实现。使用这些技术,传递给 DOS 批处理文件的文件名将是一个完全限定的,即包含驱动器名称和目录路径。你可以通过将文件拖放到以下批处理文件中来测试这一点

ECHO Filename: %1
PAUSE
由于PAUSE语句,DOS窗口将保持打开状态,直到用户按下某个键,这样你就可以检查结果。尝试上面带有空格的文件名,你会发现文件名会被双引号括起来。请注意,这里和以下所有示例中,我们假设任何网络文件都被分配了一个驱动器字母。实际上,我在本地商业网络中从未见过不同。在使用批处理文件时,你不应该尝试处理UNC名称:你可能会使你的批处理文件工作,但这会给你带来很多不必要的麻烦。当在Convert命令行中使用此文件名时,这种行为会导致问题。让我们执行一个从任何其他格式到JPEG的简单转换。最基本的代码是

magick %1 %1.jpg
PAUSE
这将在同一个目录中生成一个JPEG文件(具有标准质量和分辨率),并附加一个额外的".jpg"扩展名。上面的代码适用于任何文件名,无论它是否包含空格。如果你想摆脱原始扩展名,事情会变得有点棘手

magick %1 "%~dpn1.jpg"
PAUSE
上面的批处理文件通过使用~运算符来操作文件名
%~1     展开%1,删除任何周围的引号(")
%~f1 将%1展开为一个完整的路径名
%~d1 将%1展开为一个驱动器字母
%~p1 将%1展开为一个路径
%~n1 将%1展开为一个文件名
%~x1 将%1展开为一个文件扩展名
这些修饰符可以组合起来,例如"%~dpn1"表示"驱动器+路径+没有扩展名和括号引号的名称"。因此,我们必须用双引号括起名称,这样代码也适用于包含空格的文件名。(如果没有,引号不会造成任何伤害。)PAUSE语句仅用于测试目的,可以在最终的批处理文件中删除。如果你只想测试你的代码而不实际调用IM,你应该写

ECHO magick %1 "%~dpn1.jpg"
PAUSE
这只会显示你的字符串操作的结果。

批处理多个文件

FOR 循环

DOSFOR命令可以用来处理一系列文件,类似于它在UNIX下的工作方式。为了将当前目录中的所有JPEG文件按比例缩小到50%,你可以在DOS窗口中输入以下内容

  FOR %a in (*.jpg) DO magick %a -resize 50% small_%a
请注意,百分号没有加倍。但是,如果你将此命令放在批处理文件中,你必须用以下命令替换它

  FOR %%a in (*.jpg) DO magick %%a -resize 50%% small_%%a
同样地,通过拖放或发送到,传递一个完整的路径名(或文件夹名)到一个可能位于另一个目录中的DOS批处理文件(例如shell:sendto)来调用此批量操作很方便。在这种情况下,我们应该在第一步中将文件的目录设置为当前目录

  %~d1
  CD "%~p1"
  MD small
  FOR %%a in (*.jpg) DO magick %%a -resize 50%% small\%%a
  PAUSE
在这个批处理文件中,我们
  • 通过提供驱动器名称(d: 或其他)来更改驱动器
  • 将文件的文件夹设置为当前目录
  • 创建一个名为“small”的子目录
  • 将所有JPEG文件按比例缩小到50%,并将这些缩小后的版本放在新创建的子目录中。
请注意:由于波浪号(~)释放了作为命令行参数传递的文件名,使其不受任何可能存在的括号引号的影响,因此我们通常必须再次用引号括起任何此类操作的结果。因此,我们在上面的例子中写了CD "%~p1"。在CD命令的情况下,我们甚至可以省略括号引号,因为此命令只接受一个参数,因此可以处理没有括号引号的空格。在第一步中将文件的目录设置为当前目录确实会使后续步骤变得更容易,因为对文件名的引用变得更容易和更短。然而,我们也可以写

  MD "%~dp1small"
  FOR %%a in ("%~dp1*.jpg") DO magick "%%a" -resize 50%% "%%~dpasmall\%%~nxa"
  PAUSE
这可能会使事情变得更短,但也更棘手。请注意,文件名修饰符也适用于For循环变量%%a。注意两点:最终的反斜杠是路径名的一部分。因此,它必须是"%~dp1small"而不是"%~dp1\small",这不会使代码更易读,特别是在"%%~dpasmall\%%~nxa"的情况下。FOR语句存在一些缺点和注意事项。其中之一是你基本上只在DO之后执行一个单一命令。但是,你可以用括号"("、")"将一系列DOS命令分组,从而执行一个简单的命令序列

  @ECHO OFF
  :: Lighten darker areas of all images in a directory
  %~d1
  CD "%~p1"
  FOR %%a in (*.jpg) DO (
    ECHO Processing file: "%%~nxa"
    magick %%a -blur 30 -negate %%a.miff
    magick composite %%a.miff %%a -compose overlay "%%~dpn1_light"%%~xa
    DEL %%a.miff
  )
  PAUSE
这个批处理文件将处理作为命令行参数传递的目录中找到的所有图像。首先,它会模糊原始图像并反转它,将中间结果存储在一个具有额外".miff"扩展名的文件中。然后,它将原始图像叠加到这个修改后的版本上,从而使原始图像中较暗的部分变亮。最后,中间图像被删除。请注意,在上面,必须强调简单的命令序列:你不能在块内使用GOTO跳转。如果你需要这种行为,你必须通过FOR循环调用另一个批处理文件

  %~d1
  CD %~p1
  MD small
  FOR %%a in (*.jpg) DO CALL "%~dp0process" "%%~fa"
其中"process.bat"是执行实际工作的批处理文件,它与调用批处理文件位于同一个目录中。命令行参数0("%0")是批处理文件本身的名称,因此"%~dp0process"在同一个目录中调用了批处理文件process.batFOR语句只提供文件名,它通过"%~fa"被转换为一个完整的路径名。在本例中,批处理文件process.bat中的代码与前面例子中括号内的代码相同

  magick %%1 -blur 30 -negate %%1.miff
  magick composite %%1.miff %%1 -compose overlay "%%~dpn1_light"%%~x1
  DEL %%1.miff
然而,使用一个单独的批处理文件提供了DOS批处理文件的所有(有限的)可能性。这在本文示例中没有区别,但我们将在后面展示这种方法的好处。如果你不想麻烦使用两个批处理文件,你可以让脚本创建第二个process.bat脚本(使用ECHO),从主循环中调用它,然后在工作完成后将其删除

  ECHO magick %%1 -blur 30 -negate %%1.miff >%~dp0process.bat
  ECHO composite %%1.miff %%1 -compose overlay "%%~dpn1_light"%%~x1 >>%~dp0process.bat
  ECHO DEL %%1.miff >>%~dp0process.bat
  %~d1
  CD %~p1
  MD small
  FOR %%a in (*.jpg) DO CALL "%~dp0process" "%%~fa"
  DEL %~dp0process.bat
在使用ECHO命令时,我们必须对任何特殊的DOS字符,特别是百分号,进行第二次转义。没错,IM本来可以在一个处理命令中完成上面所有的事情,从而不需要".miff"中间图像,但这并不是本文示例的重点。

批处理(子)目录树

有几种技术可以处理(子)目录树中的所有文件。最简单的方法是在FOR语句中使用"/R"标志,使它循环遍历当前目录下所有子目录中的所有文件。为了将子目录树中的所有TIFF文件转换为JPEG,你只需输入

  FOR /R %%a IN (*.tif) DO imconv "%%~a" "%%~dpna.jpg"
在使用"/R"标志时,你始终循环遍历整个子目录树,没有排序或过滤文件的选项。在接下来的例子中,我们将为所有子目录生成照片索引打印,并将这些打印放在根目录中。这提供了一种简单的方法来执行特定照片的视觉搜索,类似于Windows资源管理器中的预览,但不需要(耗时)地为每次搜索重新扫描整个目录树。首先,我们借助两个批处理文件来解决这个问题,一个执行循环,另一个执行实际工作。索引打印将是名为IDX_0001.jpg, IDX_0002.jpg, IDX_0003.jpg等等的低质量JPEG文件。首先,我们建立循环

  DEL IDX_????.JPG
  SET COUNT=0
  FOR /F "delims=" %%a in ('DIR /S /B /AD ^|FIND /I "Porsche" ^|SORT') DO CALL c.bat "%%a"
  DEL title.txt
第一行清除以前搜索的任何结果。在第二行,我们定义环境变量COUNT,我们将使用它来生成IDX_nnnn.JPG文件名。在第三行,我们通过DIR /S /B /AD建立所有子目录的列表,提取包含“Porsche”的目录(通过使用/I选项进行不区分大小写的匹配),并对这个过滤后的列表进行排序。排序将确保IDX文件的数字排序与目录路径名的字母排序一致。"delims="选项将抑制在第一个空格后截断行的标准行为。当调用批处理文件C.BAT时,我们用引号括起路径名以确保空格被正确处理。在最后一行,我们删除了由批处理文件C.BAT创建的临时文件。现在我们来进行实际工作

  CHCP 1252
  DIR %1\*.jpg>nul || GOTO :EOF

  :: Generate IDX filename
  SET /A COUNT+=1
  SET TFILE=000%COUNT%
  SET TFILE=IDX_%TFILE:~-4%.jpg

  :: Generate title without bracketing quotes
  ECHO %~1>temp.txt
  "C:\Program Files\Gnuwin32\bin\iconv.exe" -f ISO-8859-1 -t UTF-8 temp.txt>title.txt

  montage -geometry 210x140+0+5 -tile 6x -title @title.txt %1\*.jpg -quality 30%% %TFILE%
  jhead -cl %1 %TFILE%
在第一行,我们将代码页切换到西欧拉丁语(ISO-8859-1)。在第二行,我们检查目录是否实际包含任何照片,如果没有,则跳过批处理文件的其余部分。(执行批处理文件的其余部分实际上不会造成任何伤害,因为magick montage将不会生成任何输出,但IDX文件的计数将不再是连续的。)自Windows XP以来,有一个特殊的GoTo目标标签:EOF,它允许终止执行而不定义一个合适的标签。然后,我们通过递增"COUNT"、附加一些前导零,并通过%TFILE:~-4%提取最后4个字符,然后将它们连接起来,生成索引文件的名称"TFILE",以创建类似于"IDX_nnnn.jpg"的文件名。SET /A语句用于执行计算,在后面的使用SET进行计算中对此进行了说明。在接下来的几行中,我们将路径名"PNAME"的引号释放,并将结果存储在中间文件'temp.txt'中,该文件通过"Icon.exe"(参见"字符编码")被转码为Unicode(UTF-8)。然后,IM的蒙太奇读取存储在'title.txt'中的Unicode字符串。这将确保该字符串被逐字处理,因此我们不必对Windows路径名中的反斜杠进行转义。然后,蒙太奇以六行(-tile 6x)组合照片,并用路径名对其进行标题。生成的索引打印将宽度为1260像素,并以30%的JPG质量存储,以减少存储需求。在最后一行,我们使用程序JHEAD将路径名写入JPEG注释中。这提供了一种可能性,可以根据Windows资源管理器中的文件名中的某些子字符串对索引打印进行文本搜索过滤。我们可以将这两个批处理文件合并,将“工作批处理”的代码放在FOR循环中

  SETLOCAL EnableDelayedExpansion
  SET ICONV="%PROGRAMFILES%\Gnuwin32\bin\iconv.exe" -f ISO-8859-1 -t UTF-8
  CHCP 1252
  DEL IDX_????.JPG
  SET COUNT=0
  FOR /F "delims=" %%a in ('DIR /S /B /AD ^|FIND /I "Porsche" ^|SORT') DO (
    DIR "%%a\*.jpg">nul
    IF !ERRORLEVEL!==0 (
      SET /A COUNT+=1
      SET TFILE=000!COUNT!
      SET TFILE=IDX_!TFILE:~-4!.jpg
      ECHO %%a >temp.txt
      %ICONV% temp.txt>title.txt
      montage  -geometry 210x140+0+5 -tile 6x -title @title.txt "%%a\*.jpg" -quality 30%% !TFILE!
      jhead -cl %%a !TFILE!
    )
  )
  DEL temp.txt
  DEL title.txt
基本上,必须对初始代码进行两个修改
  • 我们必须启用延迟扩展,并通过用感叹号而不是百分号括起它们来引用FOR循环中使用的环境变量。
  • 我们必须避免GOTO语句,它会重置命令处理器。
默认情况下,FOR循环中的环境变量不会在运行时进行评估。相反,代码将使用括号中给出的列表进行预处理。因此,FOR循环中对%COUNT%的引用总是返回相同的值。为了启用环境变量的运行时评估,你必须打开延迟扩展。这可以通过cmd /V:on调用命令处理器来完成,或者通过使用以下REG文件在注册表中全局打开

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Command Processor]
"DelayedExpansion"="1"

[HKEY_CURRENT_USER\Software\Microsoft\Command Processor]
"DelayedExpansion"="1"
然而,最简单的版本是在批处理文件中使用SETLOCAL EnableDelayedExpansion来设置此选项,这也会将对环境变量的任何更改限制在当前版本的命令处理器中,这可能是我们想要的。现在,循环中对环境变量的运行时值的引用必须使用感叹号而不是百分号。在FOR循环中使用GOTO语句可能是非常微妙的错误的来源,因此应该避免。然而,在我们的批处理中,我们可以很容易地用一个IF语句来交换跳转,并用蒙太奇代码括起代码块。

批处理任意数量的文件

在 DOS 批处理文件中,只有九个命令行参数可以通过 `%1` 到 `%9` 直接寻址。在早期的 Windows 版本中,你只能通过 `SHIFT` 命令绕过这个限制,该命令会导致命令行参数的循环移位。在新版本中,命令行参数可以在 For 循环中处理。

  FOR %%i in (%*) DO ...
这允许我们对通过拖放传递的任意数量的图像进行拼贴。

  @ECHO OFF
  SETLOCAL EnableDelayedExpansion
  %~d1
  CD "%~p1"
  DEL Files.txt   2>nul:
  DEL FSorted.txt 2>nul:
  FOR %%I in (%*) DO ECHO %%~nxI>>files.txt
  FOR /F "delims=" %%A in ('TYPE files.txt ^| Sort') Do (
  ECHO %%A>>fsorted.txt
  )
  SET MONTAGE=montage -tile 3x
  FOR /F "delims=" %%A in (FSorted.txt) Do (
  SET MONTAGE=!MONTAGE! %%A
  )
  SET MONTAGE=%MONTAGE% result%~x1
  %MONTAGE%
  DEL Files.txt
  DEL FSorted.txt
上面的代码假设作为命令行参数传递的文件位于同一个目录中,并且必须根据其文件名的字母数字顺序进行拼贴。例如,这对于数字照片的索引是有意义的,这些照片将按拍摄时间排序。我们首先将文件的目录设置为当前目录,这使得后面的代码更加简单。然后,我们将文件名转储到 `files.txt` 中。即使文件是按字母顺序选择的,我们也不能依赖于将文件名传递给脚本时这种顺序会被保留。因此,我们在第二个工作步骤中对文件进行排序,并将它们转储到 `fsorted.txt` 中。基于该文件,我们然后在另一个 For 循环中构建拼贴命令行。拼贴输出文件使用与第一个输入文件相同的扩展名(`%~x1`)。(假设所有文件共享相同的扩展名。)请注意,最终的拼贴命令只是通过评估环境变量来调用的,即 `%MONTAGE%`。正如在 中提到的,在 Windows XP 下传递大量带有长(完整)文件名的文件可能会出现问题,因为 ShellExecute 的参数列表限制为 2048 个字符。此错误无法由批处理文件处理,因为它发生在将控制权传递给批处理文件 **之前**。一个可能的基于脚本的解决方案是在将一个文件传递给批处理文件时处理目录中的所有图像文件。

 %~d1 & IF EXIST %1\* (CD %1) ELSE CD %~p1
 IF "%2"=="" (
 SET PATTERN=*.jpg
 ) ELSE (
 SET PATTERN=%*
 )
 FOR %%v IN (%PATTERN%) DO (...)
在第一行中,我们检查第二个命令行参数是否存在。如果存在,则处理所有命令行参数(%*)。如果只将一个文件传递给脚本,则模式设置为所有 JPEG 文件。这种简单的模式匹配要求我们更改到当前驱动器(通过 %~d1)和当前文件夹,即
  • 如果将文件夹名称传递给脚本,则 `CD %1`
  • 如果将文件名传递给脚本,则 `CD %p1`。

从 ImageMagick 获取信息

重复使用 IM 命令的输出

在最近的 Windows 版本中,`FOR` 语句的功能变得更加强大,请参见 DOS "For" 命令帮助。通过使用 "/F" 选项,你可以从文件、字符串或来自另一个 DOS 命令或另一个程序的输出中读取替换变量的输入。后者对于 IM 来说特别有用。为了大致了解 IM 的叠加方法的真正含义,你可以使用以下批处理文件

  @ECHO OFF
  :: compose two gradients using all compose methods available
  ::
  magick -size 80x80 -flip gradient: compose_src.png
  magick compose_src.png -rotate 90 compose_dst.png
  FOR /F %%A in ('magick -list compose') DO ^
     magick composite compose_src.png compose_dst.png -compose %%A compose_%%A.png
[IM Output]
Src
[IM Output]
Dst
==> [IM Output]
Multiply
[IM Output]
Screen
[IM Output]
Overlay
此脚本将两个渐变图像组合在一起,使用每个可用的 Alpha 组合方法,因此你可以看到运算符如何影响图像颜色。它生成的图像中只有部分显示在上面。这类似于为 组合表格 生成的图像,因此你可以看到运算符如何影响图像颜色。由于上面的行被认为是批处理文件,因此我们必须将百分号加倍。上面的脚本首先创建两个正交(直角对齐)的灰度图像,渐变覆盖整个灰度范围。IM 命令 `Convert -list compose` 将提供我们所有可能的选项列表,每个选项都放置在单个输出行中。请注意,在引用括号中的命令时,我们必须使用单引号。使用 "/F" 选项,`FOR` 命令将处理这些输出行中的每一个,并将它传递给 `DO` 执行的命令。结果,两个渐变图像将叠加,应用 IM 所知的叠加方法。输出文件根据叠加方法进行相应命名。 在下面的示例中,我们说明了 IM 提供的颜色空间。我们使用与上面相同的渐变技术来生成一个立方体的三个表面,这些表面由颜色空间的三个坐标跨越

magick -size 256x256 gradient: gy.miff
magick gy.miff -rotate 90 gx.miff
magick -size 256x256 xc:black black.miff

::R + G top left
magick gy.miff gx.miff -flop black.miff -set colorspace %1 -combine ^
        -resize 260x300! -background none -shear 0x-30 ^
        -virtual-pixel Transparent RG.miff

:: R + B top right
magick gy.miff  black.miff gx.miff -set colorspace %1 -combine ^
        -resize 260x300! -background none -shear 0x30 RB.miff

:: G + B bottom
magick black.miff gx.miff gy.miff -set colorspace %1 -combine ^
        -resize  260x300! -background none -shear 0x30 -rotate 120 ^
        -crop 520x300+0+75 GB.miff

magick -set colorspace %1 RG.miff RB.miff +append top.miff
magick -set colorspace %1 -size 520x150 xc:Transparent w.miff
magick top.miff w.miff -append topx.miff

composite -geometry +0+299 GB.miff  topx.miff colorspace_%1.png
DEL *.miff
[IM Output]
colorspace RGB
[IM Output]
colorspace sRGB
使用 UNIX shell 脚本的类似示例在 使用剪切的等轴测立方体 中给出。
此批处理文件将颜色空间作为命令行参数 "%1"。然后它生成立方体的三个侧面,并将它们剪切和装配起来,使我们得到一个等轴测视图,其中点 (0,0,0) 位于六边形的中心。最终的图片以颜色空间(即 "%1")命名,并保存为 PNG 格式。我们现在想要从另一个批处理文件中调用这个批处理文件(保存为 "cspace.bat"),该批处理文件提供颜色空间的名称

  FOR /F %%A in ('magick -list colorspace') DO CALL cspace %%A
我们还可以通过在 DOS 中使用管道过滤 `-list` 选项的输出

  magick -list colorspace | FIND "RGB" >>clist.txt
  FOR /F %%A in (clist.txt) DO CALL cspace %%A
  DEL clist.txt
在此示例中,我们从输出中过滤包含 "RGB" 的那些行,并将它们写入文件 `clist.txt`。然后,该文件被用作 `FOR /F` 命令的输入。我们也可以在一个运行中完成此操作,避免使用临时文件

  FOR /F %%A in ('magick -list colorspace ^| FIND "RGB"') DO CALL cspace %%A
在这种情况下,管道符号 "|" 必须进行转义,因为它没有被双引号括起来(只有 `FOR` 语句所需的单引号),并且(至少在上面的命令行中)不具有其通常的意义。

处理单行输出

此技术还可以有效地应用于单行输出。例如,我们可以通过 Fred Weinhaus 的网站 上解释的技术来应用自动伽马校正,该技术大致将图片的平均亮度设置为量子范围的中间(即对于 8 位颜色深度为 127)。

  FOR /F %%a in ('identify -format "%%[fx:log(mean)/log(0.5)]" %1') DO ^
  magick %1 -gamma %%a "%~dpn1"_c.%~x1
此批处理文件将一个完整限定的文件名作为命令行参数 "%1" 传递,最有可能通过拖放或发送到。IM 的 Identify 命令的输出将提供一个伽马值,该值将设置图像的平均亮度到其动态范围的中间。此值是使用 FX 格式表达式 计算的。Identify 命令的单行输出保存到 "%%a" 变量中,并作为 Gamma 运算符 的参数传递给 Convert 命令。
当涉及到行延续时,`FOR` 命令似乎非常敏感:如果你使用它们,请确保下一行不要以空格开头。
这种自动伽马校正方法现在已内置于 IM 中,使用 "-auto-gamma",并添加到 IM v6.5.5-1 中。但它展示了将命令输出重新用于以后命令参数的技术。
使用相同的 `FOR` 技术,我们可以从嵌入在照片中的 EXIF 信息中读取,并将其写入图像的左上角

  FOR /F "tokens=1,2" %%i IN ('identify -format "%%[EXIF:DateTime]" %1') DO ^
  magick %1 -pointsize 18 -fill white -gravity northwest ^
    -annotate +0+0 "%%i %%j" "%~dpn1"_dated%~x1
照片通常使用 JPEG 格式保存。由于 JPEG 有损压缩,读取和重新保存 JPEG 图像会导致图像略微降级,因此不建议保存回 JPEG 格式。
在上面的批处理文件中,照片的文件名作为单个命令行参数提供,称为 "%1"。Identify 命令从 JPEG 文件中的 EXIF 信息中读取拍摄照片的日期和时间。然后,`FOR` 命令将此输出传递给 Convert,Convert 将相应地在照片的左上角添加注释。EXIF 日期和时间信息格式为 "yyyy:mm:dd hh:mm:ss",例如 "2006:12:26 00:22:38"。因此日期和时间用空格隔开。默认情况下,`FOR` 语句只会找到每行中的第一个标记("单词"),以制表符和空格字符作为标准分隔符。因此,在上面的示例中,标准处理只会处理返回日期,而不是时间。使用选项 "tokens=1,2",我们声明我们对两个标记都有兴趣,这些标记按顺序命名,即 "%x, %y"。但是,我们可以通过以下代码更改日期的非常规格式

  FOR /F "tokens=1,2,3,* delims=: " %%i IN ('identify -format "%%[EXIF:DateTime]" %1') DO ^
  magick %1 -pointsize 18 -fill white -gravity northwest ^
    -annotate +0+0 "%%j/%%k/%%i %%l" "%~dpn1"_dated%~x1
我们现在将冒号(':')定义为额外的分隔符,导致日期被分解为三个标记 "%i","%j","%k"。找到的下一个分隔符是分隔日期和时间的空格字符。使用星号("*"),我们要求将行的其余部分存储在第四个标记 "%l" 中。我们现在可以按照我们喜欢的格式来格式化日期。我们选择了上面的示例中的英美格式 "mm/dd/yyyy"。

从单个命令设置多个值

从一个 ImageMagick 命令中设置多个值的技术是让命令格式化数据,以便你可以设置多个变量。

  FOR /F %%L IN ('identify -format "Width=%%w\nHeight=%%h" %1') DO set %%L
这将导致从单个 ImageMagick 命令调用中设置 DOS 变量 'Width' 和 'Height'。

执行计算

DOS 命令解释器在进行计算方面很差。你可以使用它来执行简单的整数运算。但对于进行更复杂的浮点数学运算,你可以访问 IM 的 FX 格式表达式 或第三方 DOS 计算器程序。

使用 IM 的 FX 表达式

IM 的 FX 格式表达式 可用于浮点数学运算,并且可以将这些数学运算添加到更大的格式化字符串中,如上面 处理单行输出 部分的第一个示例中所示。通过使用 `SET` 命令,结果可以存储在环境变量中,并在以后的批处理文件中使用。作为一个简单的例子,我们可能希望调整上面示例中日期时间字符串的字体大小,使其与照片的尺寸相对应

  FOR /F %%i IN ('identify -format "%%[fx:min(w,h)*0.05]" %1') DO SET psize=%%i

  FOR /F "tokens=1,2,3,* delims=: " %%i IN ('identify -format "%%[EXIF:DateTime]" %1') DO ^
  magick %1 -pointsize %psize% -fill white -gravity northwest ^
    -annotate +0+0 "%%j/%%k/%%i %%l" "%~dpn1"_dated%~x1
在第一行中,我们通过 "%[fx:min(w,h)]" 计算照片的较小尺寸,取其 5% 并将其存储在环境变量 PSIZE 中。这个值在下一条语句 (%psize%) 中被引用,以设置日期时间信息的字体大小。在这里,我们计算了一个随机角度,作为 -15° 到 +15° 之间的整数,以创建一个旋转的缩略图图像。

  FOR /F %%x IN ('magick null: -format "%%[fx:int(rand()*31)-15]" info:') DO SET angle=%%x
  magick %1 -thumbnail x90 -alpha set ^
            -background none -rotate %angle%   "%~dpn1"_rotated.png
FX 表达式 不仅可以生成数字,还可以生成多个数字,并将其嵌入更大的字符串中。例如,在 圆角边框 中,它被用来直接根据图像宽度和高度信息生成一个复杂的绘制字符串。此附加功能,以及避免和进一步依赖其他外部程序,使得这种方法成为在批处理脚本中进行计算的首选方法。

使用 SET 命令

当调用 "/A" 选项时,`SET` 命令可以执行一些简单的整数数学运算和一些基本的字符串操作。在下面的示例中,我们使用 `SET` 命令粗略地计算日期时间字符串的宽度

  :: Determine the font height
  FOR /F %%i IN ('identify -format "%%[fx:min(w,h)*0.05]" %1') DO SET psize=%%i

  :: The width of the date-time string is roughly 9 times its height
  SET /A pwidth=%psize% * 9

  :: Calculate the average brightness in this section
  :: and choose the text color correspondingly
  FOR /F %%i IN ('identify -format "%%[fx:mean]" -crop %pwidth%x%psize%+0+0 %1') DO SET mean=%%i
  IF %mean% LEQ 0.5 (SET fcolor=white) ELSE SET fcolor=black

  :: Annotate the photograph
  FOR /F "tokens=1,2,3,* delims=: " %%i IN ('identify -format "%%[EXIF:DateTime]" %1') DO ^
  magick %1 -pointsize %psize% -fill %fcolor% -gravity northwest ^
    -annotate +0+0 "%%j/%%k/%%i %%l" "%~dpn1"_dated%~x1
此示例批处理文件根据日期时间字符串将要放置的区域的平均亮度 (%mean%) 选择日期时间字符串的颜色。如果平均颜色强度小于 50%,则字符串将为白色,否则为黑色。该示例还使用了 `IF` 语句。请注意,`ELSE` 部分必须放在同一行中,并且第一个命令必须用括号括起来。

使用其他外部计算器

作为替代方案,您可以使用提供浮点运算的 DOS 程序,例如 EVAL。 如果您将此文件放在 IM 程序目录或 Windows 系统目录中,您可以在任何 DOS shell 窗口中执行浮点运算。 通过使用 EVAL 程序、FOR 命令和环境变量,我们可以使上面的颜色立方体示例更灵活,并且其各种计算更加透明。

  magick -size 256x256 gradient: gy.gif
  magick gy.gif -rotate 90 gx.gif
  magick -size 256x256 xc:black black.gif

  :: Set the dimension of the color cube / hexagon and calculate the various lengths
  SET l1=512
  FOR /F %%i IN ('EVAL "round(cos(degree*30)*%l1%)"') DO SET l2=%%i
  FOR /F %%i IN ('EVAL "2*%l2%"') DO SET l3=%%i
  FOR /F %%i IN ('EVAL "round((1+sin(degree*30))*%l1%/2)"') DO SET l4=%%i
  FOR /F %%i IN ('EVAL "round(%l1%/4)"') DO SET l5=%%i

  magick gy.gif gx.gif -flop black.gif -set colorspace %1 -combine ^
          -resize %l2%x%l1%! -background none -shear 0x-30 ^
          -virtual-pixel Transparent RG.miff

  magick gy.gif  black.gif gx.gif -set colorspace %1 -combine ^
          -resize %l2%x%l1%! -background none -shear 0x30 RB.miff

  magick black.gif gx.gif gy.gif -set colorspace %1 -combine ^
          -resize  %l2%x%l1%! -background none -shear 0x30 -rotate 120 ^
          -crop %l3%x%l1%+0+%l5% GB.miff

  magick -set colorspace %1 RG.miff RB.miff +append top.miff
  magick -set colorspace %1 -size %l3%x%l4% xc:Transparent w.miff
  magick top.miff w.miff -append topx.miff

  magick composite -geometry +0+%l1% GB.miff  topx.miff colorspace_%1.png
  DEL *.miff
  DEL *.gif

编辑、调试和运行时错误测试

原则上,DOS 批处理文件可以用任何编辑器编写,即使是 Windows 的记事本。 但是,您应该使用支持 DOS 批处理文件语法高亮的编辑器。 我个人认为 Notepad++ 是最佳选择,但谈论编辑器往往会让人不爽。 所以:是的,任何其他编辑器都可以。 据我所知,市面上没有免费的批处理文件 IDE(集成开发环境)。 人们可能会认为这应该是操作系统自带的东西,但事实并非如此。 到目前为止,我所有的批处理文件都是用 Notepad++ 编写的,但对于那些经常编写批处理文件的人来说,Running Steps 批处理 IDE 可能会有所帮助。 它是共享软件,价格约为 80 美元。 有关 DOS 命令的全面解释,请访问 http://www.computerhope.com/msdos.htm。 就像 DOS 批处理语言本身一样,调试批处理文件是一件相当奇怪的事情。 我会建议您从在 DOS 盒子里测试任何批处理文件开始。 测试拖放或发送到时,建议在批处理作业完成后用 PAUSE 语句结束批处理文件,这样 DOS 盒子会保持打开状态。 考虑到运行时错误消息,一般方法是检查 DOS ERRORLEVEL 并跳转到由 ECHO 命令生成的相应错误消息。 我发现最有可能的错误来源之一是 Convert 程序在运行脚本的机器上没有被正确找到。 因此,如果您打算与他人共享您的批处理脚本,您首先应该检查 Convert 是否可以访问。

  @ECHO OFF
  magick -version 1>nul: 2>nul:
  IF NOT %errorlevel%==0 GOTO NoMagick:
  magick ...
  GOTO :EOF
  ...
  :NoMagick
  ECHO ImageMagick (convert.exe) not found.
  PAUSE
在第一行,我们询问 ImageMagick 版本,通过 1>nul:(或只用 >nul:)抑制标准输出,通过 2>nul: 抑制任何错误消息,即我们将 stdoutstderr 重定向到 nul:。 如果调用 IM 的 Convert 失败,系统程序 Convert 将被调用,它无法处理 -version 选项,并将设置 ERRORLEVEL 变量。 您可以尝试确定为什么找不到 Convert 并尝试解决问题:您可以确定 IM 的程序路径是否是环境变量 PATH 的一部分。

  @ECHO OFF
  PATH | FIND /I "ImageMagick"
  IF NOT %errorlevel%==0 GOTO NoPath:
  ...
  :NoPath
  ...
如果 Find(以不区分大小写的选项 /I 调用)找不到字符串,它将设置 ERRORLEVEL。 在更复杂的方法中,您可以检查注册表项,不再依赖 PATH。

  @ECHO OFF
  FOR /F "tokens=1,2,*" %%A in ^
  ('reg  query "HKCM\Software\ImageMagick\Current" ^| FIND "BinPath"') DO ^
  SET MPATH=%%C
  IF [%MPATH%]==[] GOTO NoMagick:
  "MPATH\convert.exe" ...
  ...
  :NoMagick
  ...
通过这段代码,我们查询 IM 的注册表键 Current 并搜索 BinPath 项。 输出中决定性的一行是:LibPath REG_SZ C:\Program Files\ImageMagick 这行文本中的“词语”由制表符(在 Windows XP 中)或几个空格(Windows Vista)隔开。 这些是 For /F 使用的标准分隔符。 我们要找的是第三个“词语”(%%C),我们将它存储在环境变量 MPATH 中,我们可以在脚本中稍后调用 magick 时引用它。 脚本可能需要安装特定版本的 ImageMagick,才能满足最低版本要求。 例如,透视扭曲方法 最初是在版本 6.3.5-9(2007 年 9 月)中实现的。 因此,如果您的脚本处理透视校正,您应该测试安装的 IM 版本是否比该版本更新。

  @ECHO OFF
  SETLOCAL EnableDelayedExpansion
  SET MINVERSION=7.5.3-0
  FOR /F "tokens=1,2,3" %%a in ('magick -version ^|FIND "Version"') DO SET VERSION=%%c
  IF %VERSION% LSS %MINVERSION% GOTO GetNewVersion:
  Goto :EOF
  :GetNewVersion
  ECHO This Script requires et least ImageMagick version %MINVERSION%.
  ECHO Yours is %VERSION%.
  PAUSE
  Goto :EOF
SETLOCAL 将任何对环境变量的更改限制在当前脚本范围内,这样我们就不必担心副作用。 选项 EnableDelayedExpansion 在这里并不真正需要,但在使用 SETLOCAL 时使用该选项是一个好习惯。 然后我们将所需的最低版本存储在环境变量 MINVERSION 中。 在第三行,我们用 '-version' 选项调用 Convert,通过 ^|FIND "Version" 从输出中提取第一行,从该行中获取第三个词语,并将它存储在环境变量 VERSION 中。 然后,我们在第四行将此版本与所需的最小版本进行比较。

优化执行时间

要测量执行时间,您可以显示 %TEMP% 环境变量的内容。 以下脚本测试了各种计算(大型)图像文件(例如数码照片)的平均亮度的各种方法。

   IF "%1"=="" GOTO :EOF
   ECHO %TIME%
   Identify -verbose %1 | FIND "mean" & ECHO %TIME%
   copy %1 %TEMP%\*.* & ECHO %TIME%
   Identify -verbose %TEMP%\%1 | FIND "mean" & ECHO %TIME%
   Convert %TEMP%\%1  -format %%[fx:mean] info: & ECHO %TIME%
   Convert %TEMP%\%1 -resize 1x1! -format %%[fx:mean] info: & ECHO %TIME%
   DEL %TEMP%\%1
图像作为单个命令行参数传递给脚本,在脚本的第一行进行测试。 接下来,通过在语句之前和之后回显环境变量 %TIME% 来测量各种方法的执行时间。 与号 & 允许将多个 DOS 命令放在一行中,这里只是用来缩短代码所需的空格。 如果图像放置在网络驱动器上,则传输到客户端计算机的内存可能会消耗相当多的执行时间。 因此,该文件被复制到本地临时文件夹,其名称存储在环境变量 %TEMP% 中。 事实证明,简单的 Convert 命令的执行时间与过滤 Identify 结果的执行时间相同,但通过 -resize 1x1! 将图像调整为一个像素,可以显着加快操作速度,而不会过多地改变其结果。 请注意,我们使用 ECHO %TIME% 而不是 TIME /T,因为后者只会显示小时和分钟,而前者会提供百分之一秒。 与 UNIX 命令 shell 相比,没有直接的方法来测量相对时间,即设置一个参考点,执行语句,然后评估所需的时间。 在批处理文件中计算相对时间之所以困难,是因为批处理文件只允许整数运算。 可以通过 FOR 命令提取秒数,然后使用 IM 的 fx 运算符执行减法,允许 60 秒溢出。

   FOR /F "tokens=1,2,* delims=:" %%a in ("%TIME%") DO SET START=%%c
        ... some command(s)...
        FOR /F "tokens=1,2,* delims=:" %%a in ("%TIME%") DO SET STOP=%%c
   Convert null: -format "%%[fx:(%STOP%-%START%<0.0)?%STOP%-%START%+60.0:%STOP%-%START%]" info:
但是,这仅适用于将小数点设置为小数点的 Windows 版本,因为时间是根据区域设置提供的,而 fx 是根据美国方案执行计算的。 与 VBScript 相比,在批处理文件中没有方法可以更改区域设置(除了通过注册表更改整个机器的区域设置)。 作为替代方案,可以将整个时间转换为百分之一秒,这可以在整数运算中完成,并且以后可以计算任何差异。 基本代码是

   for /f "tokens=1-4 delims=:., " %%a in ("%TIME%") do ^
        set /a  Start100S=1%%a * 360000 + 1%%b * 6000 + 1%%c * 100 + 1%%d - 36610100
在拆分的每个时间代码部分之前插入“1”可以防止以零开头的数字被(错误地)解释为八进制。 通过这种方法引入的“计算误差”将在最后通过减去 36610100 来补偿。 完整的(更优雅的)示例代码可以在这里找到 这里。 另一种方法是 Windows 2003 资源工具包提供的 TimeIt 实用程序,可以从 这里 下载。 但它官方上只支持 Windows XP。

批处理编程指南

简而言之,编程批处理文件时应遵循以下规则:
  • SETLOCAL EnableDelayedExpansion 开始。
  • 定义一个变量来引用 IM 的 Convert 工具:SET IMCONV="%PROGRAMFILES%\ImageMagick"
  • 处理多个文件时,将包含这些文件的文件夹设为当前文件夹通常可以简化代码,即
    • 通过 %~d1 更改驱动器。
    • 通过 CD %~p1 更改文件夹。
  • 使用 GnuTools 的 iconv.exe 将文本转换为 UTF-8 并从文件提供文本。
  • 请记住,Convert 和 Montage 将文本输出写入 stderr,而不是 stdout
  • 许多错误都来自文件名包含空格,因此检查每个批处理文件是否正确处理了此类文件名。
  • 不要忘记将每个百分号加倍,例如设置 JEPG 质量时。
  • 不要忘记对字符串中的特殊字符进行转义,例如 "^|"。
  • SET /A 执行的整数计算将以零开头的任何数字视为八进制,因此在每个这样的数字前面加上一个“1”。

总结

上面的示例证明了,当与 ImageMagick 提供的功能结合使用时,简单的 DOS 批处理文件具有惊人的通用性。 事实上,几乎所有事情都可以通过某种(粗陋的)方式在批处理文件中完成。 一旦你开始用 DOS 批处理文件语言开发中遵循的奇怪方式思考,脚本甚至可以变得相当简短。 不过,除非你非常熟悉批处理文件语言,否则这几行代码可能会消耗数小时的枯燥实验。 如果您要进行比基本图像处理任务更高级的任务,建议使用更复杂的脚本语言,因为代码的开发将变得更简单、更结构化。

Visual Basic 脚本 (VBS)

Microsoft Windows Script Host (WSH) 的脚本功能比简单的批处理文件语言更复杂。 WSH 在语言方面是独立的,因为它可以使用不同的活动脚本语言引擎。 默认情况下,它解释并运行纯文本 JScript 文件(Java Script)和 VBScript 文件(VisualBasic Script)。 Windows Script Host 是为 Windows 98 及更高版本默认分发和安装的(但是,由于安全问题,它可能在可能的目标机器上被关闭)。 WSH 实现了一个对象模型,它公开了一组 COM 接口,使您可以访问系统对象,尤其是文件系统。 我们不会在这里详细讨论 Windows Script Host,因为这在其他地方(并且可能更好)已经完成了,而是会给出一些实际的示例来说明如何解决典型问题。 示例是用 VisualBasic Script 给出的,但 JScript 代码非常类似,因此应该很容易将示例改写成 JScript,如果这是您喜欢的语言。 与批处理文件一样,VBScript 可以用任何编辑器编写,我仍然建议 Notepad++ 作为首选编辑器。 对于批处理文件,Microsoft 没有提供专门支持 VBScript 开发的 IDE。 曾经有一个 Microsoft Script Editor 与 Microsoft Office 2000 到 2003 捆绑在一起,但我从未尝试过。 Microsoft 还提供了(非常基本的)Microsoft Script Debugger,但同样,我对它没有太多个人经验。 市场上提供了一些商业化的 VBS IDE,作为价格合理的共享软件,例如 VbsEdit。 正如在 在 Windows 上安装 ImageMagick 部分中所述,我们通常不会在以下示例中使用 ImageMagick 的 COM+ 接口。 IM 的工具(例如 Convert、Montage 和 Identify)将通过调用 shell 的 run 命令来直接运行,并包含所有必要的选项和文件名,这与在批处理文件中执行的方式非常相似。 然而,在组装命令字符串时,我们将利用真正的编程语言提供的功能。

基本示例:镜头校正

由于 WSH 的使用会产生一些开销,因此我们的入门示例并非过于基础,以便展示 VBScript 相比于简单批处理文件的优势。在接下来的内容中,我们将使用 IM 的 桶形失真 来校正尼康 995 数码相机的镜头失真。校正参数取决于焦距,焦距可以通过 magick identify 首先查找。为了校正尼康 995 镜头的失真,我们只需要参数 b(即 a, c = 0),它可以通过以下公式从焦距 f 计算得到:b = 0.000005142 f ³ - 0.000380839 f ² + 0.009606325 f - 0.075316854 此依赖关系是通过 lensfun 数据库 找到的,该数据库列出了此镜头的桶形失真参数。以下是我们的 VBScript 代码。

  SetLocale(1033)          ' US, i.e. decimal point
  const strConv = "IMCONV" ' name of the IM Convert program
  const strAdd = "_pt"    ' string attached to the filename
  '
  Dim wsh
  Set wsh = CreateObject("Wscript.Shell")
  '
  ' names of the in- and output files
  strFileIn = WScript.Arguments(0)
  Pos = InStrRev(strFileIn,".")
  strFileOut = Left(strFileIn,Pos - 1) & strAdd & Mid(strFileIn, Pos)
  '
  ' evaluation of the focal length and calculation of parameter b
  command = "identify -format ""%[EXIF:FocalLength]"" """ & strFileIn & """"
  Set objExec = wsh.Exec(command)
  strf = objExec.StdOut.Readline
  f = eval(strf)
  b =  0.000005142 * f * f * f -0.000380839 * f * f + 0.009606325 * f  -0.075316854
 '
  Command = strConv & " """ & strFileIn _
    &  """ -virtual-pixel black -filter point -distort Barrel   ""0.0 " _
    & b & " 0.0 "" """ & strFileOut & """"
  wsh.run command,7,true
在第一行,我们将区域设置设置为美国英语 (1033),这(除了其他事项之外)将小数分隔符设置为小数点。否则,小数将根据区域设置显示,即可能使用小数点而不是小数点,这将在将这些值传递给 IM 时造成问题。在字符串常量定义后的两行是标准开销,因为我们始终需要一个 Shell 对象来通过其 ExecRun 方法启动 IM 的程序。唯一的脚本参数是一个文件名,我们通常通过拖放或“发送到”提供。在命名输出文件时,我们在原始文件名后附加“_pt”,就像 PTlens 一样,例如 Photo.JPG → Photo_pt.JPG。文件名存储在 strFileIn 中,我们从中推导出输出文件名 strFileOut。然后我们运行 IM 的 Identify 程序。结果(即表示焦距的 EXIF 有理数)存储在 strf 中。EXIF 有理数以分子 / 分母的形式提供,例如 82 / 10 = 8.2 mm。因此,有理数必须在用于计算参数 b 的公式中使用之前进行评估。在最后两行,我们构建了 Convert 命令行,并通过 Shell 对象的 Run 方法执行该语句。参数 7 将窗口最小化,TRUE 告诉脚本等待结果。以上脚本概述了使用 VBScript 与 IM 命令行工具(而非 COM+ 对象)的通用策略。这些工具可以通过以下方式调用:
  • 如果不需要文本输出,则通过 Shell 对象的 Run 命令调用
  • 如果需要评估文本输出,则通过 Shell 对象的 Exec 命令调用,这通常是 Identify 的情况。
这个第一个 VBScript 并没有做任何批处理文件无法完成的事情,例如

   SETLOCAL EnableDelayedExpansion
   FOR /F %%i in ('identify -format "%%[EXIF:FocalLength]" %1') DO SET FL=%%i
   FOR /F %%i IN ('Convert null: -format "%%[fx:0.000005142*(%FL%)^3 - 0.000380839 * (%FL%)^2 + 0.009606325 * %FL% - 0.075316854]" info:') DO SET B=%%i
   Convert %1 -distort barrel "0.0 !B! 0.0" "%~dpn1_pt%~x1"
但是 VBS 代码更直观,更易于修改,并且可以轻松地扩展以进行错误检查等。请注意,第二个 FOR 语句中的换行符是不可能的,因此我们必须保持其长度。

处理多个文件

VBScript 与 DOS 批处理文件相比的一个真正优势是,您可以轻松地循环遍历任意数量的命令行参数。例如,您可以在 Windows 资源管理器中选择多个文件,并通过 IM 的 Montage 将选定的图像组合到一个索引打印中。基本代码如下

  Dim wsh
  Set wsh = CreateObject("Wscript.Shell")
  '
  strInputFiles  = ""
  For EACH Arg IN WScript.Arguments
      strInputFiles = strInputFiles & " """ & Arg & """"
  next
 '
  IndexFile= Left(WScript.Arguments(1),InStrRev(WScript.Arguments(1),"\")) & "index.jpg"
  Command = "montage -geometry 210x140+0+5 -tile 6x " & strInputfiles & " -quality 80% """ & IndexFile & """"
  wsh.run command, 7, true
该脚本首先将通过拖放传递给脚本的文件名连接起来。然后,它通过一些简单的字符串操作推导出同一文件夹中一个 JPEG 输出文件的名称。最后,Montage 被调用并带有一些适当的参数。对于较大的脚本,将文件名存储在数组中会很方便

  Dim FName()
  Dim wsh
  Set wsh = CreateObject("Wscript.Shell")
  '
  NArgs = WScript.Arguments.Count
  Redim FName(NArgs-1)
  FOR i = 0 TO NArgs - 1
    FName(i) = """" & WScript.Arguments(i) & """"
  NEXT
首先,我们通过 Dim FName() 定义一个动态数组,然后通过 Redim FName(NArgs-1) 对其进行重新调整大小。Montage 的命令行可能会变得非常长,因为在输入文件列表中,每个文件都由其完全限定的文件名命名。最大长度不是通常的 8192 个字符,而是由 ShellExecute 函数调用允许的最大长度决定的,对于 Windows XP 来说只有 2048 个字符。当目录名称很长时,这可能会造成麻烦。该错误无法由脚本处理,因为错误发生在脚本执行之前。一种可能的解决方案是将文件放置在具有较短名称的本地文件夹中。基于脚本的(部分)解决方案与批处理文件相同:如果只给出文件名,则会处理父目录中的所有图像。为了处理文件夹中的所有 GIF,我们可以执行以下操作

  Dim fs, folder
  Set fs = CreateObject("Scripting.FileSystemObject")
  If WScript.Arguments.Count <> 1 Then WScript.Quit(1)
  set Folder = fs.getFolder(fs.GetParentFoldername(WScript.Arguments(0)))
  FN=""
  FOR EACH file in folder.files
     If instr(file,"gif") <> 0 THEN FN = FN & File & vbLF
  NEXT
  MsgBox FN
在这里,我们使用 FileSystem 对象来确定父文件夹的名称。但是,文件扩展名的匹配是通过常规方式检查的,因为 Files 对象只提供 Type 属性而不是。通常,文件名需要按字母顺序排序,因为拖放或“发送到”会以随机顺序将它们传递给脚本。这可以通过冒泡排序来实现

  for i = 0 to NArgs - 1
    for j = i + 1 to NArgs - 1
      if FName(i) > FName(j) then
        Temp = FName(i)
        FName(i) = FName(j)
        FName(j) = Temp
      end if
    next
  next
[clip] 上述概念的更复杂应用在右侧显示:一组视频帧已通过 VBScript 和 ImageMagick 安装到两个平行的“胶片带”上。穿孔直观地表明帧的进展是从上到下,即按列,与通常的西方阅读模式从左到右,然后从上到下的顺序相反。执行此操作的整个脚本可以从归档文件 strip.zip 中下载。边注:每个帧右上角的红色时间代码是由 AVIsynth 脚本生成的。这些帧通过从 VirtualDub 中导出它们来转储。使用嵌入的时间代码,帧不一定需要在时间上等距,即可以根据需要在 Windows 资源管理器中选择并发送到脚本,该脚本放置在“发送到”文件夹中。

处理文本文件

在客户端计算机上使用脚本时,输入信息通常通过拖放或“发送到”提供,即基本上由脚本以预定义的方式处理的文件名。任何其他信息都必须在运行时通过用户交互提供,或者以文本文件的形式提供。基本上,我们有以下选择
  • 该脚本接受图像文件作为输入,并附带一个(可能可选的)文本文件,提供其他信息。
  • 该脚本接受一个用于输入的文本文件,其中列出了要处理的图像以及任何其他所需的信息。
在前面的情况下,适合将可选文本文件放置在与图像相同的目录中,并为其分配一个标准名称。然后,脚本可以从输入图像中推导出父目录名称,并在存在的情况下打开同一目录中的文本文件。上面提到的“胶片带”就是一个这种方法的示例:在脚本开头,我们可能会根据传递给脚本的图像数量定义一些标准的帧排序。但是,可能存在我们想要偏离标准帧排序的场景。因此,我们可以将一个名为 ordering.txt 的文本文件放置在帧目录中,如果存在,它将控制帧的排序

  strTxtFile="ordering.txt"
  PDir = fs.getParentFolderName(FName(0)) & "\"
  Wsh.CurrentDirectory = PDir

  If fs.FileExists(strTxtFile) then
    Set objFile = fs.OpenTextFile(strTxtFile, 1)
    bCtrlFile = True
    NCols = objFile.ReadLine
    objFile.close
  else
    bCtrlFile = False
  end if
[clip] 在 Fred Weinhaus 的网站上 演示 的图像到目标平面的透视映射中,可以找到第二个概念的一个有用应用。我们可以使用此概念将透视失真图像“蒙皮”到透视(大部分)正确的版本上,如右侧所示:在上半部分,左侧图像显示了在一次小事故现场拍摄的照片。右侧的照片是在稍后访问事故现场时从稍高位置拍摄的。在下半部分,事故照片(即平面道路表面)通过透视变换映射到目标照片上。(这样做的目的是为了可视化黑色汽车右前轮胎留下的微弱刹车痕迹的方向角。)为了执行此任务,用户必须在源图像中选择四个点,并在透视正确的图像中选择它们的对应目标点。我们可以通过手动操作来完成此操作,通过在图像查看器(如 IrfanView)中选择点来确定源图像和目标图像中的坐标,记下它们的坐标,并将它们提供给 Convert 命令行。但是,此繁琐的工作可以通过免费软件程序 WinMorph 来简化,该程序提供了一个方便的界面来执行此操作:从两张图片中选择一些源点及其相应的目标点。两张照片中的黄色折线连接了每张图片中选择的四个点。但是,变形算法本身不适合执行透视校正。(此算法的基本功能在 IM 网站使用部分的 Distorts 部分进行了说明。在 Fred Weinhaus 的 ShapeMorph 脚本中,可以找到其在变形方面的可用性演示。)WinMorph 将其信息存储在一个结构化文本文件中,该文件包含(除其他信息外)源和目标的文件名,以及源点和目标点的坐标。因此,我们可以从 WinMorph 文件中推导出 IM 透视失真所需的所有信息。您可以从文件 wmpr.zip 中下载所有参与此过程的文件和图像的副本。

管道

到目前为止,我们已经直接通过 Shell 对象的 Run 或 Exec 函数调用了 IM 的命令行工具(如 Convert、Identify、Montage)。但是,如果我们想使用 IM 的管道功能,即用前一个命令的输出馈送另一个命令,我们必须通过命令环境调用命令行工具。例如,如果我们想修剪上述脚本生成的索引打印的白色边框,代码需要是

  Dim wsh
  Set wsh = CreateObject("Wscript.Shell")
  '
  strInputFiles  = ""
  For EACH Arg IN WScript.Arguments
      strInputFiles = strInputFiles & " """ & Arg & """"
  next
 '
  IndexFile= Left(WScript.Arguments(1),InStrRev(WScript.Arguments(1),"\")) & "index.jpg"
  Command = "cmd /c montage -geometry 210x140+0+5 -tile 6x " & strInputfiles & " miff:- | magick - -trim """ & IndexFile & """"
  wsh.run command, 7, true
在这里,我们使用 /c 选项调用命令处理器 cmd,以便在完成后自动关闭命令框。出于调试目的,我们也可以使用 /k 选项调用它,这会保留命令框并允许我们读取可能的错误消息。

测试和调试 VBScripts

基本上,我们使用 VBScript 来构建 IM 命令行工具的参数列表,然后这些参数列表要么自己运行,要么在 DOS 框中运行。这意味着首先您应该确保
  • 命令行本身能够按照我们的预期执行
  • 命令行被脚本正确构建。
因此,首先,您应该在 DOS 框中测试命令行本身。在第一次测试脚本时,您不应该运行 IM 命令,而应该通过 MsgBox(strCommand) 在消息框中显示文本字符串,因为如果命令行本身是错误的,那么任何调试工具都无能为力。简单的消息框在调试脚本时也很有用,我从来没有真正觉得需要一个复杂的调试器。在考虑运行时测试时,您应该确保
  • IM 的命令行工具可以被正确访问
  • 用户已选择您希望她/他选择的项目,即多个文件(可能是特定类型),一个目录,一个文本文件等。
错误消息可以通过使用 MsgBox(...) 轻松地显示出来。

更多信息

很遗憾,除了这份文档之外,没有已知的教程专门介绍如何在 DOS 批处理文件中使用 ImageMagick 命令。网站 DOS "For" 命令帮助 页面对 "FOR" 命令的解释更详细。您可能还想参考 Bonzo's 批处理脚本 页面。