开发者社区> 问答> 正文

ImageMagick 魔咒:报错

ImageMagick 是一种开放源码工具套件,用于创建、编辑和转换位图图像。高级开发人员可以利用其丰富的功能来制作优质、专业的位图图像和其他艺术作品,以便在网站、市场 营销宣传册和其他任何需要某种艺术气息的地方使用这些作品。ImageMagick 使用 Apache 2.0 许可证提供许可,可在开放和专有应用程序中任意使用、复制、修改和分发。

英国科幻作家 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
猫咪 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 编辑器窗口
显示 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 阿姨的猫咪聚会邀请
显示为 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 程序的结果
展示运行 contrast 程序的结果的图片

MagickCore API

MagickCore API 是图像处理库与您的程序之间的低级接口。此接口主要供系统程序员使用,提供了在较高级别中不常见的基本功能:初始化环境、实例化对象、傅里叶变换计算等。

分发使用 ImageMagick 库的项目

ImageMagick 根据 Apache 2.0 开放源码许可分发,如果您要在自己的项目中使用它,有几条具体要求需要满足。简单来说,您必须在项目发布版中包含许可的完整版本,并明确指出归属 Apache Software Foundation 所有。参考资料 部分中提供了一个链接,可通过此链接获得 Apache 2.0 许可的完整细节。

结束语

在图像编辑器领域中,ImageMagick 套件独树一帜,提供了创建和编辑图像文件的强大程序员工具包。正如前面的 bash 脚本和 C 代码示例所展示的那样,这是一款综合的、有用的工具包,是您的图形相关项目的制胜法宝。

文章出处 IBM developerWorks

展开
收起
kun坤 2020-06-08 11:10:10 814 0
1 条回答
写回答
取消 提交回答
  • 这个还不错吧。我们在项目中有用到。

    2020-06-08 14:24:25
    赞同 展开评论 打赏
问答地址:
问答排行榜
最热
最新

相关电子书

更多
PHP安全开发_从白帽角度做安全 立即下载
PHP安全开发:从白帽角度做安全 立即下载
低代码开发师(初级)实战教程 立即下载