diff options
16 files changed, 224 insertions, 123 deletions
diff --git a/build.gradle b/build.gradle index f6a0a4f..c7a64f4 100644 --- a/build.gradle +++ b/build.gradle | |||
@@ -1,13 +1,13 @@ | |||
1 | group 'org.pacien.pandoc.filter.plantuml' | 1 | group 'org.pacien.pandoc.filter.plantuml' |
2 | version '1.0-SNAPSHOT' | 2 | version '1.0-SNAPSHOT' |
3 | 3 | ||
4 | apply plugin: 'java' | 4 | apply plugin: 'kotlin' |
5 | 5 | ||
6 | sourceCompatibility = 1.8 | 6 | sourceCompatibility = 1.8 |
7 | 7 | ||
8 | jar { | 8 | jar { |
9 | manifest { | 9 | manifest { |
10 | attributes 'Main-Class': 'org.pacien.pandoc.filter.plantuml.Filter' | 10 | attributes 'Main-Class': 'org.pacien.pandoc.filter.plantuml.MainKt' |
11 | } | 11 | } |
12 | 12 | ||
13 | from { | 13 | from { |
@@ -23,4 +23,27 @@ dependencies { | |||
23 | testCompile group: 'junit', name: 'junit', version: '4.12' | 23 | testCompile group: 'junit', name: 'junit', version: '4.12' |
24 | compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.9.6' | 24 | compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.9.6' |
25 | compile group: 'net.sourceforge.plantuml', name: 'plantuml', version: '8059' | 25 | compile group: 'net.sourceforge.plantuml', name: 'plantuml', version: '8059' |
26 | compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" | ||
27 | } | ||
28 | |||
29 | buildscript { | ||
30 | ext.kotlin_version = '1.2.51' | ||
31 | repositories { | ||
32 | mavenCentral() | ||
33 | } | ||
34 | dependencies { | ||
35 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" | ||
36 | } | ||
37 | } | ||
38 | |||
39 | compileKotlin { | ||
40 | kotlinOptions { | ||
41 | jvmTarget = "1.8" | ||
42 | } | ||
43 | } | ||
44 | |||
45 | compileTestKotlin { | ||
46 | kotlinOptions { | ||
47 | jvmTarget = "1.8" | ||
48 | } | ||
26 | } | 49 | } |
@@ -3,34 +3,38 @@ pandoc-filter-plantuml | |||
3 | 3 | ||
4 | A Pandoc AST filter rendering PlantUML code blocks into vector diagrams. | 4 | A Pandoc AST filter rendering PlantUML code blocks into vector diagrams. |
5 | 5 | ||
6 | This filter produces TikZ code that must then be rendered using another filter such as | 6 | This filter produces TikZ code that can be rendered as vector diagrams in PDF documents, |
7 | [tikz.py][tikz]. | 7 | or as raster graphics by using another filter such as [tikz.py][tikz]. |
8 | 8 | ||
9 | 9 | ||
10 | Usage | 10 | Example |
11 | ----- | 11 | ------- |
12 | 12 | ||
13 | A PlantUML diagram in an example Pandoc Markdown file `example.md`: | 13 | A PlantUML diagram in an example Pandoc Markdown file `example.md`: |
14 | 14 | ||
15 | ```puml | 15 | --- |
16 | header-includes: \usepackage{tikz} | ||
17 | --- | ||
18 | |||
19 | ```{.puml .centered caption="Courtesy protocol" width=\columnwidth} | ||
16 | @startuml | 20 | @startuml |
17 | Bob->Alice : hello | 21 | Bob->Alice : hello |
22 | Alice->Bob : hi | ||
18 | @enduml | 23 | @enduml |
19 | ``` | 24 | ``` |
20 | 25 | ||
21 | Using the helper scripts [tikz.py][tikz] and `pandoc-filter-plantuml.sh`: | 26 | Using the helper scripts `pandoc-filter-plantuml.sh`: |
22 | 27 | ||
23 | #/bin/sh | 28 | #/bin/sh |
24 | java -jar pandoc-filter-plantuml.jar <&0 | 29 | java -jar pandoc-filter-plantuml.jar <&0 |
25 | 30 | ||
26 | Can be rendered and included as a vector resource in a PDF by running: | 31 | Can be rendered as a vector resource in a PDF by running: |
27 | 32 | ||
28 | % pandoc --filter=pandoc-filter-plantuml.sh \ | 33 | % pandoc --filter=pandoc-filter-plantuml.sh \ |
29 | --filter=tikz.py \ | ||
30 | --output=example.pdf \ | 34 | --output=example.pdf \ |
31 | example.md | 35 | example.md |
32 | 36 | ||
33 | Or as an image in an HTML document with the following command: | 37 | Or as a raster image using [tikz.py][tikz] in an HTML document with the following command: |
34 | 38 | ||
35 | % pandoc --filter=pandoc-filter-plantuml.sh \ | 39 | % pandoc --filter=pandoc-filter-plantuml.sh \ |
36 | --filter=tikz.py \ | 40 | --filter=tikz.py \ |
@@ -38,6 +42,18 @@ Or as an image in an HTML document with the following command: | |||
38 | example.md | 42 | example.md |
39 | 43 | ||
40 | 44 | ||
45 | Options | ||
46 | ------- | ||
47 | |||
48 | The following rendering options can be supplied as [fenced code attributes][fenced_code_attribute]: | ||
49 | |||
50 | * `.centered`: centers the diagram horizontally on the page | ||
51 | * `caption="Some caption"`: adds a figure caption below the diagram | ||
52 | * `label="somelabel`: adds a label to the figure | ||
53 | * `width=\columnwidth` and `height=100pt`: resize the diagram using the `\resizebox` command, | ||
54 | keeping the aspect ration of only one of the two is given | ||
55 | |||
56 | |||
41 | Build | 57 | Build |
42 | ----- | 58 | ----- |
43 | 59 | ||
@@ -54,3 +70,4 @@ See /license.txt | |||
54 | 70 | ||
55 | 71 | ||
56 | [tikz]: https://github.com/jgm/pandocfilters/blob/master/examples/tikz.py | 72 | [tikz]: https://github.com/jgm/pandocfilters/blob/master/examples/tikz.py |
73 | [fenced_code_attribute]: http://pandoc.org/MANUAL.html#fenced-code-blocks | ||
diff --git a/src/main/java/org/pacien/pandoc/filter/plantuml/Filter.java b/src/main/java/org/pacien/pandoc/filter/plantuml/Filter.java deleted file mode 100644 index 66abc2d..0000000 --- a/src/main/java/org/pacien/pandoc/filter/plantuml/Filter.java +++ /dev/null | |||
@@ -1,84 +0,0 @@ | |||
1 | package org.pacien.pandoc.filter.plantuml; | ||
2 | |||
3 | import com.fasterxml.jackson.databind.JsonNode; | ||
4 | import com.fasterxml.jackson.databind.ObjectMapper; | ||
5 | import com.fasterxml.jackson.databind.node.ArrayNode; | ||
6 | import com.fasterxml.jackson.databind.node.ObjectNode; | ||
7 | import com.fasterxml.jackson.databind.node.TextNode; | ||
8 | import net.sourceforge.plantuml.FileFormat; | ||
9 | import net.sourceforge.plantuml.FileFormatOption; | ||
10 | import net.sourceforge.plantuml.SourceStringReader; | ||
11 | |||
12 | import java.io.*; | ||
13 | import java.util.Iterator; | ||
14 | import java.util.stream.Collectors; | ||
15 | |||
16 | final public class Filter { | ||
17 | |||
18 | private static final String BEGIN_TAG = "\\begin{tikzpicture}[yscale=-1]"; | ||
19 | private static final String LINE_SEP = "\n"; | ||
20 | private static final String TYPE_KEY = "t"; | ||
21 | private static final String CONTENT_KEY = "c"; | ||
22 | private static final String CODE_BLOCK_TYPE = "CodeBlock"; | ||
23 | private static final String RAW_BLOCK_TYPE = "RawBlock"; | ||
24 | private static final String PLANTUML_TYPE = "puml"; | ||
25 | private static final String LATEX_TYPE = "latex"; | ||
26 | private static final int META_INDEX = 0; | ||
27 | private static final int META_PROP_INDEX = 1; | ||
28 | private static final int META_PROP_TYPE_INDEX = 0; | ||
29 | private static final int CONTENT_INDEX = 1; | ||
30 | |||
31 | private static String plantumlToLatex(String puml) throws IOException { | ||
32 | try (ByteArrayOutputStream s = new ByteArrayOutputStream()) { | ||
33 | new SourceStringReader(puml).generateImage(s, new FileFormatOption(FileFormat.LATEX_NO_PREAMBLE)); | ||
34 | try (BufferedReader r = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(s.toByteArray())))) { | ||
35 | return BEGIN_TAG + LINE_SEP + r.lines().filter(l -> !l.equals(BEGIN_TAG)).collect(Collectors.joining(LINE_SEP)); | ||
36 | } | ||
37 | } | ||
38 | } | ||
39 | |||
40 | private static void renderPlantumlNode(ObjectNode n) throws IOException { | ||
41 | String puml = n.get(CONTENT_KEY).get(CONTENT_INDEX).asText(); | ||
42 | String tikz = plantumlToLatex(puml); | ||
43 | |||
44 | n.set(TYPE_KEY, TextNode.valueOf(RAW_BLOCK_TYPE)); | ||
45 | ((ArrayNode) n.get(CONTENT_KEY)).removeAll() | ||
46 | .add(TextNode.valueOf(LATEX_TYPE)) | ||
47 | .add(TextNode.valueOf(tikz)); | ||
48 | } | ||
49 | |||
50 | private static boolean isPlantumlNode(JsonNode n) { | ||
51 | return n.path(TYPE_KEY).asText().equals(CODE_BLOCK_TYPE) && | ||
52 | n.path(CONTENT_KEY).path(META_INDEX).path(META_PROP_INDEX).path(META_PROP_TYPE_INDEX).asText().equals(PLANTUML_TYPE); | ||
53 | } | ||
54 | |||
55 | private static void walk(JsonNode n) throws IOException { | ||
56 | if (isPlantumlNode(n)) | ||
57 | renderPlantumlNode((ObjectNode) n); | ||
58 | else if (n.isContainerNode()) | ||
59 | for (Iterator<JsonNode> i = n.elements(); i.hasNext(); ) walk(i.next()); | ||
60 | } | ||
61 | |||
62 | public static void filter(InputStream i, OutputStream o) throws IOException { | ||
63 | ObjectMapper m = new ObjectMapper(); | ||
64 | JsonNode t = m.readTree(i); | ||
65 | if (t != null) { | ||
66 | walk(t); | ||
67 | m.writeValue(o, t); | ||