SVG(可缩放矢量图形)是用于描述图像的 XML 格式。 SVG 图像支持以下附加图像描述符属性:
:foreground foreground若 foreground 非 nil,则应为表示颜色的字符串,用作图像前景色。若值为 nil,则默认使用当前文本视觉样式的前景色。
:background background若 background 非 nil,则应为表示颜色的字符串,在图像支持透明时用作图像背景色。若值为 nil,则默认使用当前文本视觉样式的背景色。
:css css若 css 非 nil,则应为字符串,指定用于覆盖生成图像时默认样式的 CSS。
若你编译的 Emacs 带有 SVG 支持,可使用 svg.el 库中的以下函数创建与操作这类图像。
创建指定尺寸的新空白 SVG 图像。 args 为属性参数列表,可指定以下内容:
:stroke-width所创建所有线条的默认宽度(单位:像素)。
:stroke所创建所有线条的默认描边颜色。
该函数返回一个 SVG 对象,即用于描述 SVG 图像的 Lisp 数据结构,后续所有函数均操作该结构。以下函数中的参数 svg 均指代此类 SVG 对象。
在 svg 中创建标识符为 id 的渐变。type 指定渐变类型,可为 linear(线性)或 radial(径向)。stops 为百分比/颜色对构成的列表。
以下示例创建一个线性渐变:起点为红色,25% 处为绿色,终点为蓝色:
(svg-gradient svg "gradient1" 'linear
'((0 . "red") (25 . "green") (100 . "blue")))
创建并插入到 SVG 对象中的渐变,可被后续所有创建图形的函数使用。
以下所有函数均接受可选关键字参数列表,用于修改各类属性的默认值。可用属性包括:
:stroke-width所绘制线条与实心图形轮廓的宽度(单位:像素)。
:stroke-color所绘制线条与实心图形轮廓的颜色。
:fill-color实心图形的填充颜色。
:id图形的标识符。
:gradient若指定,应为预先定义的渐变对象标识符。
:clip-path裁剪路径的标识符。
向 svg 添加矩形,其左上角坐标为 x/y,尺寸为 width/height。
(svg-rectangle svg 100 100 500 500 :gradient "gradient1")
向 svg 添加圆形,其圆心坐标为 x/y,半径为 radius。
向 svg 添加椭圆,其圆心坐标为 x/y,水平半径为 x-radius,垂直半径为 y-radius。
向 svg 添加直线,起点为 x1/y1,终点为 x2/y2。
向 svg 添加多段线(又称 “折线(polyline)”),路径经过 points,即 X/Y 坐标对构成的列表。
(svg-polyline svg '((200 . 100) (500 . 450) (80 . 100))
:stroke-color "green")
向 svg 添加多边形,其中 points 为描述多边形外轮廓的 X/Y 坐标对列表。
(svg-polygon svg '((100 . 100) (200 . 150) (150 . 90))
:stroke-color "blue" :fill-color "red")
根据 commands 向 svg 添加图形轮廓,参见 SVG Path Commands。
坐标默认为绝对坐标。若要使用相对于上一点(初始时为原点)的坐标,可将属性 :relative 设为 t。该属性可作用于整个函数或单个命令。若作用于函数,则所有命令默认使用相对坐标。若要让单个命令使用绝对坐标,可将其 :relative 设为 nil。
Add the outline of a shape to svg according to commands, see SVG Path Commands.
(svg-path svg '((moveto ((100 . 100))) (lineto ((200 . 0) (0 . 200) (-200 . 0))) (lineto ((100 . 100)) :relative nil)) :stroke-color "blue" :fill-color "lightblue" :relative t)
向 svg 添加指定文本 text。
(svg-text svg "This is a text" :font-size "40" :font-weight "bold" :stroke "black" :fill "white" :font-family "impact" :letter-spacing "4pt" :x 300 :y 400 :stroke-width 1)
向 svg 添加嵌入的(光栅)图像。若 datap 为 nil,则 image 应为文件名;否则应为包含原始字节图像数据的字符串。image-type 应为 MIME 图像类型,例如 "image/jpeg"。
(svg-embed svg "~/rms.jpg" "image/jpeg" nil
:width "100px" :height "100px"
:x "50px" :y "75px")
向 svg 添加位于 relative-filename 的嵌入(光栅)图像。relative-filename 会在 SVG 图像属性 :base-uri 所在的 file-name-directory 中查找。
:base-uri 指定待创建 SVG 图像的文件名(可不存在),因此所有嵌入文件均相对于该文件名所在目录查找。若省略 :base-uri,则使用加载 SVG 图像的源文件名。与 svg-embed 相比,使用 :base-uri 可提升嵌入大图像的性能,因为所有工作均由 librsvg 直接完成。
;; 嵌入 /tmp/subdir/rms.jpg 与 /tmp/another/rms.jpg
(svg-embed-base-uri-image svg "subdir/rms.jpg"
:width "100px" :height "100px"
:x "50px" :y "75px")
(svg-embed-base-uri-image svg "another/rms.jpg"
:width "100px" :height "100px"
:x "75px" :y "50px")
(svg-image svg :scale 1.0
:base-uri "/tmp/dummy"
:width 175 :height 175)
向 svg 添加裁剪路径。若通过 :clip-path 属性应用到某个图形,该图形位于裁剪路径外的部分将不会被绘制。
(let ((clip-path (svg-clip-path svg :id "foo")))
(svg-circle clip-path 200 200 175))
(svg-rectangle svg 50 50 300 300
:fill-color "red"
:clip-path "url(#foo)")
向 svg 添加自定义节点 tag。
(svg-node svg
'rect
:width 300 :height 200 :x 50 :y 100 :fill-color "green")
从 svg 中移除标识符为 id 的元素。
最后,svg-image 接受 SVG 对象作为参数,并返回可用于 insert-image 等函数的图像对象。
以下是完整示例,创建并插入一个带圆形的图像:
(let ((svg (svg-create 400 400 :stroke-width 10)))
(svg-gradient svg "gradient1" 'linear '((0 . "red") (100 . "blue")))
(svg-circle svg 200 200 100 :gradient "gradient1"
:stroke-color "green")
(insert-image (svg-image svg)))
SVG 路径可通过组合直线、曲线、圆弧等基础图形创建复杂图像。下文所述函数支持在 Lisp 程序中调用 SVG 路径命令。
将画笔移动到 points 中的第一个点。后续点由直线连接。points 为 X/Y 坐标对列表。后续的 moveto 命令代表新 子路径(subpath) 的起点。
(svg-path svg '((moveto ((200 . 100) (100 . 200) (0 . 100))))
:fill "white" :stroke "black")
将当前子路径连接回起点以结束该路径,并绘制连接线。
(svg-path svg '((moveto ((200 . 100) (100 . 200) (0 . 100)))
(closepath)
(moveto ((75 . 125) (100 . 150) (125 . 125)))
(closepath))
:fill "red" :stroke "black")
从当前点向 points 中的第一个点绘制直线,points 为 X/Y 坐标对列表。若指定多个点,则绘制折线。
(svg-path svg '((moveto ((200 . 100)))
(lineto ((100 . 200) (0 . 100))))
:fill "yellow" :stroke "red")
从当前点向 x-coordinates 中的第一个点绘制水平线。可指定多个坐标,但通常无实际意义。
(svg-path svg '((moveto ((100 . 200)))
(horizontal-lineto (300)))
:stroke "green")
绘制竖直线。
(svg-path svg '((moveto ((200 . 100)))
(vertical-lineto (300)))
:stroke "green")
使用 coordinate-sets 中的第一个元素,从当前点绘制三次贝塞尔曲线。若存在多组坐标,则绘制多段贝塞尔曲线。每组坐标格式为 (x1 y1 x2 y2 x y),其中 (x, y) 为曲线终点,(x1, y1) 与 (x2, y2) 分别为起点与终点的控制点。
(svg-path svg '((moveto ((100 . 100)))
(curveto ((200 100 100 200 200 200)
(300 200 0 100 100 100))))
:fill "transparent" :stroke "red")
使用 coordinate-sets 中的第一个元素,从当前点绘制三次贝塞尔曲线。若存在多组坐标,则绘制多段贝塞尔曲线。每组坐标格式为 (x2 y2 x y),其中 (x, y) 为曲线终点,(x2, y2) 为对应控制点。若上一条命令为 curveto 或 smooth-curveto,则第一个控制点为上一条命令第二个控制点相对于当前点的对称点;否则第一个控制点与当前点重合。
(svg-path svg '((moveto ((100 . 100)))
(curveto ((200 100 100 200 200 200)))
(smooth-curveto ((0 100 100 100))))
:fill "transparent" :stroke "blue")
使用 coordinate-sets 中的第一个元素,从当前点绘制二次贝塞尔曲线。若存在多组坐标,则绘制多段贝塞尔曲线。每组坐标格式为 (x1 y1 x y),其中 (x, y) 为曲线终点,(x1, y1) 为控制点。
(svg-path svg '((moveto ((200 . 100)))
(quadratic-bezier-curveto ((300 100 300 200)))
(quadratic-bezier-curveto ((300 300 200 300)))
(quadratic-bezier-curveto ((100 300 100 200)))
(quadratic-bezier-curveto ((100 100 200 100))))
:fill "transparent" :stroke "pink")
使用 coordinate-sets 中的第一个元素,从当前点绘制二次贝塞尔曲线。若存在多组坐标,则绘制多段贝塞尔曲线。每组坐标格式为 (x y),其中 (x, y) 为曲线终点。若上一条命令为 quadratic-bezier-curveto 或 smooth-quadratic-bezier-curveto,则控制点为上一条命令控制点相对于当前点的对称点;否则控制点与当前点重合。
(svg-path svg '((moveto ((200 . 100)))
(quadratic-bezier-curveto ((300 100 300 200)))
(smooth-quadratic-bezier-curveto ((200 300)))
(smooth-quadratic-bezier-curveto ((100 200)))
(smooth-quadratic-bezier-curveto ((200 100))))
:fill "transparent" :stroke "lightblue")
使用 coordinate-sets 中的第一个元素,从当前点绘制椭圆弧。若存在多组坐标,则绘制连续椭圆弧。每组坐标格式为 (rx ry x y),其中 (x, y) 为椭圆终点,(rx, ry) 为椭圆半径。可向列表附加以下属性:
:x-axis-rotation椭圆 X 轴相对于当前坐标系 X 轴的旋转角度(单位:度)。
:large-arc若设为 t,则绘制大于或等于 180 度的弧;否则绘制小于或等于 180 度的弧。
:sweep若设为 t,则沿 正角度方向(positive angle direction) 绘制弧;否则沿 负角度方向(negative angle direction) 绘制。
(svg-path svg '((moveto ((200 . 250)))
(elliptical-arc ((75 75 200 350))))
:fill "transparent" :stroke "red")
(svg-path svg '((moveto ((200 . 250)))
(elliptical-arc ((75 75 200 350 :large-arc t))))
:fill "transparent" :stroke "green")
(svg-path svg '((moveto ((200 . 250)))
(elliptical-arc ((75 75 200 350 :sweep t))))
:fill "transparent" :stroke "blue")
(svg-path svg '((moveto ((200 . 250)))
(elliptical-arc ((75 75 200 350 :large-arc t
:sweep t))))
:fill "transparent" :stroke "gray")
(svg-path svg '((moveto ((160 . 100)))
(elliptical-arc ((40 100 80 0)))
(elliptical-arc ((40 100 -40 -70
:x-axis-rotation -120)))
(elliptical-arc ((40 100 -40 70
:x-axis-rotation -240))))
:stroke "pink" :fill "lightblue"
:relative t)