⚠️ 这是一个非官方翻译网站,与 ImageMagick Studio LLC 无关。准确信息请参阅原文(https://usage.imagemagick.org/advanced/index.html)

ImageMagick 示例 -- 高级技巧

ImageMagick 示例:前言与索引 | 从形状制作 3D 项目符号 | | 使用脚本生成大量图像
给三维灰度阴影图像着色和塑形
---|---|---|---
制作 3D 标志 | 使用透明叠加层为基础塑形图像着色
反射 | 添加多种类型的表面反射。
拼图块 | 从照片中裁出并增强一个异形拼图块
「凝胶」效果 | 调整高光的尺寸、亮度和锐度
使用 'Screen' 与 'Multiply' 合成来变亮和变暗
「Aqua」效果 | 使用 'curves' 调整高光。
可平铺的星星与彗星 | 随机点。
“我的天!满天都是星星!-- 2001,太空漫游”
放射状耀斑 | 在中心点周围生成随机光线和圆环。
本页提供一些很大的示例,展示如何组合多种技巧,生成超出 IM 基本图像操作范围的复合图像处理效果。主要技巧已在上面的索引中概括。虽然许多技巧在其他页面也有介绍,例如创建字体模板、给图像加漂亮标签、使用蒙版等,但这些页面展示的是如何把这些技巧组合起来,得到更复杂的效果。


从形状制作 3D 项目符号 -- 脚本化方法

网上有很多可用于网页列表的“项目符号”图像。不过你也可以自己生成 3D 对象,让整个网站符合某种统一的风格,并把各部分串联起来。最好的做法之一,是创建一个“生成”脚本,让你能按某种固定风格自动生成一整套按钮和形状,同时使用任何需要的颜色。这里就是这样一个非常简单的脚本。我们使用「[-shade](https://imagemagick.org/command-line-options/#shade)」选项,从普通形状的透明图像生成看起来像 3D 的对象。这个形状只有直截了当的开/关透明度,并且会被小心保留,因此可作为普通网页中的透明 GIF 图像使用。生成的灰度“阴影”图像随后用「[-tint](https://imagemagick.org/command-line-options/#tint)」运算符着色,用来设定图像的中间调灰色,同时保留更极端的黑白阴影。之后再把所提供图像的原始形状重新加回到着色结果上。额外的好处是,如果输入图像只有布尔透明度,那么结果也会具有适合 GIF 格式图像的布尔透明度。

    magick {_input_image_} -alpha set \
            \( +clone -channel A -separate +channel \
               -bordercolor black -border 5  -blur 0x2 -shade 120x30 \
               -normalize -blur 0x1 -fill {_color_} -tint 100 \) \
            -gravity center -compose Atop -composite \
            {_output_image_}

注意,上面的脚本只读取了一次输入图像。这样你也可以把脚本放进命令管线中,把「-」作为输入和输出文件名(也许还带上一个 IM 图像格式设置)。在编写自己的 IM 脚本时,这一点可能很重要。上面的命令被写入一个名为「create_bullet」的很简单的 shell 脚本中,随后执行以下命令,以多种颜色生成一整套符号图像。

    magick +antialias -size 15x15 xc:none -draw 'circle 7,7 3,3'  ball.gif
    create_bullet ball.gif  grey    ball_grey.gif
    create_bullet ball.gif  red     ball_red.gif
    create_bullet ball.gif  green   ball_green.gif
    create_bullet ball.gif  blue    ball_blue.gif
    create_bullet ball.gif  yellow  ball_yellow.gif
    create_bullet ball.gif  maroon  ball_maroon.gif
    create_bullet ball.gif  cyan    ball_cyan.gif

    magick -size 12x12 xc:black   square.gif
    create_bullet square.gif  grey    square_grey.gif
    create_bullet square.gif  red     square_red.gif
    create_bullet square.gif  green   square_green.gif
    create_bullet square.gif  blue    square_blue.gif
    create_bullet square.gif  yellow  square_yellow.gif
    create_bullet square.gif  maroon  square_maroon.gif
    create_bullet square.gif  cyan    square_cyan.gif

    # retrieve asterix symbol from
    # [Anthony's Web Images, Symbols](http://www.cit.griffith.edu.au/images/Symbols/Images.html)
    create_bullet asterix.gif  grey    asterix_grey.gif
    create_bullet asterix.gif  red     asterix_red.gif
    create_bullet asterix.gif  green   asterix_green.gif
    create_bullet asterix.gif  blue    asterix_blue.gif
    create_bullet asterix.gif  yellow  asterix_yellow.gif
    create_bullet asterix.gif  maroon  asterix_maroon.gif
    create_bullet asterix.gif  cyan    asterix_cyan.gif

    # Use a heart symbol from "WebDings" font (22 point => 16x16 pixel image)
    magick -font WebDings -pointsize 22 -background none \
            label:Y -trim +repage    heart.png
    create_bullet heart.png  grey    heart_grey.png
    create_bullet heart.png  red     heart_red.png
    create_bullet heart.png  green   heart_green.png
    create_bullet heart.png  blue    heart_blue.png
    create_bullet heart.png  yellow  heart_yellow.png
    create_bullet heart.png  maroon  heart_maroon.png
    create_bullet heart.png  cyan    heart_cyan.png

[IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output]
[IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output]
[IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output]
[IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output]

生成项目符号时,只会使用源图像的形状或透明度,因此任何形状都可以用。请选择适合你网站的独特形状。另请注意,GIF 或 PNG 都可以使用,不管是否用透明度来定义形状,命令并不区分。如果你使用的图像比这里展示的更大,也许还需要增加在 shade 操作之前应用的模糊量。否则你可能会发现只有靠近图像边缘的区域被圆化。此外,与其使用很大的模糊值,多次模糊可能更好(可以提高模糊速度)。当然,如果你做了改进或有其他想法,请告诉我,这样我们就能与其他人分享。


制作 3D 标志

在这个例子中,我们有一个平面的彩色标志,形状比较棘手,希望通过图像处理给它一个明显的 3D 外观。为此,我们用标志生成高光和阴影,把它们变成透明图像并叠加到原图上。这个效果一步一步地使用了所有示例页面中的许多不同技巧。这个例子大量使用由阴影运算符生成的图像,以及各种 Alpha 合成方法。建议你在继续之前先熟悉这些图像运算符,或者在想更好地理解发生了什么时再查阅它们。


不过在开始之前,我们需要一个简单的标志来应用这项技巧,以及它的蒙版……先为这个标志示例的彩色背景创建一个形状。 |

  magick -size 170x100 xc:black \
          -fill white -draw 'circle    50,50  13,50' \
                      -draw 'circle   120,50 157,50' \
                      -draw 'rectangle 50,13 120,87' \
          -fill black -draw 'circle    50,50  25,50' \
                      -draw 'circle   120,50 145,50' \
                      -draw 'rectangle 50,25 120,75' \
          -fill white -draw 'circle    60,50  40,50' \
                      -draw 'circle   110,50 130,50' \
                      -draw 'rectangle 60,30 110,70' \
          -gaussian 1x1 -alpha off logo_mask.png

[IM Output]
现在用这个蒙版裁出标志的纯色部分,并添加一些文字,生成一个普通的纯色标志。 |

  magick logo_mask.png -background red -alpha shape \
          -font Candice  -pointsize 36  -fill white  -stroke black \
          -gravity Center  -annotate 0 "Ant" \
          logo.png

[IM Output]


现在用叠加高光技巧给它一个 3D 外观。 |

  magick logo.png  -alpha extract -blur 0x6  -shade 110x30  -normalize \
          logo.png  -compose Overlay -composite \
          logo.png  -alpha on  -compose Dst_In  -composite \
          logo_3D.png

[IM Output]
添加阴影也很容易,这要归功于 IM 提供的新阴影生成运算符。 |

  magick logo_3D.png \( +clone -background navy -shadow 80x4+6+6 \) +swap \
          -background none  -layers merge +repage logo_3D_shadowed.png

[IM Output]
最后为了好玩,把标志叠加到类似“粗糙纸张”的背景上。还能创建大量其他背景画布,相关示例集合可参见背景示例。 |

  magick logo_3D_shadowed.png \
          \( +clone +repage -alpha off -fx 'rand()' -shade 120x30 \
             -fill grey70 -colorize 60 \
             -fill lavender -tint 100 \) \
          +swap -composite logo_3D_bg.jpg

[IM Output]


反射

反射相对容易制作,但看起来常常并非如此。你必须处理表面颜色、纹理等方面,还要处理这种效果如何随着反射表面与被反射对象之间的距离而增强。基本上,本应相对简单的事情,很快就会变得相当复杂。[IM Output] 所以我们先从一个相对简单图像的反射开始,这里使用的是 Pokemon 角色 Azumarill 的图像(见右侧)。你也可以换成自己的图像。要制作完美镜面反射,只需复制并翻转源对象,再在后面加一点背景来提供上下文。例如……
|

  magick pokemon.gif \( +clone -flip \) -append \
          -size 100x100 xc:black +swap \
          -gravity North -geometry +0+5 -composite  reflect_perfect.png

[IM Output]

表面颜色 - 整体衰减

上面需要注意的是,反射虽然完美,却并不像黑色表面上的反射。它更像原图的一块“镜面瓷砖”,事实也正是如此。即使是普通浴室镜子,也不会反射照射到它的全部光线,而那已经算是你能得到的好镜子了。所以反射的第一条规则是……

反射永远不会完美。

所有反射都不可能是 100% 的反射,因此会被表面(或周围环境)着色。世界并不完美,反射很擅长强化并展示这种不完美。那么我们再试一次,这次用反射表面的颜色给反射着色。可以用两种方式做到。最简单的方法,是直接把反射着色成与表面相同的颜色。着色量取决于表面的反射能力;对于有色表面,通常反射能力很差,因此需要加入大量颜色。对黑色表面来说,「65%」相当不错。 |

  magick pokemon.gif \
      \( +clone -flip -fill black -colorize 65% \) -append \
      -size 100x100 xc:black +swap \
      -gravity North -geometry +0+5 -composite  reflect_colored.png

[IM Output]
好多了……现在它真的像反射了!另一种让反射变弱的方法,是让被反射的图像半透明。比如把图像的 alpha 值相乘,让源对象只有约 35% 可见。 |

  magick pokemon.gif -alpha on \
      \( +clone -flip -channel A -evaluate multiply .35 +channel \) -append \
      -size 100x100 xc:black +swap \
      -gravity North -geometry +0+5 -composite  reflect_alpha.png

[IM Output]
这种方法其实更可取,因为表面可以是任何颜色,甚至可以是某种颜色纹理或图案。例如,我们使用观看远处地平线中的无限平铺技巧,生成一块水平的木地板。 |

  magick tile_wood.gif   -set option:distort:viewport 100x100 \
          -virtual-pixel tile     -distort Perspective \
                '0,0 -20,65  96,0 60,40  96,96 120,55  0,96 50,99' \
          wooden_floor.png

[IM Output]
然后把带半透明反射的图像叠加到这块木地板上。 |

  magick pokemon.gif -alpha on \
      \( +clone -flip -channel A -evaluate multiply .35 +channel \) -append \
      wooden_floor.png +swap \
      -gravity North -geometry +0+5 -composite  reflect_wood.png

[IM Output]
没有被反射的对象时,木质表面看起来相当沉闷、没有生气;但只要其中映出某个对象,地板一下子就显得高度抛光了!

扭曲的源图像

好吧。我们再试一点更花哨的东西,给图像加一点 3D 透视深度。 |

  magick pokemon.gif -alpha on   -virtual-pixel transparent \
      +distort Perspective '0,0 0,0  0,64 0,64  64,0 54,10  64,64 54,54' \
      \( +clone -flip -channel A -evaluate multiply .35 +channel \) -append \
      +filter  -size 100x100 xc:black +swap \
      -gravity North -geometry +0+5 -composite  reflect_distort_bad.png

[IM Output]
这显然不对。图像看起来被扭曲了,但相对于原来的观看者仍然是平贴着的。为什么呢,因为……

接触表面的对象,也会接触它的反射。

这似乎很明显,但我确实见过有人搞错。当然,如果对象漂浮在表面上方,那它们就不会接触。修正它的一种方法,是分别扭曲源图像和该图像的反射,然后再把结果图层合并到一起。 |

  magick pokemon.gif -alpha on   -virtual-pixel transparent \
      \( -clone 0 \
         +distort Perspective '0,0,0,0  0,64,0,64  64,0,54,10  64,64,54,54' \) \
      \( -clone 0  -channel A -evaluate multiply .35 +channel \
         +distort Perspective '0,0,0,128  0,64,0,64  64,0,54,98  64,64,54,54' \
      \) -delete 0 +swap -background none  -layers merge \
      +filter  -size 100x100 xc:black +swap \
      -gravity North -geometry +0+5 -composite  reflect_distort_sep.png

[IM Output]
从这两组差异很大的扭曲参数可以看出,扭曲反射会变得非常困难。更麻烦的是,只要第一个扭曲稍有变化,反射图像的第二个扭曲也必须随之重新计算。还有两条规则可以告诉你,反射扭曲的坐标应如何计算。

水平表面中的反射总是正向下方。

也就是说,反射总是朝向用户;而用户位于图像正前方,因此水平表面中的任何反射都会向下,正好朝向用户。这是物理定律。如果你希望图像至少半真实,就不该违背它。最后还有一条需要记住的规则。

垂直表面在水平表面中的反射,
高度与被反射的对象相同

不管对象在图像中看起来有多“远”,它在最终图像中的反射高度都应与被反射对象本身相同!这并不直观,而且很容易弄错。

这三条规则意味着,反射坐标的 X 值保持不变,而 Y 值会围绕“表面接触点”向下翻转,翻转量等于它在该点上方的距离。

因此只要小心一些,就能根据扭曲后源图像的坐标计算反射的扭曲坐标。现在,这些规则也给了我们一种简化扭曲图像反射的方法。先把反射附加到源图像下方,然后像它没有附带反射一样扭曲源图像,让反射随主图像一起扭曲…… |

  magick pokemon.gif -alpha on   -virtual-pixel transparent \
      \( +clone -flip -channel A -evaluate multiply .35 +channel \) -append \
      +distort Perspective '0,0,0,0  0,64,0,64  64,0,54,10  64,64,54,54' \
      -gravity North  -crop 100x100+0-5\! \
      -background black -compose Over -flatten    reflect_distort.png

[IM Output]
如你所见,这样容易得多,而且只需要处理对象的一组扭曲,修改起来也简单很多。它还允许你使用那些几乎不可能重复一次来创建单独反射的扭曲。例如,从图像生成一个 3D 弧形…… |

  magick pokemon.gif -alpha on   -virtual-pixel transparent \
      \( +clone -flip -channel A -evaluate multiply .35 +channel \) -append \
      +distort Barrel '0,0,0,1  0,0,-.35,1.5  32,32' \
      -gravity North  -crop 100x100+0-5\! \
      -background black -compose Over -flatten    reflect_3Darc.png

[IM Output]
进入下一节之前再说最后一点……阴影通常遵循与反射相同的规则,但最后两条除外。它们不一定正向下方落下,而是指向远离光源的方向(远距离光源则为平行方向)。而且它们到“表面接触点”的距离不会相同,只会保持相同的距离比例,并不像反射那样是 1:1。

渐变衰减

到目前为止,我们处理的是完全光滑的反射表面,但多数表面并没有被抛光到镜面程度。看似光滑的表面,在更小尺度上其实并不光滑,这会影响从该表面反射出的光。被反射光在对象和反射点之间需要走的距离越长,这种效果也会越强。因此……

反射离源图像越远,
就越弱、越扭曲。

创建距离效果的最简单方法,是让反射离表面越远就越弱。为此,通常可以接受让靠近图像的位置稍微亮一些。 |

  magick pokemon.gif -alpha on \
      \( +clone -flip \
         -size 64x28 gradient:gray40-black   \
         -alpha off -compose CopyOpacity -composite \
      \) -append \
      -gravity North  -crop 100x100+0-5\! \
      -background black -compose Over -flatten    reflect_attenuated.png

[IM Output]
这个方法效果相当不错,而且生成起来很容易,所以是生成反射时很常见的方法。它之所以有效,是因为被反射的光中有相当一部分并不是完美反射,而更像全局环境。离原始图像越远,反射出的原始图像就越少。

模糊衰减

构成源对象真实反射的成分,并不会只是随着距离变弱。现实中,反射表面通常并不很平滑,因此反射会随着距离变得更模糊、更朦胧、更扭曲。这不是宏观扭曲,而是非常细小的微观层面的扭曲。它与产生镜面高光反射的是同一种效果。也就是说,靠近反射源时它们可以相当清晰,但离源越远,图像就越模糊。在 IM 6.5.5-0 之前,这很难实现(虽然可以做到,但需要不少技巧)。现在则可以使用可变模糊映射,相当容易地根据反射离源图像的距离对其进行模糊。不过为了让它发挥作用,最好在对象周围添加一圈透明边框,供模糊扩散。在这些示例中,我把最终图像扩展了,这样你能看到完整反射,也更容易体会效果。 |

  magick pokemon.gif -alpha on \
      -background None -gravity South -extent 100x100 \
      \( +clone -flip -channel A -evaluate multiply .35 +channel \
         -size 100x100 gradient:gray5-white \
         -compose Blur -set option:compose:args 10 -composite -compose Over \
      \) -append -trim +repage \
      -gravity North  -crop 100x140+0-5\! \
      -background black -compose Over -flatten    reflect_blurred.png

[IM Output]
还可以使用垂直拉伸的模糊椭圆进一步增强反射模糊。例如使用「10x30」这样的椭圆模糊参数,而不是简单的「20」圆形模糊。如果再把“模糊衰减”和“渐变衰减”结合起来,就会开始得到非常逼真的、典型的、并不那么抛光但仍平滑的表面反射。 |

  magick pokemon.gif -alpha on \
      -background None -gravity South -extent 100x100 \
      \( +clone -flip \
         \( -size 100x64 gradient:'rgba(0,0,0,0.6)-none' \
            -size 100x36 xc:none  -append \
         \) -compose Dst_In -composite \
         \( -size 100x100 gradient:gray5-white \
         \) -compose Blur -set option:compose:args 4x8 -composite \
      \) -append -trim +repage \
      -gravity North  -crop 100x140+0-5\! \
      -background black -compose Over -flatten    reflect_blur_atten.png

[IM Output]
对于平面表面来说,你很难得到比这更好的反射图像。

Future: To add examples of...
  Surface Texture effects
    frosted - or non smooth surfaces (small scale randomised distortions)
    rippled - water reflections
        (very little blur or attenuation, just stronger macro distortion)

拼图块

我曾被请求帮助完成的最有趣的事情之一,是从一张较大的图片中裁出一个异形“拼图”块并加以增强。实际上,Theo van Hoesel,也就是「Mr Jigsaw」,想要生成大量单独的拼图块,并且带有许多不同的旋转角度。下面的内容是根据我们的讨论为单个拼图块发展出来的;不过只要有合适的一组模板,就能生成任意图案的拼图块。右侧是一个缩略图,链接到德国柏林大屠杀纪念碑照片的 800x600 图像。这张照片是我在 2006 年 4 月欧洲旅行期间拍摄的。它看起来很适合制作一个非常困难的拼图。下面则是我将从上方图像中提取的拼图块模板图像。它是一组此类图像中的一部分。完整的拼图块集合包含 192 个这样的蒙版,排列为 16×12,其中包括边缘和角落。这一特定拼图块是一个 100x100 像素蒙版,设计用于 800x600 像素图像 上的 +365+96 偏移。这些数值只有在你拥有一大套彼此拼合的不同拼图块时才重要。如果你不打算这样做,当然可以使用任何喜欢的偏移。 [photo]
[IM Output]
我自己收集过不少这样的拼图集合,它们可以让我把任何图像做成拼图。这也正是 Theo van Hoesel 在他的网站上实际做的事。如果你在制作真正的拼图,偏移信息就非常重要,因为它标识了该拼图块在原始图像中的位置和放置方式。因此我会尽量保留这些信息。注意,由于形状周围有额外留白,蒙版的偏移在某些情况下可能为负,因此你可能需要测试并调整图像命令来处理这种情况。额外留白本身可以让你轻松地为最终图像添加旋转、厚度和阴影效果,而不必改变裁出拼图块的尺寸或偏移。 不过首先,让我们把这个模板变成轮廓。
    magick jigsaw_tmpl.png -edge .5 -blur 0x.5 jigsaw_edge.png

[IM Output]
然后可以把它叠加到图像上,大致看看将被裁出以形成拼图块的内容。 |

    magick holocaust_md.jpg \
            \( jigsaw_edge.png -negate \) -geometry +365+96 \
            -compose multiply -composite \
            -crop 100x100+365+96 +repage jigsaw_outline.png

[IM Output]
正常生成拼图时通常不会这样做,但当拼图块的位置并不重要(因为它不是更大拼图的一部分)时,这很有用。这样你就可以调整偏移,为该拼图块选择更好的内容。 | 由于「[-edge](https://imagemagick.org/command-line-options/#edge)」的工作方式,上面生成的拼图轮廓位于蒙版图像的被遮罩(白色)区域内部。如果你之后想利用这个轮廓,这一点可能很重要。
---|---
好了,我们已经有了拼图形状,以及要裁出拼图块的偏移。接下来把它裁出来,并顺便旋转。 |

    magick holocaust_md.jpg \
            -crop 100x100+365+96\! -background none -flatten +repage \
            \( jigsaw_tmpl.png -alpha off \) -compose CopyOpacity -composite \
            -rotate -20 -gravity center -crop 100x100+0+0 +repage \
            jigsaw_cutout.png

[IM Output]
注意,我们把源图像裁剪到模板形状覆盖的区域。蒙版之外的区域不再需要,尽早移除可以加快图像处理。还要注意这里对视口裁剪的特殊用法,后面跟着「[-flatten](https://imagemagick.org/command-line-options/#flatten)」。这种裁剪方法可以保证我们得到一个 100x100 像素的图像,用来从中“裁出”模板;即使使用边缘或角落拼图块的蒙版,也能处理位于图像上边缘或左边缘上及附近拼图块的负偏移。旋转也在此时进行,因为大多数增强效果会基于特定方向来添加。旋转结果也会居中裁剪,因为该运算符通常会根据所用旋转角度扩大结果图像尺寸,而我们不希望它这样做。第一个增强,是在拼图块边缘周围添加略带斜面或圆角感的高光。这与阴影高光叠加一致,可以细致控制高光生成方式(4 个独立因子)。 |

   magick jigsaw_cutout.png \
           \( +clone -channel A -separate +channel -negate \
              -background black -virtual-pixel background \
              -blur 0x2 -shade 120x21.78 -contrast-stretch 0% \
              +sigmoidal-contrast 7x50%  -fill grey50 -colorize 10% \
              +clone +swap -compose overlay -composite \) \
          -compose In -composite jigsaw_bevel.png

[IM Output]
在真正的拼图中,这种斜面是机器压切拼图块造成的结果。它还会给拼图块一点凹痕,因此即使把拼图块重新拼回去,仍能看到切割留下的印痕。现在给拼图块加一点厚度。这是我找到的最好也最快的方法,虽然我并不认为它是很好的技巧。如果你能找到更好的方法,请告诉我。 |

   magick jigsaw_bevel.png \
           \( +clone -fill DarkSlateGrey -colorize 100% -repage +0+1 \) \
           \( +clone -repage +1+2 \)  \( +clone -repage +1+3 \) \
           \( +clone -repage +2+4 \)  \( +clone -repage +2+5 \) \
          -background none -compose DstOver -flatten \
          jigsaw_thickness.png

[IM Output]
最后再加点阴影如何。 |

    magick jigsaw_thickness.png \
            \( +clone   -background Black -shadow 50x3+4+4 \) \
            -background none -compose DstOver -flatten \
            jigsaw_shadow.png

[IM Output]
上面的所有命令都可以很容易地保存成一个 shell 脚本,我自己也已经这样做了。脚本「[jigsaw](../static/img/scripts/jigsaw) 」接受三个图像参数:源照片、模板和输出目标,同时也有许多选项来启用上面展示的各种增强效果。它也并不一定要使用拼图形状。任何蒙版模板都可以用来从图像中裁出部分,并加上适当效果。上面的命令和我的脚本版本之间最大的差异是,默认情况下,脚本会尽量让最终图像保持最小,同时追踪裁出图像的偏移。通过保留这个偏移位置,你可以使用简单的「[-mosaic](https://imagemagick.org/command-line-options/#mosaic)」或「[-flatten](https://imagemagick.org/command-line-options/#flatten)」把多个拼图块重新叠加到一起,从而产生有趣效果(见下面最后一个示例)。下面是这个脚本的几个不同用法示例。

    jigsaw -o +365+96 -m  null: jigsaw_tmpl.png  jigsaw_mask.png
    magick -size 800x600 xc:gray miff:- |\
                 jigsaw -r 30 -l -h -s miff:- jigsaw_mask.png jigsaw_grey.png
    jigsaw -r -60 -h -t 4 -s holocaust_md.jpg jigsaw_mask.png jigsaw_piece.png

    magick jigsaw_cnr.png -resize 50% -flip -flop -repage 120x90 \
            -background black -flatten -flip -flop jigsaw_cnr_tmpl.png
    jigsaw -t 3 -s  -r 15  -d +15+7 \
            holocaust_tn.gif jigsaw_cnr_tmpl.png   holocaust_piece_tn.png
    magick jigsaw_cnr_tmpl.png -negate png:- |\
      jigsaw -t 3 -s holocaust_tn.gif png:-   holocaust_puzzle_tn.png
    magick holocaust_puzzle_tn.png  holocaust_piece_tn.png \
            -background none  -mosaic    holocaust_jigsaw_tn.png

[IM Output] [IM Output] [IM Output]
[IM Output] [IM Output] [IM Output] [IM Output] [IM Output]

最后一张图是某种拼图缩略图样式的开端……它取一个角落拼图块,通过一些缩放和扩展,把蒙版转换成完整尺寸的图像模板蒙版。然后它不仅用于从现有缩略图中裁出角落拼图块,还会取反来生成图像的剩余部分。把这两幅图像叠加起来,就能得到一个相当精致的拼图缩略图。注意在拼图块创建选项中使用了「-d +15+7」。这会相对于图像中的原始位置,把生成的 PNG 图像的“页面偏移”移动一点点,从而简单轻松地得到所示结果。其他可用选项请参见脚本本身。 | _由于生成的页面偏移可能为负,并且可能包含可选的柔和阴影效果,建议提取出的拼图块只使用 PNG 图像。GIF 图像无法处理负页面偏移或阴影效果,在涉及透明度时也无法生成平滑的抗锯齿边缘。

通常,除了最终图像之外,你应避免使用 GIF(以及 JPEG)图像。更多信息见常见图像格式示例页面。_
---|---
你并不限于使用拼图模板;任何形状的蒙版都可以与任何图像一起使用。请告诉我你做出了什么。「[jigsaw](../static/img/scripts/jigsaw)」脚本的开发还没有完全结束,因为我还想为高光、厚度和阴影效果加入更好的控制,也可能加入一个“反转蒙版”选项。不过它基本上已经是一个完整可用的程序,你可以自由使用。如果你在网页上使用它,记得给我一个反向链接 :-) 如果你有一些 PerlMagick API 技能,可以试着把上面的脚本转换成 PerlMagick 以提高速度,然后提交给我,这样其他人也可以使用,并知道你对 IM 有多熟练。始终欢迎进一步的建议和想法。
如果你只是想用一组蒙版(带或不带虚拟像素偏移)从一幅图像中裁出所有拼图块,下面的命令可以非常快速地完成全部工作。

  magick mask_*.png -set filename:mask %t -alpha shape \
          null: image.jpg -compose In -layers composite \
          pieces_%[filename:mask].png

生成的每个「pieces_mask_*.png」图像,不仅包含原始图像中正确偏移处的对应内容,也会在最终图像中保留该偏移。它通过多层合成来完成:把特殊「null:」标记图像左侧的所有图像,与右侧的单一图像合并。额外的好处是,它会把所用蒙版的文件名写入拼图块图像文件名(包括最终图像文件格式),从而更容易识别哪一块是什么。(详见文件名百分号转义。注意,蒙版不必完全覆盖整个原始图像,但不应在拼图块之间留下空白或缝隙。当然,对于真正的拼图,所有蒙版都应正确对齐,以便形成无缝整体,例如 Dst_Out 合成示例中所示。


「凝胶」效果

上面使用的 3D 阴影只是高光和阴影效果能做的事情的开始。通过对 "-shade" 的输出进行各种直方图调整,可以得到范围极广的可能效果。其中一种可以复现的效果称为“Gel”效果,经常能在「Photoshop」教程网站上看到(Google 搜索 "Gel Effects Tutorial")。首先创建我们需要的形状。它可以是预先准备好的图像,也可以像上面 3D 项目符号中的“heart”那样,从某种 'Dings' 字体中提取。这里我们为按钮使用一个简单的椭圆形…… |

  magick -size 100x60 xc:none \
          -fill red -draw 'circle    25,30  10,30' \
                    -draw 'circle    75,30  90,30' \
                    -draw 'rectangle 25,15  75,45' \
          gel_shape.png

[IM Output]
现在使用高度修改过的模糊 shade 操作,为彩色形状添加锐利的“Gel”高光…… |

    magick gel_shape.png \
            \( +clone -alpha extract  -blur 0x12  -shade 110x0 -normalize \
               -sigmoidal-contrast 16,60% -evaluate multiply .5 \
               -roll +5+10 +clone -compose Screen -composite \) \
            -compose In  -composite  gel_highlight.png

[IM Output]
我们先把透明度(matte)通道的副本模糊,使其圆润,再对它应用 "-shade"。这个 shade 使用了没有任何“高度”或“方位”角的光源,基本上会在模糊形状的一侧得到灰色高光,其他地方则为黑色。随后用 "-sigmoidal-contrast" 运算符调整(锐化)这个高光灰度图,以缩小高光区域(「60%」阈值水平)并锐化边缘(使用非常高的「16」指数因子)。指数值这么高时,该运算符几乎像一个“模糊”的 "-threshold" 运算符,会基于原始图像形状生成一块平坦的颜色区域。关于这种平滑的对比度/阈值函数,更多信息见 Sigmoidal 非线性对比度。最后,用 "-evaluate" 按期望的高光强度乘以所有颜色来调整高光级别,然后使用 "-roll" 把它的位置移入形状区域。由于高光是在黑底上的灰色(黑色保持不变),可以使用「[Screen](compose.html#screen)」alpha 合成,按给定灰度级别提亮非黑区域。现在剩下的只是稍微压暗边缘…… |

    magick gel_highlight.png \
          \( +clone -alpha extract  -blur 0x2 -shade 0x90 -normalize \
             -blur 0x2  +level 60,100%  -alpha On \) \
          -compose Multiply  -composite  gel_border.png

[IM Output]
注意,这次我为边缘变暗使用了垂直照明的 "-shade",这样我想保持不变的区域会变成白色。因此,在用反向级别调整调整灰度,并恢复由 Alpha 提取方法保存的透明度之后,我就能使用「[Multiply](compose.html#multiply)」alpha 合成来压暗受影响的边缘。最后给椭圆形“Gel”按钮加上文字和阴影效果…… |

    magick gel_border.png \
            -font Candice  -pointsize 24  -fill white  -stroke black \
            -gravity Center  -annotate 0 "Gel"  -trim -repage 0x0+4+4 \
            \( +clone -background navy -shadow 80x4+4+4 \) +swap \
            -background none  -flatten    gel_button.png

[IM Output]


「Aqua」或「气泡」效果

你也可以调整完整 3D "-shade"(30 度光照)的色调,生成一种“Aqua”水感效果。不过为此,我们需要以类似「Gimp」和「Photoshop」这类 GUI 图形程序的方式进行直方图调整。我会先慢慢按步骤做一遍,让你能看到我遵循的步骤。先创建一幅要使用的图像,这里是一枚弯曲的字母 A。 |

  magick -background none -fill DodgerBlue \
          -font Candice -pointsize 72  label:A  -trim +repage \
          -bordercolor None -border 1x1 \
          aqua_shape.png

[IM Output]
注意,我在图像周围加了一圈 1 像素的透明边框。这会让接下来的处理步骤稍微容易一点。现在需要为这个形状图像生成圆润阴影。 |

  magick aqua_shape.png \
          -alpha Extract -blur 0x8  -shade 130x30 -alpha On \
          -background gray50 -alpha background -auto-level \
          aqua_shade.png

[IM Output]
那行处理 Alpha 背景的奇怪命令,是为了把透明区域的隐藏颜色重置为中间调灰色,使它不会影响颜色归一化。这可能非常重要。现在把这个 shade 变成一种“光照效果”,看起来大致像光线被水泡或玻璃泡扭曲的样子。 |

  magick aqua_shade.png \
          -function polynomial  3.5,-5.05,2.05,0.3 \
          aqua_lighting.png

[IM Output]
多项式函数用于图像的曲线调整。正是这个函数产生了整体效果,而且它可能很难确定。为此,我把这条“曲线”所需的控制点传给名为「[**im_fx_curves**](../static/img/scripts/im_fx_curves)」的 IM 支持 shell 脚本。它随后返回拟合这些控制点的“曲线”所需的多项式方程“系数”。

  im_fx_curves -c -p  0,30  100,80  50,50  80,50  > aqua_coeffs.txt

[Gnuplot] | | | [Coeffs]

这个光照效果的最后一步调整,是让光照效果的边缘变暗。 |

  magick aqua_lighting.png \
          \( +clone -alpha extract  -blur 0x2 \) \
          -channel RGB -compose multiply -composite \
          aqua_light+edge.png

[IM Output]
这样阴影叠加就完成了。剩下的只是使用 HardLight 合成,把它应用到原始图像上。 |

  magick aqua_shape.png aqua_light+edge.png \
          -compose Hardlight -composite   aqua_result.png

[IM Output]
注意,生成图像最终的整体颜色其实就是原始形状的原始颜色。事实上,你甚至可以把它应用到多色图像上,也完全没有问题。现在把上面的所有步骤,包括初始形状图像的创建,都合并成一个命令再做一遍。

  magick -background none -fill DodgerBlue \
          -font Candice -pointsize 96  label:'Aqua Text' -trim +repage \
          \
          \( +clone -bordercolor None -border 1x1 \
             -alpha Extract -blur 0x8  -shade 130x30 -alpha On \
             -background gray50 -alpha background -auto-level \
             -function polynomial  3.5,-5.05,2.05,0.3 \
             \( +clone -alpha extract  -blur 0x2 \) \
             -channel RGB -compose multiply -composite \
             +channel +compose -chop 1x1 \
          \) \
          -compose Hardlight -composite  aqua_text.png

[IM Output]

如果研究上面的命令,你会看到前面概述的所有步骤都被用于生成光照图像,然后再把它合成到原始图像上。


可平铺的星星与彗星

我想为各种用途制作一块随机星场的图块(其中星星有不同强度)。这是我逐步改进尝试后的结果。使用一幅随机噪声图像来稀疏自身,从而生成斑点图案。 |

  magick -size 100x100 xc: +noise Random -channel R -threshold 5% \
          -negate -channel RG -separate +channel \
          -compose multiply -composite   speckles.gif

[IM Output]
这个图案是闪烁动画效果的基础,也是其他效果的起点。例如要制作星星,我们需要进一步修改随机“斑点”图案,让效果更真实。 |

  magick -size 100x100 xc: +noise Random -channel R -threshold 1% \
          -negate -channel RG -separate +channel \
          \( +clone \) -compose multiply -flatten \
          -virtual-pixel tile -blur 0x.4 -contrast-stretch .8% \
          stars.gif

[IM Output]
注意,我不仅乘以斑点蒙版(「R」通道),也把星星强度图像(「G 通道)乘了两次。这会让像素强度呈平方衰减,使暗星比亮星更多,就像真实夜空一样。之后根据星星强度通过模糊放大星星尺寸。这会产生类似星星在天文摄影底片上灼印出来的效果,使其更逼真。模糊值越大,效果越强。最后的「[-contrast-stretch](https://imagemagick.org/command-line-options/#contrast-stretch)」把结果拉回到可见范围。通过使用两幅随机噪声图像(一幅用于蒙版,另一幅用于星星颜色),我们可以生成随机着色的星星,而不是简单的灰度星星。 |

  magick -size 100x100 xc: +noise Random -channel R -threshold 1% \
          -negate -channel RG -separate +channel \
          \( xc: +noise Random \) -compose multiply -flatten \
          -virtual-pixel tile -blur 0x.4 -contrast-stretch .8% \
          stars_colored.gif

[IM Output]
不过这可能还需要更多工作,因为我们需要直接对颜色强度求平方,而不是只把它们与线性分布相乘。尽管如此,它确实可用,并提供了继续发展的起点。注意颜色不一定是随机的,也可以很容易来自某个其他图像。例如,星星本身的颜色可以取自最终将用作背景的图像。现在我有了星景生成器,就可以简单地用「[-motion-blur](https://imagemagick.org/command-line-options/#motion-blur)」创建一片坠落星星的场! |

  magick -size 100x100 xc: +noise Random -channel R -threshold .4% \
          -negate -channel RG -separate +channel \
          \( +clone \) -compose multiply -flatten \
          -virtual-pixel tile -blur 0x.4 -motion-blur 0x20+45 -normalize \
          star_fall.gif

[IM Output]
当然,我们希望星星更少,星星强度的“衰减”也更少。通过对图像进行极坐标扭曲,可以让彗星飞入或螺旋进入一个点! |

  magick -size 250x100 xc: +noise Random -channel R -threshold .4% \
          -negate -channel RG -separate +channel \
          \( +clone \) -compose multiply -flatten \
          -virtual-pixel Tile -background Black \
          -blur 0x.6 -motion-blur 0x15-90 -normalize \
          +distort Polar 0 +repage  star_inward.gif
  magick -size 250x100 xc: +noise Random -channel R -threshold .4% \
          -negate -channel RG -separate +channel \
          \( +clone \) -compose multiply -flatten \
          -virtual-pixel Tile -background Black \
          -blur 0x.6 -motion-blur 0x15-60 -normalize \
          +distort Polar 0 +repage   star_spiral.gif

[IM Output]

[IM Output]
这里我们把星星沿六个方向(成对)做运动模糊,然后合并到一起,创建出类似玻璃镜头中看到的“星芒”场。 |

  magick -size 100x100 xc: +noise Random -channel R -threshold .2% \
          -negate -channel RG -separate +channel \
          \( +clone \) -compose multiply -flatten \
          -virtual-pixel tile  -blur 0x.3 \
          \( -clone 0  -motion-blur 0x10+15  -motion-blur 0x10+195 \) \
          \( -clone 0  -motion-blur 0x10+75  -motion-blur 0x10+255 \) \
          \( -clone 0  -motion-blur 0x10-45  -motion-blur 0x10+135 \) \
          -compose screen -background black -flatten  -normalize \
          star_field.gif

[IM Output]
注意,较暗的星星只生成一个小点,几乎没有“星芒”;而较大、较亮的星星会生成非常大的“星芒”。如果我能找到一种添加 'sinc()' 类型模糊的方法,在最亮星星周围也生成耀斑“圆环”,那我们就会拥有一个很棒的星场生成器。再加上一些 plasma 背景,甚至可以生成假的星云和气体云天文照片。把上面的内容与plasma 闪烁动画结合起来,就能制作一组看起来像圣诞装饰的星星。 |

  magick -size 100x100 xc: +noise Random -separate \
          null: \
            \( xc: +noise Random -separate -threshold 50% -negate \) \
            -compose CopyOpacity -layers composite \
          null: \
            plasma:red-firebrick plasma:red-firebrick plasma:red-firebrick \
            -compose Screen -layers composite \
          null:  \
            \( xc: +noise Random -channel R -threshold .08% \
              -negate -channel RG -separate +channel \
              \( +clone \) -compose multiply -flatten \
              -virtual-pixel tile  -blur 0x.4 \
              \( -clone 0  -motion-blur 0x15+90  -motion-blur 0x15-90 \) \
              \( -clone 0  -motion-blur 0x15+30  -motion-blur 0x15-150 \) \
              \( -clone 0  -motion-blur 0x15-30  -motion-blur 0x15+150 \) \
              -compose screen -background black -flatten  -normalize \) \
            -compose multiply -layers composite \
          -set delay 30 -loop 0 -layers Optimize       stars_xmas.gif

[IM Output]
上面的技巧只是可实现内容的开始。使用一些简单的动画技巧,可以创建可添加到图像中的闪光和随机耀斑。GIF 动画示例中提供了一个简单例子,使用一个简单的 shell 脚本「[star_field](../static/img/scripts/star_field) 」生成星芒。你能用这个星星生成器做什么?挑战:

  • 生成闪光而不是星星。初始斑点场应由蒙版限制(比如通过相乘)。然后闪光和星星都可以用 'screen' 合成叠加到图像上。
  • 使用带蒙版的“斑点场”生成用于叠加的星芒。通过遮罩种子而不是完整星芒,星芒的“光线”可以离开蒙版区域,叠加到图像的其他部分。也就是说,光线不会只是被“切断”。
  • 创建随机星芒的动画。这可能需要让单个星芒场动起来(也许让光线旋转)。
  • 生成几个星芒动画后,可以把它们合并起来,形成来自不同位置的一系列重叠星芒。
  • 通过直方图拉伸和阈值处理,在图像最亮部分找到一个单独的“种子”点。然后逐个选取像素,直到有一个落入蒙版区域。
  • 在平面阴影形状的边缘创建星星。

如果你完成了上面的任何挑战,或把星星生成器用于其他目的,请告诉我和 IM 社区的其他人。


放射状耀斑

生成放射状耀斑的实验。注意,在进行极坐标扭曲之前,初始图像的宽度基本上决定了将生成的光线数量。

  magick -size 100x1 xc: +noise Random -channel G -separate +channel \
          -scale 100x100\!                                +write flare_1a.png \
          \( -size 100x100 gradient:'gray(100%)' -sigmoidal-contrast 10x50% \) \
          -colorspace sRGB -compose hardlight -composite  +write flare_1b.png \
          -virtual-pixel HorizontalTileEdge -distort Polar -1 \
          flare_1_final.png

[IM Output] [IM Output] [IM Output]

注意,我使用「[+write](https://imagemagick.org/command-line-options/#write)」保存中间图像以便显示。这是一种调试技巧,详见复杂图像处理与调试。下面是另一个例子,使用多个叠加层来实现不同外观的耀斑。请注意其中用于生成中间调试图像和示例图像、以展示相关步骤的技巧。

  magick -size 100x1 xc: +noise Random -channel G -separate +channel \
          -size 100x99 xc:black -append -motion-blur 0x35-90 \
          \( -size 100x50 gradient:'gray(0)' \
             -evaluate cos .5 -sigmoidal-contrast 3,100% \
             -size 100x50 xc:'gray(0)' -append \) \
          \( -size 1x50 xc:'gray(0)' \
             -size 1x1 xc:'gray(50%)' \
             -size 1x49 xc:'gray(0)' \
             -append -blur 0x2 -scale 100x100\! \) \
          \
          -scene 10 +write flare_2%x.png \
          \
          -background 'gray(0)' -compose screen -flatten +write flare_2f.png \
          \
          -virtual-pixel HorizontalTileEdge -distort Polar -1 \
          -colorspace sRGB flare_2_final.png

[IM Output] [IM Output] [IM Output] [IM Output] [IM Output]

使用极坐标扭曲来生成耀斑图像的主要问题,是光线会随着半径变宽,而实际上我们希望它们在变暗时保持大致恒定的宽度,或者至少变得更细。欢迎想法和指点 在这类图像中,颜色调色也可能很重要。例如,这里我把中间调颜色着色为蓝色。 |

  magick flare_2_final.png  -fill SkyBlue  -tint 100%  flare_2_color.png

[IM Output]
[-tint](https://imagemagick.org/command-line-options/#tint)」操作使用的百分比,也可以用来调整光线和耀斑圆环的强度,不过它不会明显改变图像的白色核心。这些示例在 IM 论坛讨论使用放射状耀斑作为蒙版中得到了进一步发展。