【问题标题】:How to programmatically generate a ring/annulus with varying blocks of colors如何以编程方式生成具有不同颜色块的环/环
【发布时间】:2015-08-03 16:05:03
【问题描述】:

一张图胜过千言万语……

我想知道如何生成这样的图像,其中(1)两个圆显然是完美的圆,(2)我可以根据角度定义每个区域的开始和结束部分,例如第 1 部分从垂直的 0 弧度开始,到垂直的 pi/2 弧度结束,等等,(3) 我可以定义每个区域的颜色。

其实环的外侧和内侧不应该有黑色边框;每个区域的边框应该和每个区域的颜色相同。

我如何使用 ImageMagick 来做到这一点?

【问题讨论】:

  • 大概您也需要提供内半径和外半径?是否只有一个环,或者您打算稍后顺便提一下,可能还有其他您没有提到的同心环? ;-)

标签: image imagemagick dynamic-image-generation


【解决方案1】:

您可以使用 Arc 命令在矢量图形中创建环形。有关参数的详细信息,请参阅 Mozilla 的Path Document

使用 ImageMagick,您可以-draw 矢量图形的任何部分。示例:

convert -size 100x100 xc:transparent -stroke black -strokewidth 1 \
        -fill blue  -draw 'path "M 10 50 A 40 40 0 0 1 50 10 L 50 20 A 30 30 0 0 0 20 50 Z"' \
        -fill red   -draw 'path "M 50 10 A 40 40 0 0 1 90 50 L 80 50 A 30 30 0 0 0 50 20 Z"' \
        -fill green -draw 'path "M 90 50 A 40 40 0 0 1 10 50 L 20 50 A 30 30 0 0 0 80 50 Z"' \
        annulus.png

其他很好的例子herehere

更新

要创建更加程序化的方法,请使用任何OOP 脚本语言。下面是使用 Python 和 Wand 的快速示例,但也强烈推荐使用 Ruby 和 RMagick

#!/usr/bin/env python3

import math

from wand.color import Color
from wand.drawing import Drawing
from wand.image import Image

class Annulus(Image):
  def __init__(self, inner, outer, padding=5):
    self.Ri = inner
    self.Ro = outer
    side = (outer + padding) * 2
    self.midpoint = side/2
    super(Annulus, self).__init__(width=side,
                                  height=side,
                                  background=Color("transparent"))
    self.format = 'PNG'

  def __iadd__(self, segment):
    cos_start, cos_end = math.cos(segment.As), math.cos(segment.Ae)
    sin_start, sin_end = math.sin(segment.As), math.sin(segment.Ae)
    SiX, SiY = self.midpoint + self.Ri * cos_start, self.midpoint + self.Ri * sin_start
    SoX, SoY = self.midpoint + self.Ro * cos_start, self.midpoint + self.Ro * sin_start
    EiX, EiY = self.midpoint + self.Ri * cos_end,   self.midpoint +  self.Ri * sin_end
    EoX, EoY = self.midpoint + self.Ro * cos_end,   self.midpoint + self.Ro * sin_end
    with Drawing() as draw:
      for key, value in segment.draw_args.items():
        setattr(draw, key, value)
      draw.path_start()
      draw.path_move(to=(SiX, SiY))
      draw.path_elliptic_arc(to=(EiX, EiY),
                             radius=(self.Ri, self.Ri),
                             clockwise=True)
      draw.path_line(to=(EoX, EoY))
      draw.path_elliptic_arc(to=(SoX, SoY),
                             radius=(self.Ro, self.Ro),
                             clockwise=False)
      draw.path_close()
      draw.path_finish()
      draw(self)
    return self

class Segment(object):
  def __init__(self, start=0.0, end=0.0, **kwargs):
    self.As = start
    self.Ae = end
    self.draw_args = kwargs

if __name__ == '__main__':
  from wand.display import display
  ring  = Annulus(20, 40)
  ring += Segment(start=0,
                  end=math.pi/2,
                  fill_color=Color("yellow"))
  ring += Segment(start=math.pi/2,
                  end=math.pi,
                  fill_color=Color("pink"),
                  stroke_color=Color("magenta"),
                  stroke_width=1)
  ring += Segment(start=math.pi,
                  end=0,
                  fill_color=Color("lime"),
                  stroke_color=Color("orange"),
                  stroke_width=4)
  display(ring)

【讨论】:

    【解决方案2】:

    我对@9​​87654325@ 知之甚少,但我认为它很可能符合这里的要求 - 我的命令可能很粗糙,但它们看起来非常清晰有效。比我聪明的人也许可以改进它们!

    无论如何,这是我想出的脚本:

    set xrange [-1:1]
    set yrange [-1:1]
    set angles degrees
    set size ratio -1
    # r1 = annulus outer radius, r2 = annulus inner radius
    r1=1.0
    r2=0.8
    unset border; unset tics; unset key; unset raxis
    set terminal png size 1000,1000
    set output 'output.png'
    set style fill solid noborder
    set object circle at first 0,0 front size r1 arc [0:60]    fillcolor rgb 'red'
    set object circle at first 0,0 front size r1 arc [60:160]  fillcolor rgb 'green'
    set object circle at first 0,0 front size r1 arc [160:360] fillcolor rgb 'blue'
    
    # Splat a white circle on top to conceal central area
    set object circle at first 0,0 front size r2 fillcolor rgb 'white'
    
    plot -10 notitle
    

    结果如下:

    因此,如果您将上述脚本保存为annulus.cmd,您将运行它并使用命令创建文件output.png

    gnuplot annulus.cmd
    

    显然,脚本的核心是从 set object circle 开始的 3 行代码,每行代码都创建了一个不同颜色的单独环形段,具有不同的开始和结束角度集。

    闲逛和改变一些东西会得到这个:

    set xrange [-1:1]
    set yrange [-1:1]
    set angles degrees
    set size ratio -1
    # r1 = annulus outer radius, r2 = annulus inner radius
    r1=1.0
    r2=0.4
    unset border; unset tics; unset key; unset raxis
    set terminal png size 1000,1000
    set output 'output.png'
    set style fill solid noborder
    set object circle at first 0,0 front size r1 arc [0:60]    fillcolor rgb 'red'
    set object circle at first 0,0 front size r1 arc [60:120]  fillcolor rgb 'green'
    set object circle at first 0,0 front size r1 arc [120:180] fillcolor rgb 'blue'
    set object circle at first 0,0 front size r1 arc [180:240] fillcolor rgb 'yellow'
    set object circle at first 0,0 front size r1 arc [240:300] fillcolor rgb 'black'
    set object circle at first 0,0 front size r1 arc [300:360] fillcolor rgb 'magenta'
    
    # Splat a white circle on top to conceal central area
    set object circle at first 0,0 front size r2 fillcolor rgb 'white'
    
    plot -10 notitle
    

    【讨论】:

      【解决方案3】:

      由于我更擅长直线思考而不是圆圈思考,所以我想我会再尝试一次,完全不同的方式......

      首先,将我们的圆环画成这样的直线:

      convert -size 45x40 xc:red xc:lime -size 270x40 xc:blue +append line.png
      

      我偷偷地将线段的长度加起来为 360,因此每度有一个像素 - 我的简单大脑可以应付 :-) 所以,红色有 45 px(度),45 px (度)的石灰和 270 像素(度)的蓝色,它们都与+append 一起附加以形成线条。请注意,第一个 -size 45x40 设置会一直持续到后来更改,因此在我将其更改为准备应用于蓝色之前,它适用于红色和石灰线段。

      现在我们将这条线绕一个圆弯曲,如下所示:

      convert line.png -virtual-pixel White -distort arc 360 result.png
      

      当你习惯了这个概念后,你也可以一次性完成,就像这样:

      convert -size 60x40 xc:red xc:lime xc:blue xc:cyan xc:magenta xc:black +append -virtual-pixel White -distort arc 360 result.png
      

      您可以像这样为环段添加灰色边框:

      convert -size 600x400 xc:red xc:lime xc:blue xc:cyan xc:magenta xc:black -bordercolor "rgb(180,180,180)" -border 20 +append -virtual-pixel White -distort arc 360 result.png
      

      如果您想要透明背景上的所有内容,请将上面的所有white 更改为none

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-09-30
        • 1970-01-01
        • 2012-06-16
        • 2017-12-07
        • 2014-05-29
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多