IBM®
跳转到主要内容
    中国 [选择]    使用条款
 
 
Select a scope: Search for:    
    首页    产品    服务与解决方案     支持与下载    个性化服务    
跳转到主要内容

developerWorks 中国  >  Linux  >

Linux 技巧: 从命令行创建像素标尺

如何使用 Bash 脚本、shell 算法和 ImageMagick 在图像上绘制线条和文本

developerWorks
文档选项

未显示需要 JavaScript 的文档选项

样例代码

英文原文

英文原文


级别: 中级

Ian Shields, 高级程序员, IBM

2009 年 8 月 24 日

学习如何使用 Linux® 命令行和一些基本的 Bash 脚本编写技巧,以便使用 ImageMagick 在图像上绘制线条和文本,并同时创建一个像素标尺。

有时,我需要在一张图像或一块空白画布上绘制几根线条和一些文本。就在最近,我需要将一个像素标尺的一张简单图像包含在我的一篇 developerWorks 文章中。我希望这张图像宽 572 像素,以满足目前 developerWorks 文章图像的推荐标准,就像在 “developerWorks 投稿图片处理” 中描述的一样。Linux 和 Windows 有许多屏幕像素标尺可用(见 参考资料),但我只想要一个简单的 GIF、JPEG 或 PNG 图像。本文介绍如何使用 Bash 脚本、shell 算法和 ImageMagick 创建一个像素标尺。

制作一张画布

艺术家需要的首要装备就是一张画布,因此让我们使用 XC 假想类型在 ImageMagick 中创建一张画布。我们还需要一种颜色,可以是 ImageMagick 中的众多已命名颜色中的一种,也可以是一种自定义颜色。(从 参考资料 获取到 ImageMagick 文档的链接,这些文档包含一个假想类型和颜色名称的完整列表)。清单 1 展示如何使用 convert 命令制作一张浅蓝色的 572x100 画布。(convert 命令通常用于转换到一种不同的图像格式,或者以另一种方式改变一张图像)。


清单 1. 创建一张画布
convert -size 572x100 xc:lightblue ruler1.gif
            

图 1 展示了我们的新画布。


图 1. 用于标尺的天蓝色 572x100 像素画布
用于标尺的天蓝色 572x100 像素画布




回页首


添加几根线条

现在我们有了一张画布,让我们绘制一些标记来显示沿着标尺的不同点。72 ppi(像素/每英寸)是基于 Web 的图形的标准,因此让我们将我们的第一个标记设置为 72 像素并使它从图像底部扩展 30 像素。另外,让我们用黑色填充这个线条,并为其指定两个端点。


清单 2. 将一根线条添加到这张画布
convert  -fill black -draw "line 72,70 72,100" ruler1.gif ruler2.gif 
            

图 2 展示了我们的新图像,图像上面绘制了一条线。


图 2. 带有一根垂直线的画布,线条距画布左边 72 像素
带有一根垂直线的画布,线条距画布左边 72 像素

在这个标尺上绘制每个线条都重复上述操作,这很乏味,因此让我们使用 seq 命令来生成一个相距 72 像素的水平偏移的列表,同时使用一个 for 循环来在这个标尺上绘制主线条(如清单 3 所示)。


清单 3. 在画布上每隔 72 像素添加一条线
convert  -fill black -draw "$(for n in $(seq 0 72 572) ;\
 do echo line $n,70 $n,100 ; done)" ruler1.gif ruler3.gif 
            

注意,我们使用了两个命令替代来为绘制操作生成单独的线条规范。我们还在 0 位置 —— 左侧边缘 —— 放置了一个标记。现在,图 3 看起来更像一个标尺了。


图 3. 从左边缘起每 72 像素一条垂直线的画布
从左边缘起每 72 像素一条垂直线的画布




回页首


对更多线条编写脚本

此时,我们的命令行变得有点复杂了,但是我们的标尺上仍然只有主要标记。现在是时候编写脚本了。在清单 4 中,我们使用 shell 算法和 for 循环在已经有的标记的中间放置一个 20 像素的标记,并在这些较长的标记之间每隔 6 像素放置一些 10 像素的标记。为完成本文的任务,我们将调用脚本 buildruler.sh 并将它放置在我们的工作目录中。


清单 4. 将一个完整的标记集添加到这个标尺
#!/bin/bash
# Take user parameters or set defaults
rulername="$1"
rulerlength="$2"
rulername="${rulername:=ruler.gif}"
rulerlength="${rulerlength:=572}"
drawstring=""
#Build the line definitions for the ruler marks
for x1 in `seq 0 72 $rulerlength`; do
  drawstring="$drawstring line $x1,70 $x1,100"
  for x2 in 0 36; do
    (( offset = $x1 + $x2 ))
    drawstring="$drawstring line $offset,80 $offset,100"
    for x3 in `seq 6 6 30`; do
      (( offset2 = $offset + $x3 ))
      drawstring="$drawstring line $offset2,90 $offset2,100"
    done
  done
done
#Create the ruler
convert -size "${rulerlength}x100" xc:lightblue -fill black \
 -draw "$drawstring" "$rulername"
            

注意,我们添加了两个参数,以便用户可以更改标尺的名称并指定其长度。现在,我们的标尺看起来就像图 4 一样。这个标尺是使用命令 ./buildruler.sh ruler4.gif 生成的。


图 4. 带有完整的标记集的标尺,标记之间相距 6 像素
带有完整的标记集的标尺,标记之间相距 6 像素




回页首


添加文本

引用

脚本编写的一个要点是要知道何时需要引号,何时不需要,以及如何将引用的字符串作为参数传递。特别需要注意这些脚本中使用的引号。

现在,让我们将标尺上的较大的标记的标签设置为数字 0、72、144...,依次类推。我们需要告知 ImageMagick 使用哪种字体,字体的大小和颜色是什么。显然,数字 0 应该在标尺的左边缘位置,但是如果我们将那些两位数和三位数的数字放置在那些 72 像素点,它们看起来会不平衡。为了更正这个问题,我们需要将它们向左侧稍微偏移一些,使它们正好位于标记的正上方。放大的脚本如清单 5 所示。


清单 5. 向标尺添加标签
#!/bin/bash
# Take user parameters or set defaults
rulername="$1"
rulerlength="$2"
rulername="${rulername:=ruler.gif}"
rulerlength="${rulerlength:=572}"
drawstring=""
#Build the line definitions for the ruler marks
for x1 in `seq 0 72 $rulerlength`; do
  drawstring="$drawstring line $x1,70 $x1,100"
  for x2 in 0 36; do
    (( offset = $x1 + $x2 ))
    drawstring="$drawstring line $offset,80 $offset,100"
    for x3 in `seq 6 6 30`; do
      (( offset2 = $offset + $x3 ))
      drawstring="$drawstring line $offset2,90 $offset2,100"
    done
  done
done
#Add the labels
labelfont="-fill black -font helvetica -pointsize 24  -draw"
labelstring="text 0,60 \"0\" "
for x1 in 72; do
  (( offset = $x1 - 12 ))
  labelstring="$labelstring text $offset,60 \"$x1\" "
done
for x1 in `seq 144 72 $rulerlength`; do
  (( offset = $x1 - 18 ))
  labelstring="$labelstring text $offset,60 \"$x1\" "
done

#Create the ruler
convert -size "${rulerlength}x100" xc:lightblue -fill black \
 -draw "$drawstring" $labelfont "$labelstring" "$rulername"

现在,我们的标尺如图 5 所示。


图 5. 带有完整标记集和标签的标尺
带有一个完整标记集和标签的标尺




回页首


定位文本

那么,我们如何知道文本应该偏移多少,应该放置在距离顶部多远的位置?想当然的答案可能是:试验和猜测,但这不是一个好办法。

为了更好地放置文本,我们需要知道包含文本的方框有多大。但这取决于字体,字体是否成比例,以及其他一些不容易计算的因素。幸运的是,我们可以以同样的方法使用 ImageMagick 创建一个画布,我们还能创建一个 label。我们将创建一个标题 Pixel Ruler 并将它设置为 36 点的字体。这个标签作为一个图像创建,我们可以使用 identify 命令来确定其大小(如清单 6 所示)。


清单 6. 创建一个标题并测量其大小
$ convert -fill NavyBlue -background Lavender -font helvetica -pointsize 36 \
 label:"Pixel Ruler" label.gif
$ identify "label.gif"
label.gif GIF 175x36 175x36+0+0 8-bit PseudoClass 256c 1.98kb 

我将文本设置为海军蓝并添加一个淡紫色的背景颜色,以便这个图像从这个页面背景中凸显出来。但是,不管是否使用背景颜色,得到的图像的大小都相同。生成的标签图像如图 6 所示。


图 6. 标签图像
标签图像

比编写一个文件甚至更好的是,我们可以使用 ImageMagick INFO 类确定关于文本的更多信息,比如基线的位置。我们将文本写到一张足够大的画布上,然后沿着文本的边缘修剪画布(如清单 7 所示)。


清单 7. 使用 INFO 图像类确定字体信息
$ convert -size 572x100 xc:lightblue -font helvetica -pointsize 36 \
  -fill black -undercolor lavender  -annotate +40+50 'Pixel Ruler' -trim info:
xc:lightblue XC 174x36 572x100+40+23 16-bit DirectClass

注解的文本从一个点开始,该点的 y 坐标轴代表文本的基线。上面的输出显示,文本填充到一个大小为 174x36 像素的方框中。这个结果和此前的结果之间存在 1 个像素的差距,但这并不重要。方框的顶部距离原始画布的顶部 23 像素。由于基线位于原始画布顶端下方 50 像素处,这意味着基线实际上距离文本顶端 27 像素(50 减去 23),为下行线留出了 9 个像素。图 7 将一个图像放置在未修剪的画布上来说明这种关系。


图 7. 标签度量
标签度量

现在我们已经知道了这个标签的尺寸,让我们将基线放置在距离图像顶部 40 像素的位置并使其水平居中。我们的最终脚本如清单 8 所示并可供 下载


清单 8. 最终脚本
#!/bin/bash
# Take user parameters or set defaults
rulername="$1"
rulerlength="$2"
rulername="${rulername:=ruler.gif}"
rulerlength="${rulerlength:=572}"
drawstring=""
#Build the line definitions for the ruler marks
for x1 in `seq 0 72 $rulerlength`; do
  drawstring="$drawstring line $x1,70 $x1,100"
  for x2 in 0 36; do
    (( offset = $x1 + $x2 ))
    drawstring="$drawstring line $offset,80 $offset,100"
    for x3 in `seq 6 6 30`; do
      (( offset2 = $offset + $x3 ))
      drawstring="$drawstring line $offset2,90 $offset2,100"
    done
  done
done
#Add the labels
labelfont="-fill black -font helvetica -pointsize 24  -draw"
labelstring="text 0,60 '0' "
for x3 in 72; do
  offset3=$(($x3 - 12 ))
  labelstring="$labelstring text $offset3,60 '$x3' "
done
for x4 in `seq 144 72 $rulerlength`; do
  offset4=$(( $x4 - 18 ))
  labelstring="$labelstring text $offset4,60 '$x4' "
done
#Add a title
titledimension=$(convert -size 572x100 xc:lightblue -font helvetica \
  -pointsize 36  -fill black -undercolor lavender\
  -annotate +40+50 'Pixel Ruler' -trim info: | awk ' {print $3 } ')
titlewidth=${titledimension%x*}
titlefont="-fill NavyBlue -font helvetica -pointsize 36"  
titlepos=$(( (($rulerlength - $titlewidth)) / 2 ))
titletext="text $titlepos,30 'Pixel Ruler' "
#Create the ruler
convert -size "${rulerlength}x100" xc:lightblue \
 -fill black  -draw "$drawstring" $labelfont "$labelstring" \
 $titlefont -draw "$titletext" "$rulername"

最终的标尺如图 8 所示。


图 8. 带有标题的最终标尺
带有标题的最终标尺

对于那些没有艺术技巧的人来说,这算得上一种不错的方法。





回页首


一个实践示例

如果图像被缩进 — 比如在列表中 — developerWorks 上允许的最大宽度就相应减小。因此,您可以使用这些方便的标尺来检查随文章一起提交的图像。





回页首


结束语

通过本文的简单实践,您看到了使用 ImageMagick 通过脚本编写包含线条和文本的图像的一些基本技巧。您将在我们的文章 “通过命令行处理图形 -- 使用 ImageMagick 进行翻转、缩放大小、旋转以及更多操作” 和 “通过命令行进一步处理图形 -- 在 Linux 上使用 ImageMagick 的提示与技巧” 中发现更多技巧。您也可以在 ImageMagick 的主页上找到更多示例,从 参考资料 部分获取相关链接。

本文中的脚本并不是无懈可击的。例如,对于长度是不是对一个有意义的标尺足够大的正数值,或者指定的文件是不是 ImageMagick 的有效图像文件类型,我们没有进行验证。您可能还会发现其他问题。例如,标尺标签可能像图 10 中那样被截断,这是我们的脚本没有考虑的一个问题。

您还可以任意添加多个参数,例如,尝试添加颜色或标尺高度参数。

尽管这个技巧主要关注在 Linux 上使用 ImageMagick,ImageMagick 也可用于 Windows 等其他平台上。尝试在您喜欢的平台上使用脚本工具实践这些技巧。






回页首


下载

描述名字大小下载方法
用脚本构建像素标尺buildruler.zip1KBHTTP
关于下载方法的信息


参考资料

学习

获得产品和技术

讨论
  • 加入 My developerWorks 社区;您可以通过个人信息和定 制主页获得符合自己的兴趣的 developerWorks 文章,并 与其他 developerWorks 用户进行交流。


关于作者

作者照片

Ian Shields 参与 developerWorks Linux 专区的许多 Linux 项目。他是 IBM 北卡罗莱那州 Research Triangle Park 的一名高级程序员。他于 1973 年作为一名系统工程师加入 IBM 位于澳大利亚堪培拉的子公司。之后,在加拿大蒙特利尔和北卡罗莱那州 RTP 从事通信系统和普及运算。他拥有多项专利。他毕业于 Australian National University,本科学位是纯粹数学和哲学。他拥有北卡罗来纳州立大学的计算机硕士和博士学位。




对本文的评价










回页首


IBM 公司保留在 developerWorks 网站上发表的内容的著作权。未经IBM公司或原始作者的书面明确许可,请勿转载。如果您希望转载,请通过 提交转载请求表单 联系我们的编辑团队。
    关于 IBM 隐私条约 联系 IBM 使用条款