@Gizmosir
2016-03-15T14:52:34.000000Z
字数 5232
阅读 813
date: 2016-03-15
categories: Computer graphics
tag: [SVG, 矢量图]
博客
图像分为两类:位图和矢量图。位图是由一个个独立的像素组成,也就是一般照片的呈现方式,所以我们更为熟悉。而矢量图(Scalable vector graphics, 下用 SVG代替)则是使用数学公式来表示图像,虽然其生成过程较为复杂,但是有个显著的特点就是可以无限放大且不会出现锯齿。
图1. 左为位图,右为矢量图。
SVG 可以作为一个独立的文件存在,也可以插入到HTML中。但是相同的是都是运行在浏览器上的,而且不同的浏览器效果不同。所以如果你不希望在别人的浏览器上查看不了你的图像,在生成SVG图像时,多在几个主流的浏览器如Chrome、Firefox上运行看看。
但是其格式都是相同的,如下:
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
>
<text x="10" y="300" style="font-size:60px;fill:red" >This is SVG text </text>
</svg>
值得注意的是,SVG对代码的格式跟次序并不敏感,而且对于文字样式的定义可以放或不放在Style
里面,也就是说,下面四个写法是完全等价的:
<text x="10" y="300" style="font-size:60px; fill:red">
<text style="font-size:60px; fill:red" x="10" y="300" >
<text x="10" y="300" style="font-size:60px; fill:red" >
<text x="10" y="300" font-size="60px" fill="red" >
SVG有其他形如text的“控件”如直线等,其语法包括格式和样式等与文本无异,所以就不详细罗列代码了。部分控件有:
除了使用SVG自带的以上控件,你也可以使用路径来画直线椭圆等,其格式为:
<!--
该例子使用两条路径画出两个梯形,如上图左。
-->
<svg>
<path d="M100,25 L200,25 L250,125 L50,125 z" style="fill:pink;stroke:black"/>
<path d="M50,150 h200 l-50,100 h-100 z" style="fill:yellow;stroke:black"/>
</svg>
<!--
该例子使用三条路径画出上图右。
-->
<svg>
<path d="M50,200 Q135.5,210.5 125,125 T200,50 z" style="fill:khaki;stroke:brown"/>
<path d="M50,200 L135.5,210.5 L125,125 L109.5,34.5 L200,50 z" style="fill:none;stroke:grey"/>
<path d="M225,225 h-50 a50,50 0 1,0 50,-50 z" style="fill:lightgreen;stroke:darkgreen"/>
</svg>
使用路径时可以使用的命令有:
需要注意的是以上命令分大小写,大写表示绝对位置,小写表示相对位置。个人建议全部使用大写以提高代码可读性。
除此之外,你还能使用Group
和Style
命令来避免冗余代码以及绘制更加复杂的图型。
<svg>
<g id="my_group_name">
<circle cx="100" cy="120" r="30" style="fill:red"/>
<circle cx="200" cy="120" r="30" style="fill:red"/>
<circle cx="150" cy="150" r="100"
style="fill:none;stroke:blue;stroke-width:3"/>
</g>
</svg>
通过以上代码,我们将三个圆心组成一个组群。所以我们可以通过my_group_name
来获得这个组群并多次绘制这个组群而不需要重复写圆的代码。在显示时它会单独绘制没有任何不同。
我们可以使用Style
来避免需要绘制的图形样式完全一样的重复代码。
<!--
该例子首先对图形的样式进行定义,然后将其实现到需要绘制的图形上,从而避免定义每个图形样式的代码。
-->
<svg>
<style type = "text/css">
rect{
fill: yellow;
fill-opacity: 0.5;
stroke: orange;
stroke-width: 5;
}
text {
fill: red;
font-family: Arial;
font-size: 60px;
text-anchor: middle;
}
</style>
<rect x="50" y="50" width="200" height="100" rx="10" ry="10"/>
<text x="150" y="120">SVG</text>
</svg>
用Style
来定义图形样式的另外一个好处就是将图形的样式与实际实现位置分开,使得修改样式或者位置时,需要阅读和修改的代码量较小。
在对SVG基础控件有一定了解后,我们来看看如果使用SVG来生成更加负责的图形,首先来看看定义(Definitions)。定义是SVG一个相当重要的功能,通过使用定义功能够提高代码可读性以及降低代码的冗余度,实际上Group
和Style
也属于定义。但除了这两个之外,还能定义:
在基础中我们提到能够将样式或者图形组成组群来避免冗余代码,实际上我们也能使用自定义组来生成更为复杂的图形。
实际应用如下:
<!--
该例子中,先定义黑云,然后再重复调用定义图形绘制上图左。
-->
<svg>
<defs>
<g id="Cloud">
<circle cx="24" cy="36" r="15"/>
<circle cx="41" cy="26" r="17"/>
<circle cx="90" cy="40" r="13"/>
<circle cx="105" cy="31" r="13"/>
<ellipse cx="75" cy="20" rx="27" ry="20"/>
<ellipse cx="56" cy="50" rx="25" ry="18"/>
</g>
</defs>
<circle id="Sun" cx="125" cy="140" r="56" style="fill:orange"/>
<use id="SunCloud1" xlink:href="#Cloud" x="20" y="20" />
<use id="SunCloud2" xlink:href="#Cloud" x="0" y="130" />
<use id="SunCloud3" xlink:href="#Cloud" x="150" y="210" />
</svg>
<!--
该例子中,先定义小黑云,然后在用小黑云来定义大黑云,然后再重复调用定义图形绘制上图右。
-->
<svg>
<defs>
<g id="Cloud">
<circle cx="24" cy="36" r="15"/>
<circle cx="41" cy="26" r="17"/>
<circle cx="90" cy="40" r="13"/>
<circle cx="105" cy="31" r="13"/>
<ellipse cx="75" cy="20" rx="27" ry="20"/>
<ellipse cx="56" cy="50" rx="25" ry="18"/>
</g>
<g id="SuperCloud">
<use xlink:href="#Cloud" x="20" y="20" />
<use xlink:href="#Cloud" x="70" y="10" />
<use xlink:href="#Cloud" x="0" y="55" />
<use xlink:href="#Cloud" x="75" y="50" />
</g>
</defs>
<circle id="Sun" cx="125" cy="140" r="56" style="fill:orange"/>
<use id="SunCloud1" xlink:href="#Cloud" x="20" y="20" />
<use id="SunCloud2" xlink:href="#Cloud" x="0" y="130" />
<use id="SunCloud3" xlink:href="#Cloud" x="150" y="210" />
<use id="BigCloud1" xlink:href="#SuperCloud" x="250" y="30" />
<use id="BigCloud2" xlink:href="#SuperCloud" x="240" y="250" />
<use id="BigCloud3" xlink:href="#SuperCloud" x="0" y="280" />
</svg>
裁剪路径实际上是生成一个能够遮挡原矢量图的“蒙版”,其中剪裁的部分透明使得能够看到SVG的图形。
实际应用如下:
<!--
该例子中,首先定义了裁剪窗口的样式,然后使用样式来定义裁剪路径,最后将裁剪路径应用到一张图片(上图左)上生成�右图。
-->
<svg>
<style type="text/css">
text {
font-family: Arial;
font-size: 120px;
font-weight: bold;
}
rect {
fill: black;
fill-opacity: 1.0;
}
</style>
<defs>
<clipPath id="some_text" >
<text x="0" y="130">Clipping</text>
<text x="10" y="220">Window</text>
</clipPath>
</defs>
<image xlink:href="image.jpg"
style="clip-path:url(#some_text)" width="800" height="400"/>
</svg>
有时我们需要生成不断连续(tileable)的图像,这个时候我们就可以使用模式。模式实际上是通过不断重复某个图形/图像的方法来实现的。
实际应用如下:
<svg>
<defs>
<pattern id="dotspattern" x="0" y="0"
patternUnits="userSpaceOnUse" width="495px" height="495px">
<image xlink:href="dots.png" x="0" y="0" width="495px" height="495px"/>
</pattern>
</defs>
<rect style="fill:url(#dotspattern)" width="950" height="700" x="50" y="50" />
</svg>
渐变是SVG中比较重要的一种定义,能够生成很多效果不错的图形。渐变分为线性的(Linear)和径向的(Radial)两种。
实际应用如下:
<svg>
<defs>
<linearGradient id="disc_gradient">
<stop offset="0" style= "stop-color:white"/>
<stop offset="1" style= "stop-color:purple"/> </linearGradient>
</defs>
<ellipse style="fill:url(#disc_gradient)" cx="400" cy="400" rx="50" ry="250" />
<ellipse style="fill:url(#disc_gradient)" cx="400" cy="400" rx="250" ry="50" />
</svg>
滤镜更是SVG的精髓,基本上SVG出色的效果都离不开滤镜的使用,而且滤镜的种类繁多,这里先卖个关子,给个处理后的图形。在下一篇中我们将来仔细研究SVG的滤镜。