英国科幻作家 Arthur C. Clarke 曾经说到:“任何高尖技术初看起来都与魔法无异。” 虽然业内人士都在使用当今的先进技术,但不可否认的是,我们的工具有时看起来是多么神奇。假设您从不久之前的另外一个时代穿越而来,就会看到我们正在使用现代技术,念出一条又一条的魔咒,拍摄、传输、处理、最终打印出我们的朋友、家人、宠物、工作地点、甚至我们自己的图像。

ImageMagick 是一个有趣的名字,它代表了一个使您能够使用百余种格式创建、编辑、合成和转换数字图像的程序套件。其中的工具本身包含分立的程序和库,为您的图像处理工作提供了最丰富的选项,帮助您通过操作和编程方式完成这些任务。

本文主要关注使用 convertdisplay 命令行实用工具。ImageMagick 是一组出色的工具,阅读本文之后,这个套件将给您留下深刻的印象。

ImageMagick 是一种编辑器

一般而言,称为编辑器 的计算机程序设计用于使您能够轻松创建、修改和保存某种类型的数字数据。有多少具体的数字数据类型,就有多少种编辑器。目前有针对文档、程序代码和脚本的文本编辑器,最流行的例子就是 Vi 和 Emacs。针对音频数据的编辑器包括 Audacity 和 Wavosaur 等等。ImageMagick 为图形图像编辑提供了一种专业编辑器。

用于创建位图图像

与其他许多图像编辑器相似,ImageMagick 提供了一种交互图像编辑环境。但 ImageMagick 也提供了丰富的可编程应用程序编程接口 (API),供许多标准编程语言使用。ImageMagick 程序员社区提供了许多有用的程序,任您选择,其范围从编辑一直到您能想象到的任何功能。

在描述图像处理的功能时,图片胜过千言万语,ImageMagick 网站提供了大量图片,展示了每种图像处理功能的实际效果。(参考资料 部分中提供了一个链接,可从中获得有关图像处理的更多的信息。)

用于编辑位图图像

常用的图形图像格式超过一百种,因此,为了简化编辑现有图像的过程,ImageMagick 提供了 convert 程序,不仅可从一种格式转为另一种格式,还能将图像转为一种优化 ImageMagick 自己的交互式编辑器的形式。

用于将图像整合到项目之中

ImageMagick 的优点之一就是它的脚本编程功能,您可以编写自定义脚本,轻松将图像整合到特殊项目之中。我们的示例是使用潜在客户的个人数据(姓名、地址、电话号码等)自动自定义一套市场营销宣传图像。

为了查看此功能的实际效果,让我们来看我女儿和女婿的爱猫的一张普通图像,它的名字恰巧是 Merlin(图 1)。

图 1. Merlin

为了给图像加上美观的标题,我使用了下面这样的命令:

$ convert bMerlin.jpg -font Ubuntu-Bold-Italic   -pointsize 56 -fill blue -annotate +25+70   'Merlin, the Wizard of Cats' NewMerlin.jpg

注意: 如果您的系统中没有 Ubuntu-Bold-Italic 字体,请使用以下命令列出可用字体:

 $ convert -list font

图像处理完成后,您将得到 图 2 所示的图像。

图 2. 经过修改、添加了标题的图像

如您所见,ImageMagick 的魔咒一点都不难。只需要通过练习掌握工具的用法。制作 ImageMagick 的程序员(或者说是法师)在网站中制作了有关其工具的出色文档。建议您访问网站,加强您通过本文学习到的知识。(请参阅 参考资料 部分。)


回页首

ImageMagick 是一种图像处理库

有了这种强大的工具,程序员的选项库已经无法用 “全面” 来形容。利用熟悉的编程语言,您可以通过为各种语言设计的简单的 API 来整合 ImageMagick 的力量。从原始 ImageMagick 命令的简单 bash 脚本,到调用 C 和 Perl 等语言的 API 功能,ImageMagick 的编程能力使之从其他众多图形处理工具之中脱颖而出。

您可以选择使用交互式编辑器来调整一个图像,也可以全面调整多个图像。利用该套件中各种编辑工具的能力使之极有价值。


回页首

在流行的图像格式之间转换

数字图像有着百余种不同的图形文件格式。ImageMagick 使您能够处理如此之多的标准,驾驭复杂性。

ImageMagick 可在多种不同的操作系统之间迁移。它有 Windows?、UNIX? 和 Linux?、Mac OS X 以及 Apple iOS 的功能版本。本文主要关注 Ubuntu Linux 版本。要下载源代码或者您喜爱的系统的二进制文件版本,请参阅 参考资料 部分中提供的链接。

二进制还是源代码?

与许多的开放源码系统中一样,在获取程序时,您就面临着第一个选择:您是希望通过源代码进行编译,还是希望下载已经专门为您的系统编译好的二进制文件版本。两种方法各有优势,但我选择了通过源代码构建系统。

发布版还是自定义?

每个发布版(或者 “发行版”)都有着自己的添加预先构建的二进制文件的方法。要在源于 Debian Linux 的发行版(例如 Ubuntu)中安装 ImageMagick,您可以使用像 Synaptic Package Manager 这样的基于图形用户界面的程序包管理器,也可以使用命令行操作,例如:

 $ sudo apt-get install imagemagick

您还可以根据自己的喜好自定义 ImageMagick,例如修改从何处获取其配置文件或者某些特有的构建设置。为此,请在使用源代码构建 ImageMagick 时使用命令行选项开关。可以使用 configure 命令列出这些选项,如下所示:

 $ ./configure --help

在您的机器上进行构建时如果遇到问题,那么许多此类选项都是非常有用的。

使用源代码构建 ImageMagick

为基于 *nix 的计算机构建大多数开放源码程序都涉及到三条命令,ImageMagick 也不例外。标准命令如下:

$ ./configure
配置脚本的目标是为后续步骤创建一个自定义的 Makefile。它会有系统地运行一系列步骤,确定您的机器配置,随后向您报告某些关键部分缺失,例如必要的库等,或者报告一切正常并且已经成功创建了 Makefile。
$ make
上一个步骤中创建的 Makefile 将由 make 程序使用,用于构建构成 ImageMagick 套件的所有程序以及其相关文档。
$ sudo make install
最后一条命令会将程序、文档和相关数据文件复制到其永久位置,系统的所有用户都将到这个位置来寻找这些内容。通常情况下,这个位置是 /usr/local/bin 目录。

回页首

面向用户的图像处理

与其他图像编辑器相似,ImageMagick 也提供了一种用于编辑图像的交互式程序。调用此程序之后,您就可以访问菜单驱动式图像处理工具,进行图像编辑。

从零开始创建图像

使用 display 命令即可调用交互式 ImageMagick 编辑器,此命令可以附带相关文件名,也可以不带。其界面与其他许多绘图类程序相似,易于使用,而且是由菜单驱动的。

输入 display 命令。您应看到如 图 3 所示的窗口。

图 3. ImageMagick 编辑器窗口

单击窗口,随后单击菜单中的 File > New,开始创建您的位图图像。您将看到要求您输入图像几何结构的提示,随后是要求您确定图像背景色的提示。输入图像几何结构之后,您还会得到使用背景色渐变的选项。

命令行实用工具

ImageMagick 套件包含许多命令行实用工具。这里简要列出了几种:

  • animate:产生一系列图像的动画效果
  • compare:标注图像的差异
  • composite:创建叠加,将一个图像放置在另一个图像上方
  • conjure:执行使用 Magick 脚本语言编写的脚本
  • convert:将一种图像格式转为另一种
  • display:交互式图像编辑器
  • identify:描述图像文件
  • import:对于屏幕或窗口捕捉非常有用
  • mogrify:类似于 convert
  • montage:类似于 composite,具有多种图像和其他效果
  • stream:一种可脚本化工具,用于流式显示图像,每次一行

创建了画布之后,即可开始使用绘图工具进行修饰。单击 Image Edit > Draw。模式将发生更改,您将看到新菜单,此外画布的游标功能也会发生更改。此时,选择一种绘图工具,将您的想法展现在画布上。您可以保留绘图功能和图像的颜色部分,添加特殊效果,展现您的创意。

编辑图像

您可以通过多种方式编辑现有图像。只需输入 display image-name 命令,您就可以使用上述交互式编辑器,但也可以使用套件中的其他工具来处理图像。举例来说,convert 程序使您能够将图像文件转为适于不同环境另外一种常用图形格式。

为了介绍实现方法,我们将使用一个程序来生成一系列 “猫咪聚会” 邀请。这个程序采用 bash 脚本的形式,因此请启动 xterm,如下创建第一个文件:

 $ touch catcards $ chmod a+x catcards

创建脚本文件并使之可执行之后,下一个步骤就是打开您喜爱的程序编辑器(例如 Vi、Emacs),将 清单 1 所示的使用 bash 脚本的程序代码输入 catcards 文件。

清单 1. 生成邀请的 Bash 脚本
---#!/bin/bash# A "catcard" bash script for demonstrating ImageMagick# and generating invitations to a "cat party."# 20111115 by Bill Zimmerly.# Find the "seq" command, to generate sequence numbers.SEQ=`which seq`# Create the guests file. Comment this# out if "guests" is an external file.# (Important Note: "cat" in this script# has nothing to do with cats!)cat > guests << EOFGrandmaAunt LindaUncle DaveAunt RachaelUncle JoeUncle MykEOF# Read the guests into an array called "a."# (Note: IFS is the field separator value,# which in this case MUST be set for lines.)old_IFS=$IFSIFS=$'\n'a=($(cat guests))echo "Generating $((${#a[@]})) invitations to:"# Generate the invitations.for i in $($SEQ 0 $((${#a[@]} - 1)))do  # Use base=1 for human counting and  # show it on the console.  j=i  ((j += 1))  echo $j. ${a[$i]}  # Prepare the file name.  echo "Merlin"$j".jpg" > filename  # Prepare the invitational text.  echo ${a[$i]}", I love you and"       > text1  echo "I want you to come to my"       > text2  echo "cat party to scratch my belly." > text3  echo "Sincerely,"                     > text4  echo "Merlin"                         > text5  # Use ImageMagick's "convert" command  # to generate a new card.  convert bMerlin.jpg     -font Ubuntu-Bold-Italic     -pointsize 24 -fill blue     -annotate +25+40 $(cat text1)     -annotate +25+70 $(cat text2)     -annotate +25+100 $(cat text3)     -annotate +25+130 $(cat text4)     -annotate +25+160 $(cat text5)     $(cat filename)done# Restore the field separator value and clean up# temporary files.IFS=$old_IFSrm guestsrm filenamerm text1rm text2rm text3rm text4rm text5exit 0---

右键单击猫咪 Merlin 的原始照片(图 1),将其保存到 catcards 脚本所在的目录中。(catcards 脚本需要使用该图像文件作为数据。)

最后,运行脚本,列出所生成的文件,如 清单 2 所示。

清单 2. 调用脚本生成邀请
$ ./catcardsGenerating 6 invitations to:1. Grandma2. Aunt Linda3. Uncle Dave4. Aunt Rachael5. Uncle Joe6. Uncle Myk$ ls Merlin*

请注意,现在目录中共有六个新文件。使用 ImageMagick 的 display 命令获取各图像的显示顺序,请注意它们之间的区别:

 $ display Merlin1.jpg     .     .     .    Etc.

例如,图 4 显示了为 Rachael 阿姨生成的邀请的图像。

图 4. Rachael 阿姨的猫咪聚会邀请

您可以轻松修改这个程序,为您的所有客户生成销售宣传或自定义图片。


回页首

面向程序员的图像处理

程序员可以通过两种方法整合图像处理功能:通过 C 中的 MagickWand API 或 MagickCore API 整合。

使用 C 中的 MagickWand API

举例来说,ImageMagick 的制作者创建了一个示例程序,用于提高猫咪 Merlin 的图像的对比度(参考资料 部分中提供了有关这个程序的更多细节的链接)。清单 3 给出了代码。

清单 3. 更改图像对比度的示例 C 程序
---#include <stdio.h>#include <stdlib.h>#include <math.h>#include <wand/MagickWand.h>int main(int argc,char **argv){#define QuantumScale  ((MagickRealType) 1.0/(MagickRealType) QuantumRange)#define SigmoidalContrast(x)   (QuantumRange*(1.0/(1+exp(10.0*(0.5-QuantumScale*x)))-0.0066928509)*1.0092503)#define ThrowWandException(wand) {   char     *description;    ExceptionType     severity;    description=MagickGetException(wand,&severity);   (void) fprintf(stderr,"%s %s %lu %s\n",GetMagickModule(),description);   description=(char *) MagickRelinquishMemory(description);   exit(-1); }  MagickBooleanType    status;  MagickPixelPacket    pixel;  MagickWand    *contrast_wand,    *image_wand;  PixelIterator    *contrast_iterator,    *iterator;  PixelWand    **contrast_pixels,    **pixels;  register ssize_t    x;  size_t    width;  ssize_t    y;  if (argc != 3)    {      (void) fprintf(stdout,"Usage: %s image sigmoidal-image\n",argv[0]);      exit(0);    }  /*    Read an image.  */  MagickWandGenesis();  image_wand=NewMagickWand();  status=MagickReadImage(image_wand,argv[1]);  if (status == MagickFalse)    ThrowWandException(image_wand);  contrast_wand=CloneMagickWand(image_wand);  /*    Sigmoidal non-linearity contrast control.  */  iterator=NewPixelIterator(image_wand);  contrast_iterator=NewPixelIterator(contrast_wand);  if ((iterator == (PixelIterator *) NULL) ||      (contrast_iterator == (PixelIterator *) NULL))    ThrowWandException(image_wand);  for (y=0; y < (ssize_t) MagickGetImageHeight(image_wand); y++)  {    pixels=PixelGetNextIteratorRow(iterator,&width);    contrast_pixels=PixelGetNextIteratorRow(contrast_iterator,&width);    if ((pixels == (PixelWand **) NULL) ||        (contrast_pixels == (PixelWand **) NULL))      break;    for (x=0; x < (ssize_t) width; x++)    {      PixelGetMagickColor(pixels[x],&pixel);      pixel.red=SigmoidalContrast(pixel.red);      pixel.green=SigmoidalContrast(pixel.green);      pixel.blue=SigmoidalContrast(pixel.blue);      pixel.index=SigmoidalContrast(pixel.index);      PixelSetMagickColor(contrast_pixels[x],&pixel);    }    (void) PixelSyncIterator(contrast_iterator);  }  if (y < (ssize_t) MagickGetImageHeight(image_wand))    ThrowWandException(image_wand);  contrast_iterator=DestroyPixelIterator(contrast_iterator);  iterator=DestroyPixelIterator(iterator);  image_wand=DestroyMagickWand(image_wand);  /*    Write the image then destroy it.  */  status=MagickWriteImages(contrast_wand,argv[2],MagickTrue);  if (status == MagickFalse)    ThrowWandException(image_wand);  contrast_wand=DestroyMagickWand(contrast_wand);  MagickWandTerminus();  return(0);}---

如果将这段源代码放在一个名为 contrast.c 的文件中,随后即可使用以下命令来构建 contrast 程序:

$ cc `MagickWand-config      --cflags --cppflags`      -O2 -o wand wand.c      `MagickWand-config --ldflags --libs`

contrast 命令构建完成后,您就可以像下面这样使用它来提高猫咪 Merlin 的照片的对比度:

 $ ./contrast bMerlin.jpg MerlinX.jpg

图 5 中的图像与上面的猫咪 Merlin 图像对比。

图 5. 运行 contrast 程序的结果