Skip to content

Commit

Permalink
use latex to get string bounder (#1914)
Browse files Browse the repository at this point in the history
* tikz: use latex to get string bounder

use !pragma to configure tex and preamble, and the default is like this:

```
!pragma TexSystem xelatex
```

and the template is
```
\documentclass{standalone}
\usepackage{tikz}
\usepackage{aeguill}
% preamble
\begin{document}
```
latex implementations is inspired by matplotlib

* tikz: latex show log if fail

* tikz: add custom preamble to tex

```
!pragma TexPreamble \usepackage{ctex}
```
  • Loading branch information
liudongmiao authored Sep 23, 2024
1 parent 2b47c7a commit 0ef877f
Show file tree
Hide file tree
Showing 8 changed files with 161 additions and 16 deletions.
4 changes: 2 additions & 2 deletions src/net/atmp/ImageBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -333,9 +333,9 @@ private UGraphic createUGraphic(final XDimension2D dim, double scaleFactor, Prag
case VDX:
return new UGraphicVdx(backcolor, colorMapper, stringBounder);
case LATEX:
return new UGraphicTikz(backcolor, colorMapper, stringBounder, scaleFactor, true);
return new UGraphicTikz(backcolor, colorMapper, stringBounder, scaleFactor, true, pragma);
case LATEX_NO_PREAMBLE:
return new UGraphicTikz(backcolor, colorMapper, stringBounder, scaleFactor, false);
return new UGraphicTikz(backcolor, colorMapper, stringBounder, scaleFactor, false, pragma);
case BRAILLE_PNG:
return new UGraphicBraille(backcolor, colorMapper, stringBounder);
case UTXT:
Expand Down
40 changes: 31 additions & 9 deletions src/net/sourceforge/plantuml/FileFormat.java
Original file line number Diff line number Diff line change
Expand Up @@ -224,25 +224,47 @@ public boolean matchesProperty(String propertyName) {

private StringBounder getTikzStringBounder(final TikzFontDistortion tikzFontDistortion) {
return new StringBounderRaw(FileFormat.gg.getFontRenderContext()) {

private final LatexManager latexManager = new LatexManager(tikzFontDistortion.getTexSystem(), tikzFontDistortion.getTexPreamble());

public String toString() {
return "FileFormat::getTikzStringBounder";
}

protected XDimension2D calculateDimensionInternal(UFont font, String text) {
text = text.replace("\t", " ");
final XDimension2D w1 = getJavaDimension(font.goTikz(-1), text);
final XDimension2D w2 = getJavaDimension(font.goTikz(0), text);
final XDimension2D w3 = getJavaDimension(font.goTikz(1), text);
final double factor = (w3.getWidth() - w1.getWidth()) / w2.getWidth();
final double distortion = tikzFontDistortion.getDistortion();
final double magnify = tikzFontDistortion.getMagnify();
final double delta = (w2.getWidth() - w1.getWidth()) * factor * distortion;
return w2.withWidth(Math.max(w1.getWidth(), magnify * w2.getWidth() - delta));
double[] widthHeightDepth = latexManager.getWidthHeightDepth(styleText(font, text));
return new XDimension2D(widthHeightDepth[0], widthHeightDepth[1] + widthHeightDepth[2]);
}

public boolean matchesProperty(String propertyName) {
return false;
}

public double getDescent(UFont font, String text) {
double[] widthHeightDepth = latexManager.getWidthHeightDepth(styleText(font, text));
return widthHeightDepth[2];
}

protected String styleText(UFont font, String text) {
StringBuilder sb = new StringBuilder();
final boolean italic = font.isItalic();
final boolean bold = font.isBold();

if (italic)
sb.append("\\textit{");

if (bold)
sb.append("\\textbf{");

sb.append(text);
if (bold)
sb.append("}");

if (italic)
sb.append("}");

return sb.toString();
}
};
}

Expand Down
98 changes: 98 additions & 0 deletions src/net/sourceforge/plantuml/LatexManager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package net.sourceforge.plantuml;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.nio.file.Files;

public class LatexManager implements AutoCloseable {

private final Process process;
private final PrintWriter writer;
private final BufferedReader reader;

private static final String TEMPLATE_PREFIX = "{" +
"\\catcode`\\^=\\active" +
"\\catcode`\\%=\\active" +
"\\sbox0{{" +
"\\catcode`\\^=\\active\\def^{\\ifmmode\\sp\\else\\^{}\\fi}" +
"\\catcode`\\%=\\active\\def%{\\%}";
private static final String TEMPLATE_SUFFIX = "}}" +
"\\typeout{\\the\\wd0,\\the\\ht0,\\the\\dp0}" +
"}";

public LatexManager(String system, String preamble) {
String command = (system != null && !system.isEmpty()) ? system : "xelatex";
if (!command.endsWith("latex")) {
throw new IllegalArgumentException("command " + command + " is unsupported");
}
try {
File tempDir = Files.createTempDirectory("plantuml-latex-").toFile();
tempDir.deleteOnExit();
this.process = new ProcessBuilder(command, "-halt-on-error")
.directory(tempDir)
.start();
} catch (IOException e) {
throw new RuntimeException(e);
}
this.writer = new PrintWriter(new OutputStreamWriter(this.process.getOutputStream()), true);
this.reader = new BufferedReader(new InputStreamReader(this.process.getInputStream()));
this.writer.println("\\documentclass{standalone}\n" +
"\\usepackage{tikz}\n" +
"\\usepackage{aeguill}\n" +
((preamble != null && !preamble.isEmpty()) ? preamble + "\n" : "") +
"\\begin{document}\n" +
"\\typeout{latex_query_start}");
if (expect("*latex_query_start") == null) {
throw new IllegalArgumentException("please install " + command + ", and package `tikz`, `aeguill` (and `ae`)");
}
}

private String expect(String s) {
StringBuilder sb = new StringBuilder();
while (true) {
String line;
try {
line = this.reader.readLine();
} catch (IOException e) {
throw new RuntimeException(e);
}
if (line == null) {
break;
}
if (line.startsWith("*Missing character")) {
System.err.println(line);
break;
}
sb.append(line);
sb.append(System.lineSeparator());
if (line.startsWith(s)) {
return sb.toString();
}
}
System.err.println(sb);
return null;
}

public double[] getWidthHeightDepth(String s) {
this.writer.println(TEMPLATE_PREFIX + s + TEMPLATE_SUFFIX);
String output = this.expect("*");
if (output == null) {
throw new IllegalArgumentException("cannot get width, height, depth, text: " + s);
}
String[] pts = output.trim().replace("*", "").split(",", 3);
double width = Double.parseDouble(pts[0].replace("pt", ""));
double height = Double.parseDouble(pts[1].replace("pt", ""));
double depth = Double.parseDouble(pts[2].replace("pt", ""));
return new double[] {width, height, depth};
}

@Override
public void close() {
this.process.destroy();
}

}
17 changes: 17 additions & 0 deletions src/net/sourceforge/plantuml/TikzFontDistortion.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,15 @@

import java.util.StringTokenizer;

import net.sourceforge.plantuml.skin.Pragma;

public class TikzFontDistortion {
// ::remove file when __HAXE__

private final double magnify;
private final double distortion;
private String texSystem;
private String texPreamble;

private TikzFontDistortion(double magnify, double distortion) {
this.magnify = magnify;
Expand Down Expand Up @@ -84,4 +88,17 @@ public final double getDistortion() {
return distortion;
}

public String getTexSystem() {
return texSystem;
}

public String getTexPreamble() {
return texPreamble;
}

public void updateFromPragma(Pragma pragma) {
this.texSystem = pragma.getValue("texsystem");
this.texPreamble = pragma.getValue("texpreamble");
}

}
1 change: 1 addition & 0 deletions src/net/sourceforge/plantuml/UmlDiagram.java
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ final protected ImageData exportDiagramNow(OutputStream os, int index, FileForma
throws IOException {

fileFormatOption = fileFormatOption.withTikzFontDistortion(getSkinParam().getTikzFontDistortion());
fileFormatOption.getTikzFontDistortion().updateFromPragma(getPragma());

// ::comment when __CORE__
if (fileFormatOption.getFileFormat() == FileFormat.PDF)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,15 +54,16 @@
import net.sourceforge.plantuml.klimt.shape.UPolygon;
import net.sourceforge.plantuml.klimt.shape.URectangle;
import net.sourceforge.plantuml.klimt.shape.UText;
import net.sourceforge.plantuml.skin.Pragma;
import net.sourceforge.plantuml.tikz.TikzGraphics;
import net.sourceforge.plantuml.url.Url;

public class UGraphicTikz extends AbstractUGraphic<TikzGraphics> implements ClipContainer {

public UGraphicTikz(HColor defaultBackground, ColorMapper colorMapper, StringBounder stringBounder, double scale,
boolean withPreamble) {
boolean withPreamble, Pragma pragma) {
super(stringBounder);
copy(defaultBackground, colorMapper, new TikzGraphics(scale, withPreamble, colorMapper));
copy(defaultBackground, colorMapper, new TikzGraphics(scale, withPreamble, colorMapper, pragma));
register();
}

Expand Down
2 changes: 1 addition & 1 deletion src/net/sourceforge/plantuml/sudoku/GraphicsSudoku.java
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ public ImageData writeImageEps(OutputStream os) throws IOException {

public ImageData writeImageLatex(OutputStream os, FileFormat fileFormat) throws IOException {
final UGraphicTikz ug = new UGraphicTikz(HColors.WHITE, ColorMapper.IDENTITY,
FileFormat.LATEX.getDefaultStringBounder(), 1, fileFormat == FileFormat.LATEX);
FileFormat.LATEX.getDefaultStringBounder(), 1, fileFormat == FileFormat.LATEX, null);
drawInternal(ug);
ug.writeToStream(os, null, -1); // dpi param is not used
return ImageDataSimple.ok();
Expand Down
10 changes: 8 additions & 2 deletions src/net/sourceforge/plantuml/tikz/TikzGraphics.java
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
import net.sourceforge.plantuml.klimt.drawing.eps.EpsGraphics;
import net.sourceforge.plantuml.klimt.geom.USegment;
import net.sourceforge.plantuml.klimt.geom.USegmentType;
import net.sourceforge.plantuml.skin.Pragma;
import net.sourceforge.plantuml.url.Url;
import net.sourceforge.plantuml.utils.Log;
import net.sourceforge.plantuml.version.Version;
Expand All @@ -78,13 +79,15 @@ public class TikzGraphics {
private final double scale;
private String dash = null;
private final ColorMapper mapper;
private final String preamble;

private final Map<Color, String> colornames = new LinkedHashMap<Color, String>();

public TikzGraphics(double scale, boolean withPreamble, ColorMapper mapper) {
public TikzGraphics(double scale, boolean withPreamble, ColorMapper mapper, Pragma pragma) {
this.withPreamble = withPreamble;
this.scale = scale;
this.mapper = mapper;
this.preamble = pragma != null ? pragma.getValue("texpreamble") : null;
}

private final Map<String, Integer> styles = new LinkedHashMap<String, Integer>();
Expand Down Expand Up @@ -158,6 +161,9 @@ public void createData(OutputStream os) throws IOException {
out(os, "\\usetikzlibrary{calc}");
out(os, "\\usepackage{hyperref}");
}
if (preamble != null && !preamble.isEmpty()) {
out(os, preamble);
}
out(os, "\\begin{document}");
}
out(os, "% generated by Plantuml " + Version.versionString(15));
Expand Down Expand Up @@ -321,7 +327,7 @@ public void text(double x, double y, String text, boolean underline, boolean ita
sb.append(",color=");
sb.append(getColorName(color));
}
sb.append("]{");
sb.append(",inner sep=0]{");
if (pendingUrl == null || urlIgnoreText) {
if (underline)
sb.append("\\underline{");
Expand Down

0 comments on commit 0ef877f

Please sign in to comment.