ImageMagick 通过命令行处理图形
理大量文件的能力,无论是使用命令行还是脚本。程序员 Michael Still 介绍了 ImageMagick 套件,这是一个用于以多种格式对图像进行缩放大小、旋转、转换和其它操作的 Linux 工具箱,无论图像的数量是一个还是上百个,它都可以一次处理掉。
本文展示了 如何使用命令行工具执行图像操作。这种任务对我而言相当常见,因为我拥有几部数码相机,并且现在管理着一个拥有几千张精彩照片的资料库。对于经常需要对大 量图像进行批处理的 Web 开发人员和管理员而言,命令行工具是特别具有吸引力的选择,因为开发人员可以将它们合并成脚本。但即使您只想执行一两次操作,选择命令行也可以节省时间。
本文中讨论的命令行工具是优秀的 ImageMagick 套件的一部分,该套件是随 Red Hat Linux 一起提供的,并可免费在线下载(请参阅 参考资料)。也可以通过 C、C++、Perl、Python、Java 和其它几种语言使用 ImageMagick,Linux 程序员会喜欢这样做。
请注意,有许多种方法可以完成本文中所讨论的任务。我讨论了我所使用的方法,它对我确实很有效。这并不意味着除此之外的其它工具就很差劲;仅仅表示我对于现在所使用的工具很满意。
本文采用了以具体问题作为示例进行讨论这种形式,但其思想应该也适用于其它问题领域。
生成缩略图
我对照片集所执行的第一个操作是生成缩略图。我还想减少图像的大小,以适用于网站版本因为许多人实际上并不想看到我儿子的 1920 x 1440 像素的照片。
|
我使用 convert
工具,它是 ImageMagick 套件的一部分。 convert
确实很酷。除了图像缩放,它还具有平滑处理、均衡图像组、模糊化、在图像格式间进行转换、修剪、去斑滤镜、抖动、绘制边界、翻转、连接、重新采样、调整大小以及许多功能。查看联机帮助页以获取关于它的各种命令行选项的更多信息。本文稍后还讨论了 convert
所提供的许多在视觉上比较有趣的效果。
让我们假定我希望为这幅非常美丽的玫瑰图像制作缩略图:
图 1. 玫瑰的照片
要用 convert
调整图像的大小,只要使用 -sample
命令行选项。例如,让我们假定我希望得到 80 x 40 像素的缩略图。则命令行将是:
# convert -sample 80x40 input.jpg output.jpg |
这生成了如下的缩略图:
图 2. 生成缩略图的第一次尝试
ImageMagick 会自动地考虑在缩放图像大小时图像的两条邻边所产生的比例。这意味着新的图像的高宽比与原图相同。在上面的示例中,这意味着缩放后的图像实际上是 53 x 40 像素,而不是所要求的 80 x 40 像素。指定输出图像大小的另一种方法是使用百分数。如果您不能确定输入图像的大小,或者并不是刻意地要得到确切大小的新图像,那么这种方法比较方便。以下 是关于如何使用百分数的示例:
# convert -sample 25%x25% input.jpg output.jpg |
现在,我们得到了如下所示的缩略图:
图 3. 生成缩略图的第二次尝试
使用该命令,您可以在某个目录中生成图像的缩略图。虽然本文并不是关于 shell 脚本编制的,但我会迅速地向您展示一个示例,以说明如何生成当前目录中每个 JPEG 的缩略图:
清单 1. 为当前目录中的所有 JPEG 生成缩略图
for img in `ls *.jpg` do convert -sample 25%x25% $img thumb-$img done |
这会生成一系列大小为实际图像 25% 的缩略图,其文件名称是在 JPEG 文件名的前面加上 thumb-前缀。
|
获取关于图像文件的信息
另一个常见任务是确定图像文件的尺寸(dimension)。例如,您可能需要知道前一个示例中的缩略图有多大。
许多图像处理库提供了用于此用途的优秀工具。例如,libtiff(TIFF 库,我先前曾写过有关这个库的文章;请参阅 参考资料)提供了 tiffinfo
, tiffinfo
显示了关于 TIFF 文件的下列种类的信息:
# tiffinfo sample.tif |
清单 2. tiffinfo 的样本输出
TIFF Directory at offset 0x146 Image Width: 352 Image Length: 288 Bits/Sample: 8 Compression Scheme: Deflate Photometric Interpretation: RGB color Samples/Pixel: 3 Planar Configuration: single image plane |
这并不是一个关于如何使用 tiffinfo
的详尽示例,但您可以看到它返回了诸如图像大小、像素深度(每个样本的位数和每个像素的样本数的组合)以及所用的压缩方案之类的有用信息。
类似地,有一个返回 PNG 文件的类似信息的 pnginfo
命令:
# pnginfo sample.png |
清单 3. pnginfo 的样本输出
sample.png... Image Width: 640 Image Length: 480 Bitdepth (Bits/Sample): 8 Channels (Samples/Pixel): 3 Pixel depth (Pixel Depth): 24 Colour Type (Photometric Interpretation): RGB Image filter: Single row per byte filter Interlacing: No interlacing Compression Scheme: Deflate method 8, 32k window Resolution: 0, 0 (unit unknown) FillOrder: msb-to-lsb Byte order: Network (Big Endian) Number of text strings: 0 of 0 |
我不清楚是否存在用于其它格式(诸如 BMP、GIF 和 JPEG)功能相当的单个工具。但是,ImageMagick 又一次帮了我们的忙,这次是使用名为 identify
的工具。
# identify -verbose sample.png |
清单 4. identify 的样本输出
Image: sample.png Format: PNG (Portable Network Graphics) Geometry: 640x480 Class: DirectClass Type: true color Depth: 8 bits-per-pixel component Colors: 142360 Filesize: 555.6k Interlace: None Background Color: grey100 Border Color: #DFDFDF Matte Color: grey74 Dispose: Undefined Iterations: 0 Compression: Zip signature: 361fe70ae623ef6f1fca44e0d29d157c2d701039fcf0f8625862925d881e13a4 Tainted: False User Time: 0.190u Elapsed Time: 0:01 |
您可以看到 identify
显示了一串关于图像文件的有用信息,如以像素为单位的图像大小、图像的色深以及图像的格式。
|
identify
还有 -format
命令行标志,它允许您仅指定想要输出的信息。例如,如果您只对图像尺寸感兴趣,则可以使用如下命令:
# identify -format "%wx%h" sample.png |
输出类似于:
640x480 |
此处, %w
表示图像宽度,而 %h
表示图像高度。有关可以与该选项一起使用的格式化字符的更多信息,请查看 identify
联机帮助页。
|
旋转图像
另一种经常需要用到的图像操作是旋转图像。例如,我用数码相机所拍摄的许多照片都旋转了九十度,因为我是把相机竖过来拍摄它们的。相机不会为我旋转这些照片,因此我编写了一个脚本,以便在从相机下载这些图像之后完成旋转任务。
例如,这是我在最近去塔斯马尼亚岛的亚瑟港旅游时拍摄的一幅照片:
图 4. 横卧的亚瑟港
为了旋转该照片,我们再次求助于 convert
命令:
# convert -rotate 90 input.jpg output.jpg |
该命令生成了如下所示的图像:
图 5. 亚瑟港
请注意 -rotate
选项的参数是将图像向右旋转的度数。要向左旋转,请使用负数。
|
更改图像的格式
convert
命令还能够转换图像文件的格式。这包括图像格式之间的转换(如将 JPEG 图像转换成 PNG)以及从颜色到灰度之间的转换、抖动和类似操作。
convert
根据命令行中给定的文件扩展名来了解输入和输出的图像格式分别是什么。因此,要将 JPEG 转换成 PNG,使用如下所示的命令行:
# convert input.jpg output.png
在我撰写本文时,ImageMagick 支持 89 种图像格式。查看 ImageMagick 网站(请参阅 参考资料)以获取更多信息。
|
向图像添加文本注释
有时您需要向图像添加文本注释。例如,假设您的公司拥有标准的名片图像,并希望在将名片发送到打印机之前将每个雇员的详细信息都添加到名片上面。另一个示例是为通过您网站上的在线课程的用户生成表示证书(presentation certificate)。
让我们假定您从这幅图入手:
图 6. 2002 年芙萝莉雅蝶园艺博览会(FLORIADE 2002)照片
您可以使用下列命令行,为该图注释一些标识信息:
# convert -font helvetica -fill white -pointsize 36 \ -draw 'text 10,50 "Floriade 2002, Canberra, Australia"' \ floriade.jpg comment.jpg |
这里是结果:
图 7. 加注释的 2002 年芙萝莉雅蝶园艺博览会照片
迄今为止,这是我在本文中所展示的最复杂的 convert
命令行了,因此我将花些时间来解释它。
-font helvetica
将注释的字体设置为 Helvetica。也可以在此处指定字体文件的路径。这个示例给图像添加了标记,这样未经许可其它网站就不能再使用该图像了,但它是使用位于非标准位置的字体来完成该任务的:
# convert -font fonts/1900805.ttf -fill white -pointsize 36 \
-draw 'text 10,475 "stillhq.com"' \
floriade.jpg stillhq.jpg
以下是结果:
图 8. 带标记的图像
-fill white
用白色而不是标准的黑色来填充字母。
-pointsize 36
以点为单位指定字母的大小。一英寸等于 72 点。
-draw 'text 10,50 "..."'
是一组绘图命令,在本例中是移动到位置 10, 50,然后绘制出双引号中的文本。使用单引号是因为如果需要绘制多个字,则绘图命令中需要使用双引号,而您不能在双引号中再用双引号。
|
其它更富艺术性的转换
convert
还实现了一系列相当艺术性的转换。我将在此处演示一些在视觉上比较有趣的转换。如果您对此感兴趣,应该查看 ImageMagick 的联机帮助页和网站以获取更多信息。这是我将用于该演示的输入图像:
图 9. 乌奴奴(Uluru)夕照
这张乌奴奴(以前称为艾尔斯岩(Ayers Rock))的照片是在日落时分照的。
炭笔
炭笔效果模拟出该图像的素描画。
# convert -charcoal 2 input.jpg output.jpg |
其结果如下所示:
图 10. 应用炭笔效果之后的乌奴奴夕照
增加 -charcoal
选项的参数的数值会增加应用于该图像的“炭笔”数量,但也会延缓生成图像的过程。下面是一个使用稍多炭笔的示例。
# convert -charcoal 10 input.jpg output.jpg |
它产生了如下结果:
图 11. 应用更多炭笔效果之后的乌奴奴夕照
如果您真的想近乎疯狂地使用大量炭笔:
# convert -charcoal 200 input.jpg output.jpg |
您会得到这样的结果:
图 12. 应用过量炭笔效果之后的乌奴奴夕照
|
着色
着色是将每个像素的颜色与指定颜色混合的过程。该效果的参数就是要用来混合的颜色。可以用一个百分数(它将分别用于红色、绿色和蓝色),也可以用三个百分数来指定这个参数。也可以提供三个实际值中的一个。
# convert -colorize 255 input.jpg output.jpg |
以下是着色之后的乌奴奴:
图 13. 应用着色效果之后的乌奴奴夕照
内爆(Implode)
内爆效果模拟了您图像的中心被吸入虚拟黑洞的情形。所用的参数是您所期望的内爆效果量。
# convert -implode 4 input.jpg output.jpg |
内爆的乌奴奴如下所示:
图 14. 内爆之后的乌奴奴夕照
|
曝光
曝光是在相片冲洗过程中把底片暴露在光线中所发生的效果。这里,输入参数是应用于该效果的亮度,可以指定为绝对值,也可以是可用于像素的最大可能值的百分数。如果像素超过阈值,则对它求反。
# convert -solarize 42 input.jpg output.jpg |
在曝光之后,我们的图像如下所示:
图 15. 曝光之后的乌奴奴夕照
发散
spread
在图像之内以随机的数量移动像素。所用的参数是被移到新选择的位置的像素区域的大小。所以它指定了输出和输入的相似程度:
# convert -spread 5 input.jpg output.jpg |
再次使用乌奴奴,这次是发散之后的情形:
图 16. 发散之后的乌奴奴夕照
|
在一次 ImageMagick 调用中执行多条命令
您已经看到了将命令与注释示例联系起来的示例。但是,可以将本文中提到的任意 ImageMagick 命令链接起来。例如,也许我们希望制作某图像的缩略图,然后对它应用发散。在发散发生之后,我们将应用炭笔效果:
# convert -sample 25%x25% -spread 4 \ -charcoal 4 input.jpg output.jpg |
这会产生:
图 17. 应用了一系列效果之后的乌奴奴
|
图像操作技巧
在迫不及待地动手修改您所拥有的每一幅图像之前,您应该记住一些关于图像操作的事情。首先,您应该考虑一下打算长期使用什么图像格式,免得最终有了一大堆某种格式的图像之后再来后悔就晚了。这一点特别容易做到,因为正如本文先前所讨论的,您可以使用 convert
来更改图像的格式。
JPEG 压缩对于诸如照片之类的大图像很适合。但其压缩通常是 有损的(换句话说,在压缩过程中会丢弃图像数据)。这使得 JPEG 非常不适于压缩需要保持字迹清晰的文本。另一件需要牢记的事情是:损失是累积的。
如果您不希望在一系列操作之后产生的累积损失会影响到彩色图像的图像品质,通常 PNG 是个不错的选择。
有关该主题的更多信息,请参阅我所著的关于用 libtiff 处理彩色图像的文章“ Graphics programming with libtiff,Part 2”(请参阅下面的 参考资料中的链接)。
您 还应该记住本文中所展示的大多数操作是单向的。例如,如果您将图像缩小了,则图像数据就丢失了。如果此后您再放大该图像,则输出将很粗糙。例如,让我们拍 一幅照片,制作缩略图,然后再扩大该图像。为了节省一些篇幅,在此,我将只包括最初和最后的图像,而省略中间的缩略图。
图 18. 凯恩斯瀑布
现在,我们将把缩小和放大操作链接在一起:
# convert -sample 10% -sample 1000% input.jpg output.jpg |
这产生了如下所示的图像:
图 19. 斑驳的瀑布
很难在最终的图像中看出瀑布来,尽管分散您的眼光似乎有些帮助。
结束语
在本文中我们讨论了一些有趣的事情,ImageMagick 可以完成这些任务以满足您的命令行图像处理需求。这里所描述的工具并不能解决所有问题,有时您会需要定制代码段,但是通用的命令行图像处理工具通常可以大幅度地减轻工作负担。