summaryrefslogtreecommitdiff
path: root/devdocs/elisp/svg-images.html
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2024-04-07 13:41:34 -0500
committerCraig Jennings <c@cjennings.net>2024-04-07 13:41:34 -0500
commit754bbf7a25a8dda49b5d08ef0d0443bbf5af0e36 (patch)
treef1190704f78f04a2b0b4c977d20fe96a828377f1 /devdocs/elisp/svg-images.html
new repository
Diffstat (limited to 'devdocs/elisp/svg-images.html')
-rw-r--r--devdocs/elisp/svg-images.html221
1 files changed, 221 insertions, 0 deletions
diff --git a/devdocs/elisp/svg-images.html b/devdocs/elisp/svg-images.html
new file mode 100644
index 00000000..51a0d24e
--- /dev/null
+++ b/devdocs/elisp/svg-images.html
@@ -0,0 +1,221 @@
+ <h4 class="subsection">SVG Images</h4> <p>SVG (Scalable Vector Graphics) is an XML format for specifying images. SVG images support the following additional image descriptor properties: </p> <dl compact> <dt><code>:foreground <var>foreground</var></code></dt> <dd>
+<p><var>foreground</var>, if non-<code>nil</code>, should be a string specifying a color, which is used as the image’s foreground color. If the value is <code>nil</code>, it defaults to the current face’s foreground color. </p> </dd> <dt><code>:background <var>background</var></code></dt> <dd>
+<p><var>background</var>, if non-<code>nil</code>, should be a string specifying a color, which is used as the image’s background color if the image supports transparency. If the value is <code>nil</code>, it defaults to the current face’s background color. </p> </dd> <dt><code>:css <var>css</var></code></dt> <dd><p><var>css</var>, if non-<code>nil</code>, should be a string specifying the CSS to override the default CSS used when generating the image. </p></dd> </dl> <h4 class="subsubheading">SVG library</h4> <p>If your Emacs build has SVG support, you can create and manipulate these images with the following functions from the <samp>svg.el</samp> library. </p> <dl> <dt id="svg-create">Function: <strong>svg-create</strong> <em>width height &amp;rest args</em>
+</dt> <dd>
+<p>Create a new, empty SVG image with the specified dimensions. <var>args</var> is an argument plist with you can specify following: </p> <dl compact> <dt><code>:stroke-width</code></dt> <dd>
+<p>The default width (in pixels) of any lines created. </p> </dd> <dt><code>:stroke</code></dt> <dd><p>The default stroke color on any lines created. </p></dd> </dl> <p>This function returns an <em>SVG object</em>, a Lisp data structure that specifies an SVG image, and all the following functions work on that structure. The argument <var>svg</var> in the following functions specifies such an SVG object. </p>
+</dd>
+</dl> <dl> <dt id="svg-gradient">Function: <strong>svg-gradient</strong> <em>svg id type stops</em>
+</dt> <dd>
+<p>Create a gradient in <var>svg</var> with identifier <var>id</var>. <var>type</var> specifies the gradient type, and can be either <code>linear</code> or <code>radial</code>. <var>stops</var> is a list of percentage/color pairs. </p> <p>The following will create a linear gradient that goes from red at the start, to green 25% of the way, to blue at the end: </p> <div class="lisp"> <pre class="lisp">(svg-gradient svg "gradient1" 'linear
+ '((0 . "red") (25 . "green") (100 . "blue")))
+</pre>
+</div> <p>The gradient created (and inserted into the SVG object) can later be used by all functions that create shapes. </p>
+</dd>
+</dl> <p>All the following functions take an optional list of keyword parameters that alter the various attributes from their default values. Valid attributes include: </p> <dl compact> <dt><code>:stroke-width</code></dt> <dd>
+<p>The width (in pixels) of lines drawn, and outlines around solid shapes. </p> </dd> <dt><code>:stroke-color</code></dt> <dd>
+<p>The color of lines drawn, and outlines around solid shapes. </p> </dd> <dt><code>:fill-color</code></dt> <dd>
+<p>The color used for solid shapes. </p> </dd> <dt><code>:id</code></dt> <dd>
+<p>The identified of the shape. </p> </dd> <dt><code>:gradient</code></dt> <dd>
+<p>If given, this should be the identifier of a previously defined gradient object. </p> </dd> <dt><code>:clip-path</code></dt> <dd><p>Identifier of a clip path. </p></dd> </dl> <dl> <dt id="svg-rectangle">Function: <strong>svg-rectangle</strong> <em>svg x y width height &amp;rest args</em>
+</dt> <dd>
+<p>Add to <var>svg</var> a rectangle whose upper left corner is at position <var>x</var>/<var>y</var> and whose size is <var>width</var>/<var>height</var>. </p> <div class="lisp"> <pre class="lisp">(svg-rectangle svg 100 100 500 500 :gradient "gradient1")
+</pre>
+</div> </dd>
+</dl> <dl> <dt id="svg-circle">Function: <strong>svg-circle</strong> <em>svg x y radius &amp;rest args</em>
+</dt> <dd><p>Add to <var>svg</var> a circle whose center is at <var>x</var>/<var>y</var> and whose radius is <var>radius</var>. </p></dd>
+</dl> <dl> <dt id="svg-ellipse">Function: <strong>svg-ellipse</strong> <em>svg x y x-radius y-radius &amp;rest args</em>
+</dt> <dd><p>Add to <var>svg</var> an ellipse whose center is at <var>x</var>/<var>y</var>, and whose horizontal radius is <var>x-radius</var> and the vertical radius is <var>y-radius</var>. </p></dd>
+</dl> <dl> <dt id="svg-line">Function: <strong>svg-line</strong> <em>svg x1 y1 x2 y2 &amp;rest args</em>
+</dt> <dd><p>Add to <var>svg</var> a line that starts at <var>x1</var>/<var>y1</var> and extends to <var>x2</var>/<var>y2</var>. </p></dd>
+</dl> <dl> <dt id="svg-polyline">Function: <strong>svg-polyline</strong> <em>svg points &amp;rest args</em>
+</dt> <dd>
+<p>Add to <var>svg</var> a multiple-segment line (a.k.a. “polyline”) that goes through <var>points</var>, which is a list of X/Y position pairs. </p> <div class="lisp"> <pre class="lisp">(svg-polyline svg '((200 . 100) (500 . 450) (80 . 100))
+ :stroke-color "green")
+</pre>
+</div> </dd>
+</dl> <dl> <dt id="svg-polygon">Function: <strong>svg-polygon</strong> <em>svg points &amp;rest args</em>
+</dt> <dd>
+<p>Add a polygon to <var>svg</var> where <var>points</var> is a list of X/Y pairs that describe the outer circumference of the polygon. </p> <div class="lisp"> <pre class="lisp">(svg-polygon svg '((100 . 100) (200 . 150) (150 . 90))
+ :stroke-color "blue" :fill-color "red")
+</pre>
+</div> </dd>
+</dl> <dl> <dt id="svg-path">Function: <strong>svg-path</strong> <em>svg commands &amp;rest args</em>
+</dt> <dd>
+<p>Add the outline of a shape to <var>svg</var> according to <var>commands</var>, see <a href="#SVG-Path-Commands">SVG Path Commands</a>. </p> <p>Coordinates by default are absolute. To use coordinates relative to the last position, or – initially – to the origin, set the attribute <var>:relative</var> to <code>t</code>. This attribute can be specified for the function or for individual commands. If specified for the function, then all commands use relative coordinates by default. To make an individual command use absolute coordinates, set <var>:relative</var> to <code>nil</code>. </p> <div class="lisp"> <pre class="lisp">(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)
+</pre>
+</div> </dd>
+</dl> <dl> <dt id="svg-text">Function: <strong>svg-text</strong> <em>svg text &amp;rest args</em>
+</dt> <dd>
+<p>Add the specified <var>text</var> to <var>svg</var>. </p> <div class="lisp"> <pre class="lisp">(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)
+</pre>
+</div> </dd>
+</dl> <dl> <dt id="svg-embed">Function: <strong>svg-embed</strong> <em>svg image image-type datap &amp;rest args</em>
+</dt> <dd>
+<p>Add an embedded (raster) image to <var>svg</var>. If <var>datap</var> is <code>nil</code>, <var>image</var> should be a file name; otherwise it should be a string containing the image data as raw bytes. <var>image-type</var> should be a <acronym>MIME</acronym> image type, for instance <code>"image/jpeg"</code>. </p> <div class="lisp"> <pre class="lisp">(svg-embed svg "~/rms.jpg" "image/jpeg" nil
+ :width "100px" :height "100px"
+ :x "50px" :y "75px")
+</pre>
+</div> </dd>
+</dl> <dl> <dt id="svg-embed-base-uri-image">Function: <strong>svg-embed-base-uri-image</strong> <em>svg relative-filename &amp;rest args</em>
+</dt> <dd>
+<p>To <var>svg</var> add an embedded (raster) image placed at <var>relative-filename</var>. <var>relative-filename</var> is searched inside <code>file-name-directory</code> of the <code>:base-uri</code> svg image property. <code>:base-uri</code> specifies a (possibly non-existing) file name of the svg image to be created, thus all the embedded files are searched relatively to the <code>:base-uri</code> filename’s directory. If <code>:base-uri</code> is omitted, then filename from where svg image is loaded is used. Using <code>:base-uri</code> improves the performance of embedding large images, comparing to <code>svg-embed</code>, because all the work is done directly by librsvg. </p> <div class="lisp"> <pre class="lisp">;; Embeding /tmp/subdir/rms.jpg and /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)
+</pre>
+</div> </dd>
+</dl> <dl> <dt id="svg-clip-path">Function: <strong>svg-clip-path</strong> <em>svg &amp;rest args</em>
+</dt> <dd>
+<p>Add a clipping path to <var>svg</var>. If applied to a shape via the <var>:clip-path</var> property, parts of that shape which lie outside of the clipping path are not drawn. </p> <div class="lisp"> <pre class="lisp">(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)")
+</pre>
+</div> </dd>
+</dl> <dl> <dt id="svg-node">Function: <strong>svg-node</strong> <em>svg tag &amp;rest args</em>
+</dt> <dd>
+<p>Add the custom node <var>tag</var> to <var>svg</var>. </p> <div class="lisp"> <pre class="lisp">(svg-node svg
+ 'rect
+ :width 300 :height 200 :x 50 :y 100 :fill-color "green")
+</pre>
+</div> </dd>
+</dl> <dl> <dt id="svg-remove">Function: <strong>svg-remove</strong> <em>svg id</em>
+</dt> <dd><p>Remove the element with identifier <code>id</code> from the <code>svg</code>. </p></dd>
+</dl> <dl> <dt id="svg-image">Function: <strong>svg-image</strong> <em>svg</em>
+</dt> <dd><p>Finally, the <code>svg-image</code> takes an SVG object as its argument and returns an image object suitable for use in functions like <code>insert-image</code>. </p></dd>
+</dl> <p>Here’s a complete example that creates and inserts an image with a circle: </p> <div class="lisp"> <pre class="lisp">(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)))
+</pre>
+</div> <h4 class="subsubheading">SVG Path Commands</h4> <p><em>SVG paths</em> allow creation of complex images by combining lines, curves, arcs, and other basic shapes. The functions described below allow invoking SVG path commands from a Lisp program. </p> <dl> <dt id="moveto">Command: <strong>moveto</strong> <em>points</em>
+</dt> <dd>
+<p>Move the pen to the first point in <var>points</var>. Additional points are connected with lines. <var>points</var> is a list of X/Y coordinate pairs. Subsequent <code>moveto</code> commands represent the start of a new <em>subpath</em>. </p> <div class="lisp"> <pre class="lisp">(svg-path svg '((moveto ((200 . 100) (100 . 200) (0 . 100))))
+ :fill "white" :stroke "black")
+</pre>
+</div> </dd>
+</dl> <dl> <dt id="closepath">Command: <strong>closepath</strong>
+</dt> <dd>
+<p>End the current subpath by connecting it back to its initial point. A line is drawn along the connection. </p> <div class="lisp"> <pre class="lisp">(svg-path svg '((moveto ((200 . 100) (100 . 200) (0 . 100)))
+ (closepath)
+ (moveto ((75 . 125) (100 . 150) (125 . 125)))
+ (closepath))
+ :fill "red" :stroke "black")
+</pre>
+</div> </dd>
+</dl> <dl> <dt id="lineto">Command: <strong>lineto</strong> <em>points</em>
+</dt> <dd>
+<p>Draw a line from the current point to the first element in <var>points</var>, a list of X/Y position pairs. If more than one point is specified, draw a polyline. </p>
+<div class="lisp"> <pre class="lisp">(svg-path svg '((moveto ((200 . 100)))
+ (lineto ((100 . 200) (0 . 100))))
+ :fill "yellow" :stroke "red")
+</pre>
+</div> </dd>
+</dl> <dl> <dt id="horizontal-lineto">Command: <strong>horizontal-lineto</strong> <em>x-coordinates</em>
+</dt> <dd>
+<p>Draw a horizontal line from the current point to the first element in <var>x-coordinates</var>. Specifying multiple coordinates is possible, although usually this doesn’t make sense. </p> <div class="lisp"> <pre class="lisp">(svg-path svg '((moveto ((100 . 200)))
+ (horizontal-lineto (300)))
+ :stroke "green")
+</pre>
+</div> </dd>
+</dl> <dl> <dt id="vertical-lineto">Command: <strong>vertical-lineto</strong> <em>y-coordinates</em>
+</dt> <dd>
+<p>Draw vertical lines. </p> <div class="lisp"> <pre class="lisp">(svg-path svg '((moveto ((200 . 100)))
+ (vertical-lineto (300)))
+ :stroke "green")
+</pre>
+</div> </dd>
+</dl> <dl> <dt id="curveto">Command: <strong>curveto</strong> <em>coordinate-sets</em>
+</dt> <dd>
+<p>Using the first element in <var>coordinate-sets</var>, draw a cubic Bézier curve from the current point. If there are multiple coordinate sets, draw a polybezier. Each coordinate set is a list of the form <code>(<var>x1</var> <var>y1</var> <var>x2</var> <var>y2</var> <var>x</var> <var>y</var>)</code>, where (<var>x</var>, <var>y</var>) is the curve’s end point. (<var>x1</var>, <var>y1</var>) and (<var>x2</var>, <var>y2</var>) are control points at the beginning and at the end, respectively. </p> <div class="lisp"> <pre class="lisp">(svg-path svg '((moveto ((100 . 100)))
+ (curveto ((200 100 100 200 200 200)
+ (300 200 0 100 100 100))))
+ :fill "transparent" :stroke "red")
+</pre>
+</div> </dd>
+</dl> <dl> <dt id="smooth-curveto">Command: <strong>smooth-curveto</strong> <em>coordinate-sets</em>
+</dt> <dd>
+<p>Using the first element in <var>coordinate-sets</var>, draw a cubic Bézier curve from the current point. If there are multiple coordinate sets, draw a polybezier. Each coordinate set is a list of the form <code>(<var>x2</var> <var>y2</var> <var>x</var> <var>y</var>)</code>, where (<var>x</var>, <var>y</var>) is the curve’s end point and (<var>x2</var>, <var>y2</var>) is the corresponding control point. The first control point is the reflection of the second control point of the previous command relative to the current point, if that command was <code>curveto</code> or <code>smooth-curveto</code>. Otherwise the first control point coincides with the current point. </p> <div class="lisp"> <pre class="lisp">(svg-path svg '((moveto ((100 . 100)))
+ (curveto ((200 100 100 200 200 200)))
+ (smooth-curveto ((0 100 100 100))))
+ :fill "transparent" :stroke "blue")
+</pre>
+</div> </dd>
+</dl> <dl> <dt id="quadratic-bezier-curveto">Command: <strong>quadratic-bezier-curveto</strong> <em>coordinate-sets</em>
+</dt> <dd>
+<p>Using the first element in <var>coordinate-sets</var>, draw a quadratic Bézier curve from the current point. If there are multiple coordinate sets, draw a polybezier. Each coordinate set is a list of the form <code>(<var>x1</var> <var>y1</var> <var>x</var> <var>y</var>)</code>, where (<var>x</var>, <var>y</var>) is the curve’s end point and (<var>x1</var>, <var>y1</var>) is the control point. </p> <div class="lisp"> <pre class="lisp">(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")
+</pre>
+</div> </dd>
+</dl> <dl> <dt id="smooth-quadratic-bezier-curveto">Command: <strong>smooth-quadratic-bezier-curveto</strong> <em>coordinate-sets</em>
+</dt> <dd>
+<p>Using the first element in <var>coordinate-sets</var>, draw a quadratic Bézier curve from the current point. If there are multiple coordinate sets, draw a polybezier. Each coordinate set is a list of the form <code>(<var>x</var> <var>y</var>)</code>, where (<var>x</var>, <var>y</var>) is the curve’s end point. The control point is the reflection of the control point of the previous command relative to the current point, if that command was <code>quadratic-bezier-curveto</code> or <code>smooth-quadratic-bezier-curveto</code>. Otherwise the control point coincides with the current point. </p> <div class="lisp"> <pre class="lisp">(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")
+</pre>
+</div> </dd>
+</dl> <dl> <dt id="elliptical-arc">Command: <strong>elliptical-arc</strong> <em>coordinate-sets</em>
+</dt> <dd>
+<p>Using the first element in <var>coordinate-sets</var>, draw an elliptical arc from the current point. If there are multiple coordinate sets, draw a sequence of elliptical arcs. Each coordinate set is a list of the form <code>(<var>rx</var> <var>ry</var> <var>x</var> <var>y</var>)</code>, where (<var>x</var>, <var>y</var>) is the end point of the ellipse, and (<var>rx</var>, <var>ry</var>) are its radii. Attributes may be appended to the list: </p> <dl compact> <dt><code>:x-axis-rotation</code></dt> <dd>
+<p>The angle in degrees by which the x-axis of the ellipse is rotated relative to the x-axis of the current coordinate system. </p> </dd> <dt><code>:large-arc</code></dt> <dd>
+<p>If set to <code>t</code>, draw an arc sweep greater than or equal to 180 degrees. Otherwise, draw an arc sweep smaller than or equal to 180 degrees. </p> </dd> <dt><code>:sweep</code></dt> <dd><p>If set to <code>t</code>, draw an arc in <em>positive angle direction</em>. Otherwise, draw it in <em>negative angle direction</em>. </p></dd> </dl> <div class="lisp"> <pre class="lisp">(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)
+</pre>
+</div> </dd>
+</dl><div class="_attribution">
+ <p class="_attribution-p">
+ Copyright &copy; 1990-1996, 1998-2022 Free Software Foundation, Inc. <br>Licensed under the GNU GPL license.<br>
+ <a href="https://www.gnu.org/software/emacs/manual/html_node/elisp/SVG-Images.html" class="_attribution-link">https://www.gnu.org/software/emacs/manual/html_node/elisp/SVG-Images.html</a>
+ </p>
+</div>