tags are rendered as diagrams and saved in the images directory and a new HTML file is produced with the appropriate tags.");
cmdLnOptions.addOption("T", "transparent", false, "Causes the diagram to be rendered on a transparent background. Overrides --background.");
diff --git a/src/java/org/stathissideris/ascii2image/core/ConversionOptions.java b/src/java/org/stathissideris/ascii2image/core/ConversionOptions.java
index 52a7eb1..2157267 100644
--- a/src/java/org/stathissideris/ascii2image/core/ConversionOptions.java
+++ b/src/java/org/stathissideris/ascii2image/core/ConversionOptions.java
@@ -29,9 +29,9 @@
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
+import java.util.Objects;
/**
- *
* @author Efstathios Sideris
*/
public class ConversionOptions {
@@ -49,8 +49,10 @@ public void setDebug(boolean value) {
public ConversionOptions() {
}
- /** Parse a color from a 6- or 8-digit hex string. For example, FF0000 is red.
- * If eight digits, last two digits are alpha. */
+ /**
+ * Parse a color from a 6- or 8-digit hex string. For example, FF0000 is red.
+ * If eight digits, last two digits are alpha.
+ */
public static Color parseColor(String hexString) {
if (hexString.length() == 6) {
return new Color(Integer.parseInt(hexString, 16));
@@ -80,6 +82,7 @@ public ConversionOptions(CommandLine cmdLine) throws UnsupportedEncodingExceptio
processingOptions.setAllCornersAreRound(cmdLine.hasOption("round-corners"));
processingOptions.setPerformSeparationOfCommonEdges(!cmdLine.hasOption("no-separation"));
+ processingOptions.enableLaTeXmath(cmdLine.hasOption("latex-math"));
renderingOptions.setAntialias(!cmdLine.hasOption("no-antialias"));
renderingOptions.setFixedSlope(cmdLine.hasOption("fixed-slope"));
@@ -107,6 +110,10 @@ public ConversionOptions(CommandLine cmdLine) throws UnsupportedEncodingExceptio
processingOptions.setCharacterEncoding(encoding);
}
+ if (cmdLine.hasOption("latex"))
+ processingOptions.enableLaTeXmath(
+ Objects.equals(cmdLine.getOptionValue("latex", "no"), "yes"));
+
if (cmdLine.hasOption("svg")) {
renderingOptions.setImageType(RenderingOptions.ImageType.SVG);
}
diff --git a/src/java/org/stathissideris/ascii2image/core/ProcessingOptions.java b/src/java/org/stathissideris/ascii2image/core/ProcessingOptions.java
index 6d56f9f..c7b52dc 100644
--- a/src/java/org/stathissideris/ascii2image/core/ProcessingOptions.java
+++ b/src/java/org/stathissideris/ascii2image/core/ProcessingOptions.java
@@ -35,6 +35,7 @@ public class ProcessingOptions {
private boolean overwriteFiles = false;
private boolean performSeparationOfCommonEdges = true;
private boolean allCornersAreRound = false;
+ private boolean latexMathEnabled = false;
public static final int USE_TAGS = 0;
public static final int RENDER_TAGS = 1;
@@ -237,5 +238,11 @@ public CustomShapeDefinition getFromCustomShapes(String tagName) {
return customShapes.get(tagName);
}
+ public void enableLaTeXmath(boolean b) {
+ this.latexMathEnabled = b;
+ }
+ public boolean isLaTeXmathEnabled() {
+ return this.latexMathEnabled;
+ }
}
diff --git a/src/java/org/stathissideris/ascii2image/graphics/BitmapRenderer.java b/src/java/org/stathissideris/ascii2image/graphics/BitmapRenderer.java
index 4ff40fe..28b13d6 100644
--- a/src/java/org/stathissideris/ascii2image/graphics/BitmapRenderer.java
+++ b/src/java/org/stathissideris/ascii2image/graphics/BitmapRenderer.java
@@ -338,16 +338,19 @@ public RenderedImage render(Diagram diagram, BufferedImage image, RenderingOptio
Iterator textIt = diagram.getTextObjects().iterator();
while (textIt.hasNext()) {
DiagramText text = textIt.next();
- g2.setFont(text.getFont());
- if (text.hasOutline()) {
- g2.setColor(text.getOutlineColor());
- g2.drawString(text.getText(), text.getXPos() + 1, text.getYPos());
- g2.drawString(text.getText(), text.getXPos() - 1, text.getYPos());
- g2.drawString(text.getText(), text.getXPos(), text.getYPos() + 1);
- g2.drawString(text.getText(), text.getXPos(), text.getYPos() - 1);
- }
- g2.setColor(text.getColor());
- g2.drawString(text.getText(), text.getXPos(), text.getYPos());
+ text.drawOn(g2);
+ /*
+ g2.setFont(text.getFont());
+ if(text.hasOutline()){
+ g2.setColor(text.getOutlineColor());
+ g2.drawString(text.getText(), text.getXPos() + 1, text.getYPos());
+ g2.drawString(text.getText(), text.getXPos() - 1, text.getYPos());
+ g2.drawString(text.getText(), text.getXPos(), text.getYPos() + 1);
+ g2.drawString(text.getText(), text.getXPos(), text.getYPos() - 1);
+ }
+ g2.setColor(text.getColor());
+ g2.drawString(text.getText(), text.getXPos(), text.getYPos());
+ */
}
if (options.renderDebugLines() || DEBUG_LINES) {
@@ -387,20 +390,10 @@ public TextCanvas(ArrayList textObjects) {
}
public void paint(Graphics g) {
- Graphics g2 = (Graphics2D) g;
+ Graphics2D g2 = (Graphics2D) g;
Iterator textIt = textObjects.iterator();
while (textIt.hasNext()) {
- DiagramText text = (DiagramText) textIt.next();
- g2.setFont(text.getFont());
- if (text.hasOutline()) {
- g2.setColor(text.getOutlineColor());
- g2.drawString(text.getText(), text.getXPos() + 1, text.getYPos());
- g2.drawString(text.getText(), text.getXPos() - 1, text.getYPos());
- g2.drawString(text.getText(), text.getXPos(), text.getYPos() + 1);
- g2.drawString(text.getText(), text.getXPos(), text.getYPos() - 1);
- }
- g2.setColor(text.getColor());
- g2.drawString(text.getText(), text.getXPos(), text.getYPos());
+ textIt.next().drawOn(g2);
}
}
}
diff --git a/src/java/org/stathissideris/ascii2image/graphics/Diagram.java b/src/java/org/stathissideris/ascii2image/graphics/Diagram.java
index 80cd53c..342f4a8 100644
--- a/src/java/org/stathissideris/ascii2image/graphics/Diagram.java
+++ b/src/java/org/stathissideris/ascii2image/graphics/Diagram.java
@@ -35,7 +35,6 @@
import java.util.Iterator;
/**
- *
* @author Efstathios Sideris
*/
public class Diagram {
@@ -53,54 +52,53 @@ public class Diagram {
/**
- *
*
An outline of the inner workings of this very important (and monstrous)
* constructor is presented here. Boundary processing is the first step
* of the process:
*
*
- *
Copy the grid into a work grid and remove all type-on-line
- * and point markers from the work grid
- *
Split grid into distinct shapes by plotting the grid
- * onto an AbstractionGrid and its getDistinctShapes() method.
- *
Find all the possible boundary sets of each of the
- * distinct shapes. This can produce duplicate shapes (if the boundaries
- * are the same when filling from the inside and the outside).
- *
Remove duplicate boundaries.
- *
Remove obsolete boundaries. Obsolete boundaries are the ones that are
- * the sum of their parts when plotted as filled shapes. (see method
- * removeObsoleteShapes())
- *
Separate the found boundary sets to open, closed or mixed
- * (See CellSet class on how its done).
- *
Are there any closed boundaries?
- *
- *
YES. Subtract all the closed boundaries from each of the
- * open ones. That should convert the mixed shapes into open.
- *
NO. In this (harder) case, we use the method
- * breakTrulyMixedBoundaries() of CellSet to break boundaries
- * into open and closed shapes (would work in any case, but it's
- * probably slower than the other method). This method is based
- * on tracing from the lines' ends and splitting when we get to
- * an intersection.
- *
- *
- *
If we had to eliminate any mixed shapes, we separate the found
- * boundary sets again to open, closed or mixed.
+ *
Copy the grid into a work grid and remove all type-on-line
+ * and point markers from the work grid
+ *
Split grid into distinct shapes by plotting the grid
+ * onto an AbstractionGrid and its getDistinctShapes() method.
+ *
Find all the possible boundary sets of each of the
+ * distinct shapes. This can produce duplicate shapes (if the boundaries
+ * are the same when filling from the inside and the outside).
+ *
Remove duplicate boundaries.
+ *
Remove obsolete boundaries. Obsolete boundaries are the ones that are
+ * the sum of their parts when plotted as filled shapes. (see method
+ * removeObsoleteShapes())
+ *
Separate the found boundary sets to open, closed or mixed
+ * (See CellSet class on how its done).
+ *
Are there any closed boundaries?
+ *
+ *
YES. Subtract all the closed boundaries from each of the
+ * open ones. That should convert the mixed shapes into open.
+ *
NO. In this (harder) case, we use the method
+ * breakTrulyMixedBoundaries() of CellSet to break boundaries
+ * into open and closed shapes (would work in any case, but it's
+ * probably slower than the other method). This method is based
+ * on tracing from the lines' ends and splitting when we get to
+ * an intersection.
+ *
+ *
+ *
If we had to eliminate any mixed shapes, we separate the found
+ * boundary sets again to open, closed or mixed.
*
*
*
At this stage, the boundary processing is all complete and we
* proceed with using those boundaries to create the shapes:
*
*
- *
Create closed shapes.
- *
Create open shapes. That's when the line end corrections are
- * also applied, concerning the positioning of the ends of lines
- * see methods connectEndsToAnchors() and moveEndsToCellEdges() of
- * DiagramShape.
- *
Assign color codes to closed shapes.
- *
Assign extended markup tags to closed shapes.
- *
Create arrowheads.
- *
Create point markers.
+ *
Create closed shapes.
+ *
Create open shapes. That's when the line end corrections are
+ * also applied, concerning the positioning of the ends of lines
+ * see methods connectEndsToAnchors() and moveEndsToCellEdges() of
+ * DiagramShape.
+ *
Assign color codes to closed shapes.
+ *
Assign extended markup tags to closed shapes.
+ *
Create arrowheads.
+ *
Create point markers.
*
*
*
Finally, the text processing occurs: [pending]
@@ -565,11 +563,12 @@ else if (type == CellSet.TYPE_MIXED)
int maxX = getCellMaxX(lastCell);
DiagramText textObject;
+ boolean laTeXmathEnabled = options.processingOptions.isLaTeXmathEnabled();
if (FontMeasurer.instance().getWidthFor(string, font) > maxX - minX) { //does not fit horizontally
Font lessWideFont = FontMeasurer.instance().getFontFor(maxX - minX, string);
- textObject = new DiagramText(minX, y, string, lessWideFont);
+ textObject = new DiagramText(minX, y, string, lessWideFont, laTeXmathEnabled);
} else
- textObject = new DiagramText(minX, y, string, font);
+ textObject = new DiagramText(minX, y, string, font, laTeXmathEnabled);
textObject.centerVerticallyBetween(getCellMinY(cell), getCellMaxY(cell));
@@ -648,7 +647,6 @@ public ArrayList getAllDiagramShapes() {
* when plotted as filled shapes.
*
* @return true if it removed any obsolete.
- *
*/
private boolean removeObsoleteShapes(TextGrid grid, ArrayList sets) {
if (DEBUG)
diff --git a/src/java/org/stathissideris/ascii2image/graphics/DiagramText.java b/src/java/org/stathissideris/ascii2image/graphics/DiagramText.java
index 47767e7..58675aa 100644
--- a/src/java/org/stathissideris/ascii2image/graphics/DiagramText.java
+++ b/src/java/org/stathissideris/ascii2image/graphics/DiagramText.java
@@ -1,34 +1,48 @@
/**
* ditaa - Diagrams Through Ascii Art
- *
+ *
* ditaa is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
- *
+ *
* ditaa is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
- *
+ *
* You should have received a copy of the GNU Lesser General Public
* License along with ditaa. If not, see .
*/
package org.stathissideris.ascii2image.graphics;
+import org.scilab.forge.jlatexmath.TeXConstants;
+import org.scilab.forge.jlatexmath.TeXFormula;
+import org.scilab.forge.jlatexmath.TeXIcon;
+import org.stathissideris.ascii2image.core.RenderingOptions;
+import org.stathissideris.ascii2image.text.StringUtils;
+
+import javax.swing.JLabel;
import java.awt.Color;
import java.awt.Font;
+import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
+import java.util.Iterator;
+import java.util.regex.Pattern;
+import java.util.stream.Stream;
+
+import static org.stathissideris.ascii2image.graphics.SVGBuilder.colorToHex;
/**
- *
* @author Efstathios Sideris
*/
public class DiagramText extends DiagramComponent {
- public static final Color DEFAULT_COLOR = Color.black;
+ public static final Color DEFAULT_COLOR = Color.black;
+ public static final Pattern TEXT_SPLITTING_REGEX = Pattern.compile("([^$]+|\\$[^$]*\\$)");
+ private final boolean latexMathEnabled;
private String text;
private Font font;
@@ -38,7 +52,7 @@ public class DiagramText extends DiagramComponent {
private boolean hasOutline = false;
private Color outlineColor = Color.white;
- public DiagramText(int x, int y, String text, Font font) {
+ public DiagramText(int x, int y, String text, Font font, boolean latexMathEnabled) {
if (text == null)
throw new IllegalArgumentException("DiagramText cannot be initialised with a null string");
if (font == null)
@@ -48,6 +62,7 @@ public DiagramText(int x, int y, String text, Font font) {
this.yPos = y;
this.text = text;
this.font = font;
+ this.latexMathEnabled = latexMathEnabled;
}
public void centerInBounds(Rectangle2D bounds) {
@@ -95,6 +110,76 @@ public String getText() {
return text;
}
+ public void drawOn(Graphics2D g2) {
+ g2.setFont(this.getFont());
+ if (this.hasOutline()) {
+ g2.setColor(this.getOutlineColor());
+ Stream.of(1, -1)
+ .peek(d -> draw(g2, this.getXPos() + d, this.getYPos(), this.getColor()))
+ .peek(d -> draw(g2, this.getXPos(), this.getYPos() + d, this.getColor()))
+ .forEach(d -> {
+ });
+ }
+ g2.setColor(this.getColor());
+ draw(g2, this.getXPos(), this.getYPos(), getColor());
+ }
+
+ private void draw(Graphics2D g2, int xPos, int yPos, Color color) {
+ Iterator i = StringUtils.createTextSplitter(TEXT_SPLITTING_REGEX, this.getText());
+ int x = xPos;
+ while (i.hasNext()) {
+ String text = i.next();
+ if (isTeXFormula(text))
+ x += drawTeXFormula(g2,
+ text,
+ x, yPos, color,
+ font.getSize());
+ else
+ x += drawString(g2,
+ text,
+ x, yPos, color,
+ font);
+ }
+ }
+
+ public void renderOn(StringBuilder svgBuildingBuffer, RenderingOptions options) {
+ if (this.hasOutline()) {
+ Stream.of(1, -1)
+ .peek(d -> render(svgBuildingBuffer, options,
+ this.getXPos() + d, this.getYPos(),
+ this.getOutlineColor()))
+ .peek(d -> render(svgBuildingBuffer, options,
+ this.getXPos(), this.getYPos() + d,
+ this.getOutlineColor()))
+ .forEach(d -> {
+ });
+ }
+ render(svgBuildingBuffer, options, this.getXPos(), this.getYPos(), getColor());
+ }
+
+ private void render(StringBuilder svgBuildingBuffer, RenderingOptions options,
+ int xPos, int yPos, Color color) {
+ Iterator i = StringUtils.createTextSplitter(TEXT_SPLITTING_REGEX, this.getText());
+ int x = xPos;
+ while (i.hasNext()) {
+ String token = i.next();
+ if (isTeXFormula(token))
+ x += renderTeXFormula(svgBuildingBuffer, options,
+ token,
+ x, yPos, color,
+ font.getSize());
+ else
+ x += renderString(svgBuildingBuffer, options,
+ token,
+ x, yPos, color,
+ font);
+ }
+ }
+
+ private boolean isTeXFormula(String text) {
+ return this.latexMathEnabled && text.startsWith("$");
+ }
+
/**
* @return
*/
@@ -188,5 +273,50 @@ public void setOutlineColor(Color outlineColor) {
this.outlineColor = outlineColor;
}
+ public static int drawTeXFormula(Graphics2D g2, String text, int x, int y, Color color, float fontSize) {
+ TeXFormula formula = new TeXFormula(text);
+ TeXIcon icon = formula.new TeXIconBuilder()
+ .setStyle(TeXConstants.STYLE_DISPLAY)
+ .setSize(fontSize)
+ .build();
+ /* 12 is a magic number to adjust vertical position */
+ icon.paintIcon(new JLabel() {{
+ setForeground(color);
+ }}, g2, x, y - 12);
+ return icon.getIconWidth();
+ }
+ private static int drawString(Graphics2D g2, String text, int xPos, int yPos, Color color, Font font) {
+ g2.setColor(color);
+ g2.setFont(font);
+ g2.drawString(text, xPos, yPos);
+ return FontMeasurer.instance().getWidthFor(text, font);
+ }
+
+ @SuppressWarnings("unused")
+ private static int renderTeXFormula(StringBuilder svgBuildingBuffer, RenderingOptions options, String text, int x, int yPos, Color color, int size) {
+ throw new UnsupportedOperationException("Rendering LaTeX formula in .svg format is not currently supported.");
+ }
+
+ private static int renderString(StringBuilder svgBuildingBuffer, RenderingOptions options, String text, int xPos, int yPos, Color color, Font font) {
+ String TEXT_ELEMENT = " " +
+ "\n";
+ /* Prefer normal font weight
+ if (font.isBold()) {
+ style = " font-weight='bold'";
+ }
+ */
+
+ svgBuildingBuffer.append(
+ String.format(TEXT_ELEMENT,
+ xPos,
+ yPos,
+ options.getFontFamily(),
+ font.getSize(),
+ colorToHex(color),
+ text
+ )
+ );
+ return FontMeasurer.instance().getWidthFor(text, font);
+ }
}
diff --git a/src/java/org/stathissideris/ascii2image/graphics/SVGBuilder.java b/src/java/org/stathissideris/ascii2image/graphics/SVGBuilder.java
index 83c1031..2247620 100644
--- a/src/java/org/stathissideris/ascii2image/graphics/SVGBuilder.java
+++ b/src/java/org/stathissideris/ascii2image/graphics/SVGBuilder.java
@@ -5,7 +5,6 @@
import org.stathissideris.ascii2image.core.ShapeAreaComparator;
import java.awt.Color;
-import java.awt.Font;
import java.awt.geom.GeneralPath;
import java.awt.geom.PathIterator;
import java.util.ArrayList;
@@ -289,56 +288,10 @@ private void backgroundLayer() {
}
private void renderTexts() {
-
- for (DiagramText diagramText : diagram.getTextObjects()) {
-
- Font font = diagramText.getFont();
- String text = diagramText.getText();
-
- int xPos = diagramText.getXPos();
- int yPos = diagramText.getYPos();
-
- renderText(text, xPos, yPos, font, diagramText.getColor());
-
- if (diagramText.hasOutline()) {
-
- Color outlineColor = diagramText.getOutlineColor();
-
- renderText(text, xPos + 1, yPos, font, outlineColor);
- renderText(text, xPos - 1, yPos, font, outlineColor);
- renderText(text, xPos, yPos + 1, font, outlineColor);
- renderText(text, xPos, yPos - 1, font, outlineColor);
-
- }
- }
-
- }
-
- private void renderText(String text, int xPos, int yPos, Font font, Color color) {
-
- String TEXT_ELEMENT = " " +
- "\n";
-
- /* Prefer normal font weight
- if (font.isBold()) {
- style = " font-weight='bold'";
- }
- */
-
- layer3.append(
- String.format(TEXT_ELEMENT,
- xPos,
- yPos,
- options.getFontFamily(),
- font.getSize(),
- colorToHex(color),
- text
- )
- );
-
+ diagram.getTextObjects().forEach(each -> each.renderOn(this.layer3, this.options));
}
- private static String colorToHex(Color color) {
+ public static String colorToHex(Color color) {
return String.format("#%s%s%s",
toHex(color.getRed()),
toHex(color.getGreen()),
diff --git a/src/java/org/stathissideris/ascii2image/text/StringUtils.java b/src/java/org/stathissideris/ascii2image/text/StringUtils.java
index 9a073b6..7f37c70 100644
--- a/src/java/org/stathissideris/ascii2image/text/StringUtils.java
+++ b/src/java/org/stathissideris/ascii2image/text/StringUtils.java
@@ -1,23 +1,28 @@
/**
* ditaa - Diagrams Through Ascii Art
- *
+ *
* ditaa is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
- *
+ *
* ditaa is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
- *
+ *
* You should have received a copy of the GNU Lesser General Public
* License along with ditaa. If not, see .
*/
package org.stathissideris.ascii2image.text;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
/**
* @author sideris
*
@@ -61,7 +66,6 @@ public static boolean isBlank(String s) {
}
/**
- *
* Converts the first character of string into a capital letter
*
* @param string
@@ -173,4 +177,27 @@ public static void main(String[] args) {
}
+
+ public static Iterator createTextSplitter(Pattern pattern, CharSequence s) {
+ return new Iterator() {
+ Pattern regex = pattern;
+ CharSequence rest = s;
+
+ @Override
+ public boolean hasNext() {
+ return rest.length() > 0;
+ }
+
+ @Override
+ public String next() {
+ Matcher m = regex.matcher(rest);
+ if (m.find()) {
+ String ret = m.group(1);
+ rest = rest.subSequence(ret.length(), rest.length());
+ return ret;
+ }
+ throw new NoSuchElementException();
+ }
+ };
+ }
}
diff --git a/src/java/org/stathissideris/ascii2image/text/TextGrid.java b/src/java/org/stathissideris/ascii2image/text/TextGrid.java
index 564a408..04ba75f 100644
--- a/src/java/org/stathissideris/ascii2image/text/TextGrid.java
+++ b/src/java/org/stathissideris/ascii2image/text/TextGrid.java
@@ -1,18 +1,18 @@
/**
* ditaa - Diagrams Through Ascii Art
- *
+ *
* ditaa is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
- *
+ *
* ditaa is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
- *
+ *
* You should have received a copy of the GNU Lesser General Public
* License along with ditaa. If not, see .
*/
@@ -32,20 +32,27 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.List;
import java.util.Stack;
+import java.util.function.IntUnaryOperator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import static java.util.stream.Collectors.toList;
+import static org.stathissideris.ascii2image.text.StringUtils.createTextSplitter;
+
/**
*
* @author Efstathios Sideris
*/
-public class TextGrid {
-
- private static final boolean DEBUG = false;
+public class TextGrid{
+ private static final boolean DEBUG = false;
+ private static final char PLAIN_MODE = 'P';
+ public static final char LATEX_MODE = 'L';
private ArrayList rows;
+ private List modeRows;
private static char[] boundaries = { '/', '\\', '|', '-', '*', '=', ':' };
private static char[] undisputableBoundaries = { '|', '-', '*', '=', ':' };
@@ -91,6 +98,48 @@ public class TextGrid {
markupTags.add("o");
}
+ private void updateModeRows() {
+ // Collectors.toList creates ArrayList and you see no performance penalty
+ // caused by using LinkedList here.
+ this.modeRows = this.rows.stream().map(TextGrid::transformRowToModeRow).collect(toList());
+ }
+
+ public static String transformRowToModeRow(CharSequence row) {
+ StringBuilder b = new StringBuilder();
+ row.chars().map(new IntUnaryOperator() {
+ /**
+ * This field hold current mode of a cell in the grid.
+ * Only 2 values can be assigned, which are 'P' and 'L'.
+ * They respectively represent 'Plain', which is normal ditaa mode, and 'LaTeX', which is LaTeX
+ * formula mode.
+ */
+ int cur = PLAIN_MODE;
+
+ @Override
+ public int applyAsInt(int operand) {
+ if (cur == PLAIN_MODE) {
+ if (operand == '$') {
+ cur = LATEX_MODE;
+ return LATEX_MODE;
+ }
+ return PLAIN_MODE;
+ } else if (cur == LATEX_MODE) {
+ if (operand == '$') {
+ cur = PLAIN_MODE;
+ return LATEX_MODE;
+ }
+ return this.cur;
+ }
+ throw new IllegalStateException();
+ }
+ }).forEach(c -> b.append((char) c));
+ String ret = b.toString();
+ if (ret.endsWith("L"))
+ if (row.charAt(row.length() - 1) != '$')
+ throw new IllegalArgumentException("LaTex mode was started but not finished.");
+ return ret;
+ }
+
public void addToMarkupTags(Collection tags) {
markupTags.addAll(tags);
}
@@ -113,6 +162,7 @@ public static void main(String[] args) throws Exception {
public TextGrid() {
rows = new ArrayList();
+ this.updateModeRows();
}
public TextGrid(int width, int height) {
@@ -120,6 +170,7 @@ public TextGrid(int width, int height) {
rows = new ArrayList();
for (int i = 0; i < height; i++)
rows.add(new StringBuilder(space));
+ this.updateModeRows();
}
public static TextGrid makeSameSizeAs(TextGrid grid) {
@@ -132,6 +183,7 @@ public TextGrid(TextGrid otherGrid) {
for (StringBuilder row : otherGrid.getRows()) {
rows.add(new StringBuilder(row));
}
+ this.updateModeRows();
}
public void clear() {
@@ -373,7 +425,7 @@ public void replacePointMarkersOnLine() {
char c = get(xi, yi);
Cell cell = new Cell(xi, yi);
if (StringUtils.isOneOf(c, pointMarkers)
- && isStarOnLine(cell)) {
+ && isStarOnLine(cell) && isInPlainMode(cell)) {
boolean isOnHorizontalLine = false;
if (StringUtils.isOneOf(get(cell.getEast()), horizontalLines))
@@ -411,6 +463,8 @@ public CellSet getPointMarkersOnLine() {
int height = getHeight();
for (int yi = 0; yi < height; yi++) {
for (int xi = 0; xi < width; xi++) {
+ if (!isInPlainMode(xi, yi))
+ continue;
char c = get(xi, yi);
if (StringUtils.isOneOf(c, pointMarkers)
&& isStarOnLine(new Cell(xi, yi))) {
@@ -424,21 +478,30 @@ && isStarOnLine(new Cell(xi, yi))) {
public void replaceHumanColorCodes() {
int height = getHeight();
- for (int y = 0; y < height; y++) {
- String row = rows.get(y).toString();
- Iterator it = humanColorCodes.keySet().iterator();
- while (it.hasNext()) {
- String humanCode = (String) it.next();
- String hexCode = (String) humanColorCodes.get(humanCode);
- if (hexCode != null) {
- humanCode = "c" + humanCode;
- hexCode = "c" + hexCode;
- row = row.replaceAll(humanCode, hexCode);
- rows.set(y, new StringBuilder(row)); //TODO: this is not the most efficient way to do this
- row = rows.get(y).toString();
- }
- }
+ for (int y = 0; y < height; y++)
+ rows.set(y, replaceHumanColorCodes(y, rows.get(y)));
+ }
+
+ private StringBuilder replaceHumanColorCodes(int rowIndex, StringBuilder in) {
+ Pattern p = Pattern.compile("(c.{0,3}|[^c]+)");
+ StringBuilder ret = new StringBuilder(in.length());
+ Iterator i = createTextSplitter(p, in);
+ while (i.hasNext()) {
+ String next = i.next();
+ if (isInPlainMode(ret.length(), rowIndex) && looksColorCode(next)) {
+ String replacement = humanColorCodes.get(next.substring(1, 4));
+ if (replacement != null)
+ ret.append(String.format("c%s", replacement));
+ else
+ ret.append(next);
+ } else
+ ret.append(next);
}
+ return ret;
+ }
+
+ private static boolean looksColorCode(String word) {
+ return word.length() >= 4 && word.startsWith("c");
}
@@ -664,7 +727,8 @@ public void removeBoundaries() {
Iterator it = toBeRemoved.iterator();
while (it.hasNext()) {
Cell cell = (Cell) it.next();
- set(cell, ' ');
+ if (isInPlainMode(cell))
+ set(cell, ' ');
}
}
@@ -693,6 +757,8 @@ public ArrayList findColorCodes() {
for (int yi = 0; yi < height; yi++) {
for (int xi = 0; xi < width - 3; xi++) {
Cell cell = new Cell(xi, yi);
+ if (!isInPlainMode(cell))
+ continue;
String s = getStringAt(cell, 4);
Matcher matcher = colorCodePattern.matcher(s);
if (matcher.matches()) {
@@ -719,6 +785,8 @@ public ArrayList findMarkupTags() {
int height = getHeight();
for (int y = 0; y < height; y++) {
for (int x = 0; x < width - 3; x++) {
+ if (!isInPlainMode(x, y))
+ continue;
Cell cell = new Cell(x, y);
char c = get(cell);
if (c == '{') {
@@ -798,6 +866,8 @@ public boolean isBoundary(int x, int y) {
}
public boolean isBoundary(Cell cell) {
+ if (!isInPlainMode(cell))
+ return false;
char c = get(cell.x, cell.y);
if (0 == c)
return false;
@@ -828,14 +898,14 @@ public static boolean isHorizontalLine(char c) {
}
public boolean isHorizontalLine(Cell cell) {
- return isHorizontalLine(cell.x, cell.y);
+ return isHorizontalLine(cell.x, cell.y) && isInPlainMode(cell);
}
public boolean isHorizontalLine(int x, int y) {
char c = get(x, y);
if (0 == c)
return false;
- return StringUtils.isOneOf(c, horizontalLines);
+ return StringUtils.isOneOf(c, horizontalLines) && isInPlainMode(x, y);
}
public static boolean isVerticalLine(char c) {
@@ -843,7 +913,7 @@ public static boolean isVerticalLine(char c) {
}
public boolean isVerticalLine(Cell cell) {
- return isVerticalLine(cell.x, cell.y);
+ return isVerticalLine(cell.x, cell.y) && isInPlainMode(cell);
}
public boolean isVerticalLine(int x, int y) {
@@ -864,15 +934,15 @@ public boolean isLinesEnd(int x, int y) {
* @return
*/
public boolean isLinesEnd(Cell cell) {
- return matchesAny(cell, GridPatternGroup.linesEndCriteria);
+ return matchesAny(cell, GridPatternGroup.linesEndCriteria) && isInPlainMode(cell);
}
public boolean isVerticalLinesEnd(Cell cell) {
- return matchesAny(cell, GridPatternGroup.verticalLinesEndCriteria);
+ return matchesAny(cell, GridPatternGroup.verticalLinesEndCriteria) && isInPlainMode(cell);
}
public boolean isHorizontalLinesEnd(Cell cell) {
- return matchesAny(cell, GridPatternGroup.horizontalLinesEndCriteria);
+ return matchesAny(cell, GridPatternGroup.horizontalLinesEndCriteria) && isInPlainMode(cell);
}
@@ -881,7 +951,7 @@ public boolean isPointCell(Cell cell) {
isCorner(cell)
|| isIntersection(cell)
|| isStub(cell)
- || isLinesEnd(cell));
+ || isLinesEnd(cell)) && isInPlainMode(cell);
}
@@ -964,20 +1034,21 @@ public boolean isArrowhead(Cell cell) {
}
public boolean isNorthArrowhead(Cell cell) {
- return get(cell) == '^';
+ return get(cell) == '^' && isInPlainMode(cell);
}
public boolean isEastArrowhead(Cell cell) {
- return get(cell) == '>';
+ return get(cell) == '>' && isInPlainMode(cell);
}
public boolean isWestArrowhead(Cell cell) {
- return get(cell) == '<';
+ return get(cell) == '<' && isInPlainMode(cell);
}
public boolean isSouthArrowhead(Cell cell) {
return (get(cell) == 'v' || get(cell) == 'V')
- && isVerticalLine(cell.getNorth());
+ && isVerticalLine(cell.getNorth())
+ && isInPlainMode(cell);
}
// unicode for bullets
@@ -1000,7 +1071,8 @@ public boolean isBullet(Cell cell) {
if ((c == 'o' || c == '*')
&& isBlank(cell.getEast())
&& isBlank(cell.getWest())
- && Character.isLetterOrDigit(get(cell.getEast().getEast())))
+ && Character.isLetterOrDigit(get(cell.getEast().getEast()))
+ && isInPlainMode(cell))
return true;
return false;
}
@@ -1716,68 +1788,73 @@ public boolean initialiseWithLines(ArrayList lines, ProcessingOpt
done = true;
}
rows = new ArrayList(lines.subList(0, i + 2));
+ this.updateModeRows();
+ try {
- if (options != null)
- fixTabs(options.getTabSize());
- else
- fixTabs(options.DEFAULT_TAB_SIZE);
+ if (options != null)
+ fixTabs(options.getTabSize());
+ else
+ fixTabs(options.DEFAULT_TAB_SIZE);
- // make all lines of equal length
- // add blank outline around the buffer to prevent fill glitch
- // convert tabs to spaces (or remove them if setting is 0)
+ // make all lines of equal length
+ // add blank outline around the buffer to prevent fill glitch
+ // convert tabs to spaces (or remove them if setting is 0)
- int blankBorderSize = 2;
+ int blankBorderSize = 2;
- int maxLength = 0;
- int index = 0;
+ int maxLength = 0;
+ int index = 0;
- String encoding = null;
- if (options != null)
- encoding = options.getCharacterEncoding();
+ String encoding = null;
+ if (options != null)
+ encoding = options.getCharacterEncoding();
- Iterator it = rows.iterator();
- while (it.hasNext()) {
- String row = it.next().toString();
- if (encoding != null) {
- byte[] bytes = row.getBytes();
- row = new String(bytes, encoding);
+ Iterator it = rows.iterator();
+ while (it.hasNext()) {
+ String row = it.next().toString();
+ if (encoding != null) {
+ byte[] bytes = row.getBytes();
+ row = new String(bytes, encoding);
+ }
+ if (row.length() > maxLength)
+ maxLength = row.length();
+ rows.set(index, new StringBuilder(row));
+ index++;
}
- if (row.length() > maxLength)
- maxLength = row.length();
- rows.set(index, new StringBuilder(row));
- index++;
- }
- it = rows.iterator();
- ArrayList newRows = new ArrayList();
- //TODO: make the following depend on blankBorderSize
+ it = rows.iterator();
+ ArrayList newRows = new ArrayList();
+ //TODO: make the following depend on blankBorderSize
- StringBuilder topBottomRow =
- new StringBuilder(StringUtils.repeatString(" ", maxLength + blankBorderSize * 2));
+ StringBuilder topBottomRow =
+ new StringBuilder(StringUtils.repeatString(" ", maxLength + blankBorderSize * 2));
- newRows.add(topBottomRow);
- newRows.add(topBottomRow);
- while (it.hasNext()) {
- StringBuilder row = it.next();
+ newRows.add(topBottomRow);
+ newRows.add(topBottomRow);
+ while (it.hasNext()) {
+ StringBuilder row = it.next();
- if (row.length() < maxLength) {
- String borderString = StringUtils.repeatString(" ", blankBorderSize);
- StringBuilder newRow = new StringBuilder();
+ if (row.length() < maxLength) {
+ String borderString = StringUtils.repeatString(" ", blankBorderSize);
+ StringBuilder newRow = new StringBuilder();
- newRow.append(borderString);
- newRow.append(row);
- newRow.append(StringUtils.repeatString(" ", maxLength - row.length()));
- newRow.append(borderString);
+ newRow.append(borderString);
+ newRow.append(row);
+ newRow.append(StringUtils.repeatString(" ", maxLength - row.length()));
+ newRow.append(borderString);
- newRows.add(newRow);
- } else { //TODO: why is the following line like that?
- newRows.add(new StringBuilder(" ").append(row).append(" "));
+ newRows.add(newRow);
+ } else { //TODO: why is the following line like that?
+ newRows.add(new StringBuilder(" ").append(row).append(" "));
+ }
}
+ //TODO: make the following depend on blankBorderSize
+ newRows.add(topBottomRow);
+ newRows.add(topBottomRow);
+ rows = newRows;
+ } finally {
+ this.updateModeRows();
}
- //TODO: make the following depend on blankBorderSize
- newRows.add(topBottomRow);
- newRows.add(topBottomRow);
- rows = newRows;
replaceBullets();
replaceHumanColorCodes();
@@ -1820,6 +1897,14 @@ protected ArrayList getRows() {
return rows;
}
+ private boolean isInPlainMode(Cell cell) {
+ return this.modeRows.get(cell.y).charAt(cell.x) == PLAIN_MODE;
+ }
+
+ private boolean isInPlainMode(int x, int y) {
+ return this.modeRows.get(y).charAt(x) == PLAIN_MODE;
+ }
+
public class CellColorPair {
public CellColorPair(Cell cell, Color color) {
this.cell = cell;
diff --git a/test-resources/text/art-latexmath-1.txt b/test-resources/text/art-latexmath-1.txt
new file mode 100644
index 0000000..f1f2a58
--- /dev/null
+++ b/test-resources/text/art-latexmath-1.txt
@@ -0,0 +1,38 @@
+
+$Box_1$ $Box^2$
++---------------------+ +------+ /---------\
+|$\sum_{i=0}^{n}x^i$ | |$cBLU$| | |
+| +--->|cRED +-=-+cGRE$C_k$|
+|{io} | |cXYZ | |{o} |
++----------+----------+ +---+--+ \---------/
+ | |
+ | :
+ | V
+ | +-------------------+
+ +---------->*$A_i$ hello $B^i$ |
+ | +----+
+ | |c8FA|
+ +--------------+----+
+
+$|Set| = o-*-Freunde-*-nicht=*=diese-=-*- * töne$
+
+o Quick brown fox jumps over
+* a lazy dog.
+
+$Q_u^i$, $C_k$, $B_r^{own}$, $F_{ox}$ jumps
+
+over a lazy $d\cdot\frac{o}{g}$.
+
+
+$\forall x \in X, \quad \exists y \leq \epsilon$
+
+
+$\sin A \cos B =$
+
+ $ \frac{1}{2}\left[ \sin(A-B)+\sin(A+B) \right]$
+
+
+$\frac{d}{dx}\left( \int_{0}^{x} f(u)\,du\right)=f(x).$
+
+
+ $v \sim \mathcal{N} (m,\sigma^2)$
\ No newline at end of file
diff --git a/test/java/sandbox/Sandbox.java b/test/java/sandbox/Sandbox.java
new file mode 100644
index 0000000..1bb98e2
--- /dev/null
+++ b/test/java/sandbox/Sandbox.java
@@ -0,0 +1,145 @@
+package sandbox;
+
+import org.junit.Test;
+import org.scilab.forge.jlatexmath.TeXConstants;
+import org.scilab.forge.jlatexmath.TeXFormula;
+import org.scilab.forge.jlatexmath.TeXIcon;
+import org.stathissideris.ascii2image.graphics.DiagramText;
+import org.stathissideris.ascii2image.text.StringUtils;
+import org.stathissideris.ascii2image.text.TextGrid;
+
+import javax.imageio.ImageIO;
+import javax.swing.JLabel;
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.Insets;
+import java.awt.image.BufferedImage;
+import java.awt.image.DataBuffer;
+import java.io.File;
+import java.io.IOException;
+import java.util.Iterator;
+
+import static com.github.dakusui.crest.Crest.asString;
+import static com.github.dakusui.crest.Crest.assertThat;
+
+public class Sandbox {
+ @Test
+ public void latexMath() throws IOException {
+ String latex = "$\\sum_{i=0}^{n}x^i$";
+ TeXFormula formula = new TeXFormula(latex);
+
+ // Note: Old interface for creating icons:
+ // TeXIcon icon = formula.createTeXIcon(TeXConstants.STYLE_DISPLAY, 20);
+ // Note: New interface using builder pattern (inner class):
+ TeXIcon icon = formula.new TeXIconBuilder().setStyle(TeXConstants.STYLE_DISPLAY).setSize(20)
+ .build();
+
+ icon.setInsets(new Insets(5, 5, 5, 5));
+
+ BufferedImage image = new BufferedImage(icon.getIconWidth(), icon.getIconHeight(),
+ BufferedImage.TYPE_INT_ARGB);
+ Graphics2D g2 = image.createGraphics();
+ g2.setColor(Color.white);
+ g2.fillRect(0, 0, icon.getIconWidth(), icon.getIconHeight());
+ JLabel jl = new JLabel();
+ jl.setForeground(new Color(0, 0, 0));
+ icon.paintIcon(jl, g2, 0, 0);
+ File file = new File("target/Example1.png");
+ ImageIO.write(image, "png", file.getAbsoluteFile());
+ }
+
+ @Test
+ public void latexMath2() throws IOException {
+ String latex = "$\\sum_{i=0}^{n}x^i$";
+
+ BufferedImage image = new BufferedImage(
+ 640, 480,
+ BufferedImage.TYPE_INT_ARGB
+ );
+ DiagramText.drawTeXFormula(image.createGraphics(), latex, 0, 0, Color.black, 20);
+ File file = new File("target/Example1.png");
+ ImageIO.write(image, "png", file.getAbsoluteFile());
+ }
+
+ /**
+ * This method is based on a discussion How to compare images for similarity made in the Stackoverflow.com
+ * If 2 images are identical, this method will return 1.0.
+ *
+ * @param fileA input image A
+ * @param fileB input image B
+ * @return The similarity.
+ */
+ public static double compareImages(File fileA, File fileB) {
+ double percentage = 0;
+ try {
+ // take buffer data from both image files //
+ BufferedImage biA = ImageIO.read(fileA);
+ DataBuffer dbA = biA.getData().getDataBuffer();
+ int sizeA = dbA.getSize();
+ BufferedImage biB = ImageIO.read(fileB);
+ DataBuffer dbB = biB.getData().getDataBuffer();
+ int sizeB = dbB.getSize();
+ int count = 0;
+ // compare data-buffer objects //
+ if (sizeA == sizeB) {
+
+ for (int i = 0; i < sizeA; i++) {
+
+ if (dbA.getElem(i) == dbB.getElem(i)) {
+ count = count + 1;
+ }
+
+ }
+ percentage = ((double) count * 100) / sizeA;
+ } else {
+ System.out.println("Both the images are not of same size");
+ }
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ return percentage;
+ }
+
+
+ @Test
+ public void givenStringContainingLaTeXFormula4whenTransform$thenResultIsCorrect() {
+ assertThat(
+ TextGrid.transformRowToModeRow("xyz$xyz^^^$xyz"),
+ asString().equalTo("PPPLLLLLLLLPPP").$()
+ );
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void givenStringContainingUnfinishedLaTeXFormula$whenTransform$thenIllegalArgumentException() {
+ TextGrid.transformRowToModeRow("xyz$xyz^^^_xyz");
+ }
+
+ @Test
+ public void givenStringNotContainingLaTeXFormula$whenTransform$thenResultIsCorrect() {
+ assertThat(
+ TextGrid.transformRowToModeRow("xyz_xyz^^^_xyz"),
+ asString().equalTo("PPPPPPPPPPPPPP").$()
+ );
+ }
+
+ @Test
+ public void givenEmptyString$whenTransform$thenResultIsEmpty() {
+ assertThat(
+ TextGrid.transformRowToModeRow(""),
+ asString().equalTo("").$()
+ );
+ }
+
+
+ @Test
+ public void testSplit() {
+ String s = "hello$HELLO$ world";
+ Iterator i = StringUtils.createTextSplitter(DiagramText.TEXT_SPLITTING_REGEX, s);
+
+ while (i.hasNext())
+ System.out.println(i.next());
+ }
+
+}
From 155f7ec6476b235a69f26c835e8598ce86c9edae Mon Sep 17 00:00:00 2001
From: Hiroshi Ukai
Date: Mon, 29 Oct 2018 22:38:54 +0900
Subject: [PATCH 02/17] Add a method to do rendering asciiart containing LaTeX
math formulae.
---
test/java/sandbox/Sandbox.java | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/test/java/sandbox/Sandbox.java b/test/java/sandbox/Sandbox.java
index 1bb98e2..49b190e 100644
--- a/test/java/sandbox/Sandbox.java
+++ b/test/java/sandbox/Sandbox.java
@@ -4,6 +4,7 @@
import org.scilab.forge.jlatexmath.TeXConstants;
import org.scilab.forge.jlatexmath.TeXFormula;
import org.scilab.forge.jlatexmath.TeXIcon;
+import org.stathissideris.ascii2image.core.CommandLineConverter;
import org.stathissideris.ascii2image.graphics.DiagramText;
import org.stathissideris.ascii2image.text.StringUtils;
import org.stathissideris.ascii2image.text.TextGrid;
@@ -142,4 +143,8 @@ public void testSplit() {
System.out.println(i.next());
}
+ @Test
+ public void renderLatexAsciiArt() {
+ CommandLineConverter.main(new String[] { "tests/text/art-latexmath-1.txt", "-o", "--latex-math" });
+ }
}
From 61a46ff4f9a501f31dc508b7106df2bb29d4c964 Mon Sep 17 00:00:00 2001
From: Hiroshi Ukai
Date: Mon, 29 Oct 2018 22:45:33 +0900
Subject: [PATCH 03/17] Remove unintentionally introduced
element in
Javadoc.
---
.../stathissideris/ascii2image/graphics/DiagramText.java | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/java/org/stathissideris/ascii2image/graphics/DiagramText.java b/src/java/org/stathissideris/ascii2image/graphics/DiagramText.java
index 58675aa..f4a0c42 100644
--- a/src/java/org/stathissideris/ascii2image/graphics/DiagramText.java
+++ b/src/java/org/stathissideris/ascii2image/graphics/DiagramText.java
@@ -1,18 +1,18 @@
/**
* ditaa - Diagrams Through Ascii Art
- *
+ *
* ditaa is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
- *
+ *
* ditaa is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
- *
+ *
* You should have received a copy of the GNU Lesser General Public
* License along with ditaa. If not, see .
*/
From d6a9a28687146283d13a95532e2707bfa53d83fe Mon Sep 17 00:00:00 2001
From: Hiroshi Ukai
Date: Mon, 29 Oct 2018 22:57:08 +0900
Subject: [PATCH 04/17] Remove unintentionally introduced
element in
Javadoc.
---
.../org/stathissideris/ascii2image/text/StringUtils.java | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/java/org/stathissideris/ascii2image/text/StringUtils.java b/src/java/org/stathissideris/ascii2image/text/StringUtils.java
index 7f37c70..570c4f8 100644
--- a/src/java/org/stathissideris/ascii2image/text/StringUtils.java
+++ b/src/java/org/stathissideris/ascii2image/text/StringUtils.java
@@ -1,18 +1,18 @@
/**
* ditaa - Diagrams Through Ascii Art
- *
+ *
* ditaa is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
- *
+ *
* ditaa is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
- *
+ *
* You should have received a copy of the GNU Lesser General Public
* License along with ditaa. If not, see .
*/
From 49601061c7f65ac643e04487c2bb01dcb2e31619 Mon Sep 17 00:00:00 2001
From: Hiroshi Ukai
Date: Thu, 1 Nov 2018 07:57:14 +0900
Subject: [PATCH 05/17] Add a mechanism to do assertion for images.
---
test/java/sandbox/Sandbox.java | 74 ++++++++++++++++++++++++++++++++--
1 file changed, 71 insertions(+), 3 deletions(-)
diff --git a/test/java/sandbox/Sandbox.java b/test/java/sandbox/Sandbox.java
index 49b190e..351da3b 100644
--- a/test/java/sandbox/Sandbox.java
+++ b/test/java/sandbox/Sandbox.java
@@ -1,5 +1,6 @@
package sandbox;
+import com.github.dakusui.crest.Crest;
import org.junit.Test;
import org.scilab.forge.jlatexmath.TeXConstants;
import org.scilab.forge.jlatexmath.TeXFormula;
@@ -19,9 +20,13 @@
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
+import java.util.function.Predicate;
+import static com.github.dakusui.crest.Crest.asObject;
import static com.github.dakusui.crest.Crest.asString;
import static com.github.dakusui.crest.Crest.assertThat;
+import static com.github.dakusui.crest.Crest.callOn;
+import static java.lang.String.format;
public class Sandbox {
@Test
@@ -91,7 +96,7 @@ public static double compareImages(File fileA, File fileB) {
}
}
- percentage = ((double) count * 100) / sizeA;
+ percentage = ((double) count) / sizeA;
} else {
System.out.println("Both the images are not of same size");
}
@@ -144,7 +149,70 @@ public void testSplit() {
}
@Test
- public void renderLatexAsciiArt() {
+ public void renderAsLatexAsciiArt() {
CommandLineConverter.main(new String[] { "tests/text/art-latexmath-1.txt", "-o", "--latex-math" });
}
-}
+
+ @Test
+ public void renderAsNonLatexAsciiArt() {
+ CommandLineConverter.main(new String[] { "tests/text/art-latexmath-1.txt", "-o" });
+ }
+
+ public static BufferedImage getDifferenceImage(BufferedImage img1, BufferedImage img2) {
+ // convert images to pixel arrays...
+ final int w = img1.getWidth(),
+ h = img1.getHeight(),
+ highlight = Color.MAGENTA.getRGB();
+ final int[] p1 = img1.getRGB(0, 0, w, h, null, 0, w);
+ final int[] p2 = img2.getRGB(0, 0, w, h, null, 0, w);
+ // compare img1 to img2, pixel by pixel. If different, highlight img1's pixel...
+ for (int i = 0; i < p1.length; i++) {
+ if (p1[i] != p2[i]) {
+ p1[i] = highlight;
+ }
+ }
+ // save img1's pixels to a new BufferedImage, and return it...
+ // (May require TYPE_INT_ARGB)
+ final BufferedImage out = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
+ out.setRGB(0, 0, w, h, p1, 0, w);
+ return out;
+ }
+
+ public static File getDifferenceImageFile(File img1, File img2) throws Throwable {
+ File ret;
+ ImageIO.write(
+ getDifferenceImage(
+ ImageIO.read(img1),
+ ImageIO.read(img2)),
+ "png",
+ ret = new File("output.png"));
+ return ret;
+ }
+
+ @Test
+ public void testDiffImage() throws IOException {
+ ImageIO.write(
+ getDifferenceImage(
+ ImageIO.read(new File("tests/text/art-latexmath-1.png")),
+ ImageIO.read(new File("tests/text/art-latexmath-2.png"))),
+ "png",
+ new File("output.png"));
+ }
+
+ @Test
+ public void testImages() throws Throwable {
+ File actual = new File("tests/text/art-latexmath-1.png");
+ File expected = new File("tests/text/art-latexmath-2.png");
+ assertThat(
+ actual,
+ asObject().check(
+ callOn(Sandbox.class, "getDifferenceImageFile", expected, actual).$(), similarImpageTo(expected, 0.999999)).$()
+ );
+ }
+
+ private Predicate similarImpageTo(File expected, double threshold) {
+ return Crest.predicate(
+ format("similarImageTo(%s,%s)", expected, threshold),
+ actual -> compareImages(expected, actual) > threshold);
+ }
+}
\ No newline at end of file
From ca76be031c72b889c5d2d9e064d680eca8c8cee5 Mon Sep 17 00:00:00 2001
From: Hiroshi Ukai
Date: Fri, 2 Nov 2018 08:01:43 +0900
Subject: [PATCH 06/17] WIP: implement utility methods for testing.
---
.gitignore | 1 +
test/java/sandbox/Sandbox.java | 104 +++++++++++++++++++++------------
2 files changed, 67 insertions(+), 38 deletions(-)
diff --git a/.gitignore b/.gitignore
index 1194eb3..45a0329 100644
--- a/.gitignore
+++ b/.gitignore
@@ -22,3 +22,4 @@ tests/text/
tests/build.xml
target/
/.lein-failures
+/testImages.png
diff --git a/test/java/sandbox/Sandbox.java b/test/java/sandbox/Sandbox.java
index 351da3b..415c624 100644
--- a/test/java/sandbox/Sandbox.java
+++ b/test/java/sandbox/Sandbox.java
@@ -1,7 +1,10 @@
package sandbox;
import com.github.dakusui.crest.Crest;
+import com.github.dakusui.crest.utils.printable.Functions;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.TestName;
import org.scilab.forge.jlatexmath.TeXConstants;
import org.scilab.forge.jlatexmath.TeXFormula;
import org.scilab.forge.jlatexmath.TeXIcon;
@@ -20,6 +23,7 @@
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
+import java.util.function.Function;
import java.util.function.Predicate;
import static com.github.dakusui.crest.Crest.asObject;
@@ -29,6 +33,9 @@
import static java.lang.String.format;
public class Sandbox {
+ @Rule
+ public TestName name = new TestName();
+
@Test
public void latexMath() throws IOException {
String latex = "$\\sum_{i=0}^{n}x^i$";
@@ -50,7 +57,7 @@ public void latexMath() throws IOException {
JLabel jl = new JLabel();
jl.setForeground(new Color(0, 0, 0));
icon.paintIcon(jl, g2, 0, 0);
- File file = new File("target/Example1.png");
+ File file = createFile("target/Example1.png");
ImageIO.write(image, "png", file.getAbsoluteFile());
}
@@ -158,7 +165,58 @@ public void renderAsNonLatexAsciiArt() {
CommandLineConverter.main(new String[] { "tests/text/art-latexmath-1.txt", "-o" });
}
- public static BufferedImage getDifferenceImage(BufferedImage img1, BufferedImage img2) {
+ @Test
+ public void testDiffImage() throws IOException {
+ ImageIO.write(
+ getDifferenceImage(
+ ImageIO.read(createFile("tests/text/art-latexmath-1.png")),
+ ImageIO.read(createFile("tests/text/art-latexmath-2.png"))),
+ "png",
+ createFile("output.png"));
+ }
+
+ @Test
+ public void testImages() {
+ File actual = createFile("tests/text/art-latexmath-1.png");
+ File expected = createFile("tests/text/art-latexmath-2.png");
+ assertThat(
+ actual,
+ asObject().check(
+ callOn(Sandbox.class, "imageDiff", expected, Functions.THIS, this.name).$(),
+ similarImpageTo(expected, 0.999999)).$());
+ }
+
+ private Function