]> sipb.mit.edu Git - ikiwiki.git/blob - doc/plugins/asymptote.mdwn
f67cc2b0c64d17b252b734f712c5229be38d8ddf
[ikiwiki.git] / doc / plugins / asymptote.mdwn
1 [[!template id=plugin name=asymptote author="PeterSimons"]]
2
3 This plugin provides the [[ikiwiki/directive/asymptote]]
4 [[ikiwiki/directive]] which allows embedding
5 [asymptote](http://asymptote.sourceforge.net/) diagrams in a page.
6
7 Security implications: asymptote has functions for reading files and
8 other dangerous stuff, so enabling this plugin means that everyone who
9 can edit your Wiki can also read any file from your hard drive thats
10 accessible to the user running Ikiwiki. 
11
12 [[!if test="enabled(asymptote)" then="""
13 An example diagram:
14
15 [[!asymptote src="""
16 import geometry;
17 unitsize(1cm);
18 triangle t = triangle((0,0), (4,0), (0.5,2));
19 show(La="$D$", Lb="$E$", Lc="", t);
20 dot(t.A^^t.B^^t.C);
21 point pD = midpoint(t.BC); dot(pD);
22 point pE = midpoint(t.AC); dot(pE);
23 draw(pD--pE);
24
25 point A_ = (pD-t.A)*2+t.A; dot("$A'$", A_, NE);
26 draw(t.B--A_--t.C, dashed);
27 draw(t.A--A_, dashed);
28
29 point E_ = midpoint(line(t.B,A_)); dot(Label("$E'$", E_, E));
30 draw(E_--pD, dashed);
31 """]]
32 """]]
33
34 This plugin uses the [[!cpan Digest::SHA]] perl module.
35
36 The full source code is:
37
38         #! /usr/bin/perl
39
40         package IkiWiki::Plugin::asymptote;
41         use warnings;
42         use strict;
43         use Digest::MD5 qw(md5_hex);
44         use File::Temp qw(tempdir);
45         use HTML::Entities;
46         use Encode;
47         use IkiWiki 3.00;
48
49         sub import {
50                 hook(type => "getsetup", id => "asymptote", call => \&getsetup);
51                 hook(type => "preprocess", id => "asymptote", call => \&preprocess);
52         }
53
54         sub getsetup () {
55                 return
56                         plugin => {
57                                 safe => 1,
58                                 rebuild => undef,
59                                 section => "widget",
60                         },
61         }
62
63         sub preprocess (@) {
64                 my %params = @_;
65
66                 my $code = $params{src};
67                 if (! defined $code && ! length $code) {
68                         error gettext("missing src attribute");
69                 }
70                 return create($code, \%params);
71         }
72
73         sub create ($$$) {
74                 # This function calls the image generating function and returns
75                 # the <img .. /> for the generated image.
76                 my $code = shift;
77                 my $params = shift;
78
79                 my $digest = md5_hex(Encode::encode_utf8($code));
80
81                 my $imglink= $params->{page} . "/$digest.png";
82                 my $imglog =  $params->{page} .  "/$digest.log";
83                 will_render($params->{page}, $imglink);
84                 will_render($params->{page}, $imglog);
85
86                 my $imgurl=urlto($imglink, $params->{destpage});
87                 my $logurl=urlto($imglog, $params->{destpage});
88
89                 if (-e "$config{destdir}/$imglink" ||
90                     gen_image($code, $digest, $params->{page})) {
91                         return qq{<img src="$imgurl}
92                                 .(exists $params->{alt} ? qq{" alt="} . $params->{alt} : qq{})
93                                 .qq{" class="asymptote" />};
94                 }
95                 else {
96                         error qq{<a href="$logurl">}.gettext("failed to generate image from code")."</a>";
97                 }
98         }
99
100         sub gen_image ($$$$) {
101                 # Actually creates the image.
102                 my $code = shift;
103                 my $digest = shift;
104                 my $imagedir = shift;
105
106                 my $tmp = eval { create_tmp_dir($digest) };
107                 if (! $@ &&
108                     writefile("$digest.asy", $tmp, $code) &&
109                     writefile("$imagedir/$digest.png", $config{destdir}, "") &&
110                     system("asy -render=2 -offscreen -f png -o $config{destdir}/$imagedir/$digest.png $tmp/$digest.asy &>$tmp/$digest.log") == 0
111                    ) {
112                         return 1;
113                 }
114                 else {
115                         # store failure log
116                         my $log="";
117                         {
118                                 if (open(my $f, '<', "$tmp/$digest.log")) {
119                                         local $/=undef;
120                                         $log = <$f>;
121                                         close($f);
122                                 }
123                         }
124                         writefile("$digest.log", "$config{destdir}/$imagedir", $log);
125
126                         return 0;
127                 }
128         }
129
130         sub create_tmp_dir ($) {
131                 # Create a temp directory, it will be removed when ikiwiki exits.
132                 my $base = shift;
133
134                 my $template = $base.".XXXXXXXXXX";
135                 my $tmpdir = tempdir($template, TMPDIR => 1, CLEANUP => 1);
136                 return $tmpdir;
137         }
138
139         1
140