142 lines
4.7 KiB
Markdown
142 lines
4.7 KiB
Markdown
[[!template id=plugin name=asymptote author="[Peter Simons](http://cryp.to/)"]]
|
|
[[!tag type/widget]]
|
|
|
|
This plugin provides the [[ikiwiki/directive/asymptote]]
|
|
[[ikiwiki/directive]] which allows embedding
|
|
[asymptote](http://asymptote.sourceforge.net/) diagrams in a page.
|
|
|
|
Security implications: asymptote has functions for reading files and
|
|
other dangerous stuff, so enabling this plugin means that everyone who
|
|
can edit your Wiki can also read any file from your hard drive thats
|
|
accessible to the user running Ikiwiki.
|
|
|
|
[[!if test="enabled(asymptote)" then="""
|
|
An example diagram:
|
|
|
|
[[!asymptote src="""
|
|
import geometry;
|
|
unitsize(1cm);
|
|
triangle t = triangle((0,0), (4,0), (0.5,2));
|
|
show(La="$D$", Lb="$E$", Lc="", t);
|
|
dot(t.A^^t.B^^t.C);
|
|
point pD = midpoint(t.BC); dot(pD);
|
|
point pE = midpoint(t.AC); dot(pE);
|
|
draw(pD--pE);
|
|
|
|
point A_ = (pD-t.A)*2+t.A; dot("$A'$", A_, NE);
|
|
draw(t.B--A_--t.C, dashed);
|
|
draw(t.A--A_, dashed);
|
|
|
|
point E_ = midpoint(line(t.B,A_)); dot(Label("$E'$", E_, E));
|
|
draw(E_--pD, dashed);
|
|
"""]]
|
|
"""]]
|
|
|
|
This plugin uses the [[!cpan Digest::SHA]] perl module.
|
|
|
|
The full source code is:
|
|
|
|
#! /usr/bin/perl
|
|
|
|
package IkiWiki::Plugin::asymptote;
|
|
use warnings;
|
|
use strict;
|
|
use Digest::MD5 qw(md5_hex);
|
|
use File::Temp qw(tempdir);
|
|
use HTML::Entities;
|
|
use Encode;
|
|
use IkiWiki 3.00;
|
|
|
|
sub import {
|
|
hook(type => "getsetup", id => "asymptote", call => \&getsetup);
|
|
hook(type => "preprocess", id => "asymptote", call => \&preprocess);
|
|
}
|
|
|
|
sub getsetup () {
|
|
return
|
|
plugin => {
|
|
safe => 1,
|
|
rebuild => undef,
|
|
section => "widget",
|
|
},
|
|
}
|
|
|
|
sub preprocess (@) {
|
|
my %params = @_;
|
|
|
|
my $code = $params{src};
|
|
if (! defined $code && ! length $code) {
|
|
error gettext("missing src attribute");
|
|
}
|
|
return create($code, \%params);
|
|
}
|
|
|
|
sub create ($$$) {
|
|
# This function calls the image generating function and returns
|
|
# the <img .. /> for the generated image.
|
|
my $code = shift;
|
|
my $params = shift;
|
|
|
|
my $digest = md5_hex(Encode::encode_utf8($code));
|
|
|
|
my $imglink= $params->{page} . "/$digest.png";
|
|
my $imglog = $params->{page} . "/$digest.log";
|
|
will_render($params->{page}, $imglink);
|
|
will_render($params->{page}, $imglog);
|
|
|
|
my $imgurl=urlto($imglink, $params->{destpage});
|
|
my $logurl=urlto($imglog, $params->{destpage});
|
|
|
|
if (-e "$config{destdir}/$imglink" ||
|
|
gen_image($code, $digest, $params->{page})) {
|
|
return qq{<img src="$imgurl}
|
|
.(exists $params->{alt} ? qq{" alt="} . $params->{alt} : qq{})
|
|
.qq{" class="asymptote" />};
|
|
}
|
|
else {
|
|
error qq{<a href="$logurl">}.gettext("failed to generate image from code")."</a>";
|
|
}
|
|
}
|
|
|
|
sub gen_image ($$$$) {
|
|
# Actually creates the image.
|
|
my $code = shift;
|
|
my $digest = shift;
|
|
my $imagedir = shift;
|
|
|
|
my $tmp = eval { create_tmp_dir($digest) };
|
|
if (! $@ &&
|
|
writefile("$digest.asy", $tmp, $code) &&
|
|
writefile("$imagedir/$digest.png", $config{destdir}, "") &&
|
|
system("asy -render=2 -offscreen -f png -o $config{destdir}/$imagedir/$digest.png $tmp/$digest.asy &>$tmp/$digest.log") == 0
|
|
) {
|
|
return 1;
|
|
}
|
|
else {
|
|
# store failure log
|
|
my $log="";
|
|
{
|
|
if (open(my $f, '<', "$tmp/$digest.log")) {
|
|
local $/=undef;
|
|
$log = <$f>;
|
|
close($f);
|
|
}
|
|
}
|
|
writefile("$digest.log", "$config{destdir}/$imagedir", $log);
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
sub create_tmp_dir ($) {
|
|
# Create a temp directory, it will be removed when ikiwiki exits.
|
|
my $base = shift;
|
|
|
|
my $template = $base.".XXXXXXXXXX";
|
|
my $tmpdir = tempdir($template, TMPDIR => 1, CLEANUP => 1);
|
|
return $tmpdir;
|
|
}
|
|
|
|
1
|
|
|