英国科幻作家 Arthur C. Clarke 曾经说到:“任何高尖技术初看起来都与魔法无异。” 虽然业内人士都在使用当今的先进技术,但不可否认的是,我们的工具有时看起来是多么神奇。假设您从不久之前的另外一个时代穿越而来,就会看到我们正在使用现代技术,念出一条又一条的魔咒,拍摄、传输、处理、最终打印出我们的朋友、家人、宠物、工作地点、甚至我们自己的图像。
ImageMagick 是一个有趣的名字,它代表了一个使您能够使用百余种格式创建、编辑、合成和转换数字图像的程序套件。其中的工具本身包含分立的程序和库,为您的图像处理工作提供了最丰富的选项,帮助您通过操作和编程方式完成这些任务。
本文主要关注使用 convert
和 display
命令行实用工具。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,开始创建您的位图图像。您将看到要求您输入图像几何结构的提示,随后是要求您确定图像背景色的提示。输入图像几何结构之后,您还会得到使用背景色渐变的选项。
创建了画布之后,即可开始使用绘图工具进行修饰。单击 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 << EOF Grandma Aunt Linda Uncle Dave Aunt Rachael Uncle Joe Uncle Myk EOF # 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=$IFS IFS=$'\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_IFS rm guests rm filename rm text1 rm text2 rm text3 rm text4 rm text5 exit 0 --- |
右键单击猫咪 Merlin 的原始照片(图 1),将其保存到 catcards 脚本所在的目录中。(catcards 脚本需要使用该图像文件作为数据。)
最后,运行脚本,列出所生成的文件,如 清单 2 所示。
清单 2. 调用脚本生成邀请
$ ./catcards Generating 6 invitations to: 1. Grandma 2. Aunt Linda 3. Uncle Dave 4. Aunt Rachael 5. Uncle Joe 6. 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 程序的结果
MagickCore API
MagickCore API 是图像处理库与您的程序之间的低级接口。此接口主要供系统程序员使用,提供了在较高级别中不常见的基本功能:初始化环境、实例化对象、傅里叶变换计算等。
回页首
分发使用 ImageMagick 库的项目
ImageMagick 根据 Apache 2.0 开放源码许可分发,如果您要在自己的项目中使用它,有几条具体要求需要满足。简单来说,您必须在项目发布版中包含许可的完整版本,并明确指出归属 Apache Software Foundation 所有。参考资料 部分中提供了一个链接,可通过此链接获得 Apache 2.0 许可的完整细节。
回页首
结束语
在图像编辑器领域中,ImageMagick 套件独树一帜,提供了创建和编辑图像文件的强大程序员工具包。正如前面的 bash 脚本和 C
代码示例所展示的那样,这是一款综合的、有用的工具包,是您的图形相关项目的制胜法宝。
参考资料
学习
- 进一步了解 ImageMagick。
- 通过 ImageMagick 的 图像处理示例 进一步了解图像处理。
- 在分发您的 ImageMagick 项目之前,请务必确保已经理解 Apache 2.0 许可 条款。
- 请访问 Safari 书店 电子参考信息库,查找特定技术资源。
- 在 Twitter 上关注 developerWorks。
- 随时关注 developerWorks 技术活动和网络广播。
- 访问 developerWorks Open source 专区获得丰富的 how-to 信息、工具和项目更新以及最受欢迎的文章和教程,帮助您用开放源码技术进行开发,并将它们与 IBM 产品结合使用。
获得产品和技术
- 可通过 二进制文件 或 源代码 形式下载 ImageMagick。
- 可以在描述 MagickWand C API 的页面中找到 contrast.c 程序。
- 利用 IBM 产品评估试用版软件 在您的下一个开放源码开发项目中取得创新,可以通过下载获得这些试用软件。
- 进一步了解并 下载 SourceForge 提供的 Audacity。
讨论
- 加入 developerWorks 中文社区,developerWorks 社区是一个面向全球 IT 专业人员,可以提供博客、书签、wiki、群组、联系、共享和协作等社区功能的专业社交网络社区。
- 加入 IBM 软件下载与技术交流群组,参与在线交流。
关于作者