Skip to content

Commit ed83a0c

Browse files
committed
support relative image src for GraphvizCmdLineEngine (see #101)
1 parent 90f3447 commit ed83a0c

File tree

4 files changed

+51
-15
lines changed

4 files changed

+51
-15
lines changed

graphviz-java/src/main/java/guru/nidi/graphviz/engine/AbstractJsGraphvizEngine.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,12 @@ public String execute(String src, Options options) {
3131
protected abstract String jsExecute(String jsCall);
3232

3333
protected String jsVizExec(String src, Options options) {
34-
return src.startsWith("render") ? src : ("render('" + jsEscape(src) + "'," + options.toJson(false) + ");");
34+
return src.startsWith("render") ? src : ("render('" + preprocessCode(src) + "'," + options.toJson(false) + ");");
35+
}
36+
37+
protected String preprocessCode(String src) {
38+
if (src.contains("<img")) throw new IllegalArgumentException("Found <img> tag. This is not supported by JS engines. Either use the GraphvizCmdLineEngine or a node with image attribute.");
39+
return jsEscape(src);
3540
}
3641

3742
protected String jsEscape(String js) {

graphviz-java/src/main/java/guru/nidi/graphviz/engine/Graphviz.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,8 +153,8 @@ public Graphviz yInvert(@Nullable Boolean yInvert) {
153153
return new Graphviz(src, rasterizer, width, height, scale, fontAdjust, options.yInvert(yInvert));
154154
}
155155

156-
public Graphviz fontAdjust(double fontAdjust) {
157-
return new Graphviz(src, rasterizer, width, height, scale, fontAdjust, options);
156+
public Graphviz basedir(File basedir) {
157+
return new Graphviz(src, rasterizer, width, height, scale, fontAdjust, options.basedir(basedir));
158158
}
159159

160160
public Graphviz width(int width) {
@@ -169,6 +169,10 @@ public Graphviz scale(double scale) {
169169
return new Graphviz(src, rasterizer, width, height, scale, fontAdjust, options);
170170
}
171171

172+
public Graphviz fontAdjust(double fontAdjust) {
173+
return new Graphviz(src, rasterizer, width, height, scale, fontAdjust, options);
174+
}
175+
172176
public Renderer rasterize(@Nullable Rasterizer rasterizer) {
173177
if (rasterizer == null) {
174178
throw new IllegalArgumentException("The provided rasterizer implementation was not found. "

graphviz-java/src/main/java/guru/nidi/graphviz/engine/GraphvizCmdLineEngine.java

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
import java.nio.file.Files;
2727
import java.nio.file.Path;
2828
import java.util.Optional;
29+
import java.util.regex.Matcher;
30+
import java.util.regex.Pattern;
2931

3032
import static java.util.Locale.ENGLISH;
3133

@@ -36,6 +38,7 @@
3638
*/
3739
public class GraphvizCmdLineEngine extends AbstractGraphvizEngine {
3840
private static final Logger LOG = LoggerFactory.getLogger(AbstractGraphvizEngine.class);
41+
private static final Pattern IMG_SRC = Pattern.compile("<img .*?src\\s*=\\s*['\"]([^'\"]*)");
3942

4043
private final String envPath;
4144
private final CommandRunner cmdRunner;
@@ -74,7 +77,7 @@ public String execute(String src, Options options) {
7477
final File dotfile = getDotFile(tempDirPath.toString());
7578
try (final BufferedWriter bw = new BufferedWriter(
7679
new OutputStreamWriter(new FileOutputStream(dotfile), StandardCharsets.UTF_8))) {
77-
bw.write(src);
80+
bw.write(preprocessCode(src, options));
7881
}
7982
final String command = engine
8083
+ (options.yInvert != null && options.yInvert ? " -y" : "")
@@ -93,6 +96,21 @@ public String execute(String src, Options options) {
9396
}
9497
}
9598

99+
protected String preprocessCode(String src, Options options) {
100+
final Matcher matcher = IMG_SRC.matcher(src);
101+
final StringBuilder s = new StringBuilder();
102+
int last = 0;
103+
while (matcher.find()) {
104+
final String attr = matcher.group(1);
105+
s.append(src, last, matcher.start(1));
106+
s.append((attr.startsWith("http://") || attr.startsWith("https://") || new File(attr).isAbsolute())
107+
? attr
108+
: new File(options.basedir, attr).getAbsolutePath());
109+
last = matcher.end(1);
110+
}
111+
return s.append(src.substring(last)).toString();
112+
}
113+
96114
private String getEngineExecutable(@Nullable Engine engine) {
97115
final String exe = SystemUtils.executableName(engine == null ? "dot" : engine.toString().toLowerCase(ENGLISH));
98116
if (!CommandRunner.isExecutableFound(exe, envPath)) {

graphviz-java/src/main/java/guru/nidi/graphviz/engine/Options.java

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
package guru.nidi.graphviz.engine;
1717

1818
import javax.annotation.Nullable;
19+
import java.io.File;
1920
import java.util.regex.Matcher;
2021
import java.util.regex.Pattern;
2122

@@ -41,24 +42,27 @@ public final class Options {
4142
FORMAT = Pattern.compile("format:'(.*?)'"),
4243
ENGINE = Pattern.compile("engine:'(.*?)'"),
4344
MEMORY = Pattern.compile("totalMemory:'(.*?)'"),
44-
Y_INVERT = Pattern.compile("yInvert:(.*?)");
45+
Y_INVERT = Pattern.compile("yInvert:(.*?)"),
46+
BASE_DIR = Pattern.compile("basedir:'(.*?)'");
4547

4648
final Engine engine;
4749
final Format format;
4850
@Nullable
4951
final Integer totalMemory;
5052
@Nullable
5153
final Boolean yInvert;
54+
final File basedir;
5255

53-
private Options(Engine engine, Format format, @Nullable Integer totalMemory, @Nullable Boolean yInvert) {
56+
private Options(Engine engine, Format format, @Nullable Integer totalMemory, @Nullable Boolean yInvert, File basedir) {
5457
this.engine = engine;
5558
this.format = format;
5659
this.totalMemory = totalMemory;
5760
this.yInvert = yInvert;
61+
this.basedir = basedir;
5862
}
5963

6064
public static Options create() {
61-
return new Options(Engine.DOT, Format.SVG, null, null);
65+
return new Options(Engine.DOT, Format.SVG, null, null, new File("."));
6266
}
6367

6468
public static Options fromJson(String json) {
@@ -70,38 +74,43 @@ public static Options fromJson(String json) {
7074
final boolean hasMemory = memory.find();
7175
final Matcher yInvert = Y_INVERT.matcher(json);
7276
final boolean hasYInvert = yInvert.find();
77+
final Matcher basedir = BASE_DIR.matcher(json);
78+
basedir.find();
79+
7380
return new Options(
7481
Engine.valueOf(engine.group(1)),
7582
Format.valueOf(format.group(1)),
7683
hasMemory ? Integer.parseInt(memory.group(1)) : null,
77-
hasYInvert ? Boolean.parseBoolean(yInvert.group(1)) : null);
84+
hasYInvert ? Boolean.parseBoolean(yInvert.group(1)) : null,
85+
new File(basedir.group(1)));
7886
}
7987

8088
public Options engine(Engine engine) {
81-
return new Options(engine, format, totalMemory, yInvert);
89+
return new Options(engine, format, totalMemory, yInvert, basedir);
8290
}
8391

8492
public Options format(Format format) {
85-
return new Options(engine, format, totalMemory, yInvert);
93+
return new Options(engine, format, totalMemory, yInvert, basedir);
8694
}
8795

8896
public Options totalMemory(@Nullable Integer totalMemory) {
89-
return new Options(engine, format, totalMemory, yInvert);
97+
return new Options(engine, format, totalMemory, yInvert, basedir);
9098
}
9199

92100
public Options yInvert(@Nullable Boolean yInvert) {
93-
return new Options(engine, format, totalMemory, yInvert);
101+
return new Options(engine, format, totalMemory, yInvert, basedir);
94102
}
95103

96-
public Options fontAdjust(double fontAdjust) {
97-
return new Options(engine, format, totalMemory, yInvert);
104+
public Options basedir(File basedir) {
105+
return new Options(engine, format, totalMemory, yInvert, basedir);
98106
}
99107

100108
public String toJson(boolean raw) {
101109
final String form = "format:'" + (raw ? format : format.vizName) + "'";
102110
final String eng = ",engine:'" + (raw ? engine : engine.toString().toLowerCase(ENGLISH)) + "'";
103111
final String mem = totalMemory == null ? "" : (",totalMemory:'" + totalMemory + "'");
104112
final String yInv = yInvert == null ? "" : (",yInvert:" + yInvert);
105-
return "{" + form + eng + mem + yInv + "}";
113+
final String base = ",basedir:'" + basedir.getAbsolutePath() + "'";
114+
return "{" + form + eng + mem + yInv + base + ",images: [ { path: '/Users/nidi/idea/graphviz-java-parent/out2.png', width: '400px', height: '300px' }]}";
106115
}
107116
}

0 commit comments

Comments
 (0)