/* TeXFormula.java * ========================================================================= * This file is originally part of the JMathTeX Library - http://jmathtex.sourceforge.net * * Copyright (C) 2004-2007 Universiteit Gent * Copyright (C) 2009 DENIZET Calixte * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * This program 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 * General Public License for more details. * * A copy of the GNU General Public License can be found in the file * LICENSE.txt provided with the source distribution of this program (see * the META-INF directory in the source jar). This license can also be * found on the GNU website at http://www.gnu.org/licenses/gpl.html. * * If you did not receive a copy of the GNU General Public License along * with this program, contact the lead developer, or write to the Free * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. * */ /* Modified by Calixte Denizet */ package org.scilab.forge.jlatexmath.core; import android.annotation.SuppressLint; import android.graphics.Bitmap; import android.graphics.Bitmap.Config; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Paint.Style; import android.util.TypedValue; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.lang.Character.UnicodeBlock; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; /** * Represents a logical mathematical formula that will be displayed (by creating * a {@link TeXIcon} from it and painting it) using algorithms that are based on * the TeX algorithms. * <p> * These formula's can be built using the built-in primitive TeX parser (methods * with String arguments) or using other TeXFormula objects. Most methods have * (an) equivalent(s) where one or more TeXFormula arguments are replaced with * String arguments. These are just shorter notations, because all they do is * parse the string(s) to TeXFormula's and call an equivalent method with (a) * TeXFormula argument(s). Most methods also come in 2 variants. One kind will * use this TeXFormula to build another mathematical construction and then * change this object to represent the newly build construction. The other kind * will only use other TeXFormula's (or parse strings), build a mathematical * construction with them and insert this newly build construction at the end of * this TeXFormula. Because all the provided methods return a pointer to this * (modified) TeXFormula (except for the createTeXIcon method that returns a * TeXIcon pointer), method chaining is also possible. * <p> * <b> Important: All the provided methods modify this TeXFormula object, but * all the TeXFormula arguments of these methods will remain unchanged and * independent of this TeXFormula object!</b> */ public class TeXFormula { public static final String VERSION = "1.0.3"; public static final int SERIF = 0; public static final int SANSSERIF = 1; public static final int BOLD = 2; public static final int ITALIC = 4; public static final int ROMAN = 8; public static final int TYPEWRITER = 16; // table for putting delimiters over and under formula's, // indexed by constants from "TeXConstants" private static final String[][] delimiterNames = { { "lbrace", "rbrace" }, { "lsqbrack", "rsqbrack" }, { "lbrack", "rbrack" }, { "downarrow", "downarrow" }, { "uparrow", "uparrow" }, { "updownarrow", "updownarrow" }, { "Downarrow", "Downarrow" }, { "Uparrow", "Uparrow" }, { "Updownarrow", "Updownarrow" }, { "vert", "vert" }, { "Vert", "Vert" } }; // point-to-pixel conversion public static float PIXELS_PER_POINT = 1f; // used as second index in "delimiterNames" table (over or under) private static final int OVER_DEL = 0; private static final int UNDER_DEL = 1; // for comparing floats with 0 protected static final float PREC = 0.0000001f; // predefined TeXFormula's public static Map<String, TeXFormula> predefinedTeXFormulas = new HashMap<String, TeXFormula>( 150); public static Map<String, String> predefinedTeXFormulasAsString = new HashMap<String, String>( 150); // character-to-symbol and character-to-delimiter mappings public static String[] symbolMappings = new String[65536]; public static String[] symbolTextMappings = new String[65536]; public static String[] symbolFormulaMappings = new String[65536]; public static Map<UnicodeBlock, FontInfos> externalFontMap = new HashMap<UnicodeBlock, FontInfos>(); public List<MiddleAtom> middle = new LinkedList<MiddleAtom>(); protected Map<String, String> jlmXMLMap; private TeXParser parser; static { // character-to-symbol and character-to-delimiter mappings TeXFormulaSettingsParser parser = null; try { parser = new TeXFormulaSettingsParser(); } catch (ResourceParseException | IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } parser.parseSymbolMappings(symbolMappings, symbolTextMappings); new PredefinedCommands(); new PredefinedTeXFormulas(); new PredefMacros(); parser.parseSymbolToFormulaMappings(symbolFormulaMappings, symbolTextMappings); try { DefaultTeXFont .registerAlphabet((AlphabetRegistration) Class .forName( "org.scilab.forge.jlatexmath.cyrillic.CyrillicRegistration") .newInstance()); DefaultTeXFont .registerAlphabet((AlphabetRegistration) Class .forName( "org.scilab.forge.jlatexmath.greek.GreekRegistration") .newInstance()); } catch (Exception e) { e.printStackTrace(); } setDefaultDPI(); } public static void addSymbolMappings(String file) throws ResourceParseException, IOException { FileInputStream in; try { in = new FileInputStream(file); } catch (FileNotFoundException e) { throw new ResourceParseException(file, e); } addSymbolMappings(in, file); } public static void addSymbolMappings(InputStream in, String name) throws ResourceParseException, IOException { TeXFormulaSettingsParser tfsp = new TeXFormulaSettingsParser(in, name); tfsp.parseSymbolMappings(symbolMappings, symbolTextMappings); tfsp.parseSymbolToFormulaMappings(symbolFormulaMappings, symbolTextMappings); } public static boolean isRegisteredBlock(Character.UnicodeBlock block) { return externalFontMap.get(block) != null; } public static FontInfos getExternalFont(Character.UnicodeBlock block) { FontInfos infos = externalFontMap.get(block); if (infos == null) { infos = new FontInfos("SansSerif", "Serif"); externalFontMap.put(block, infos); } return infos; } public static void registerExternalFont(Character.UnicodeBlock block, String sansserif, String serif) { if (sansserif == null && serif == null) { externalFontMap.remove(block); return; } externalFontMap.put(block, new FontInfos(sansserif, serif)); if (block.equals(Character.UnicodeBlock.BASIC_LATIN)) { predefinedTeXFormulas.clear(); } } public static void registerExternalFont(Character.UnicodeBlock block, String fontName) { registerExternalFont(block, fontName, fontName); } /** * Set the DPI of target * * @param dpi * the target DPI */ public static void setDPITarget(float dpi) { PIXELS_PER_POINT = dpi / 72f; } /** * Set the default target DPI to the screen dpi (only if we're in * non-headless mode) */ public static void setDefaultDPI() { setDPITarget(AjLatexMath.getContext().getResources().getDisplayMetrics().xdpi); } // the root atom of the "atom tree" that represents the formula public Atom root = null; // the current text style public String textStyle = null; public boolean isColored = false; /** * Creates an empty TeXFormula. * */ public TeXFormula() { parser = new TeXParser("", this, false); } /** * Creates a new TeXFormula by parsing the given string (using a primitive * TeX parser). * * @param s * the string to be parsed * @throws ParseException * if the string could not be parsed correctly */ public TeXFormula(String s, Map<String, String> map) throws ParseException { this.jlmXMLMap = map; this.textStyle = textStyle; parser = new TeXParser(s, this); parser.parse(); } /** * Creates a new TeXFormula by parsing the given string (using a primitive * TeX parser). * * @param s * the string to be parsed * @throws ParseException * if the string could not be parsed correctly */ public TeXFormula(String s) throws ParseException { this(s, (String) null); } public TeXFormula(String s, boolean firstpass) throws ParseException { this.textStyle = null; parser = new TeXParser(s, this, firstpass); parser.parse(); } /* * Creates a TeXFormula by parsing the given string in the given text style. * Used when a text style command was found in the parse string. */ public TeXFormula(String s, String textStyle) throws ParseException { this.textStyle = textStyle; parser = new TeXParser(s, this); parser.parse(); } public TeXFormula(String s, String textStyle, boolean firstpass, boolean space) throws ParseException { this.textStyle = textStyle; parser = new TeXParser(s, this, firstpass, space); parser.parse(); } /** * Creates a new TeXFormula that is a copy of the given TeXFormula. * <p> * <b>Both TeXFormula's are independent of one another!</b> * * @param f * the formula to be copied */ public TeXFormula(TeXFormula f) { if (f != null) { addImpl(f); } } /** * Creates an empty TeXFormula. * */ protected TeXFormula(TeXParser tp) { this.jlmXMLMap = tp.formula.jlmXMLMap; parser = new TeXParser(tp.getIsPartial(), "", this, false); } /** * Creates a new TeXFormula by parsing the given string (using a primitive * TeX parser). * * @param s * the string to be parsed * @throws ParseException * if the string could not be parsed correctly */ protected TeXFormula(TeXParser tp, String s) throws ParseException { this(tp, s, null); } protected TeXFormula(TeXParser tp, String s, boolean firstpass) throws ParseException { this.textStyle = null; this.jlmXMLMap = tp.formula.jlmXMLMap; boolean isPartial = tp.getIsPartial(); parser = new TeXParser(isPartial, s, this, firstpass); if (isPartial) { try { parser.parse(); } catch (Exception e) { } } else { parser.parse(); } } /* * Creates a TeXFormula by parsing the given string in the given text style. * Used when a text style command was found in the parse string. */ protected TeXFormula(TeXParser tp, String s, String textStyle) throws ParseException { this.textStyle = textStyle; this.jlmXMLMap = tp.formula.jlmXMLMap; boolean isPartial = tp.getIsPartial(); parser = new TeXParser(isPartial, s, this); if (isPartial) { try { parser.parse(); } catch (Exception e) { if (root == null) { root = new EmptyAtom(); } } } else { parser.parse(); } } protected TeXFormula(TeXParser tp, String s, String textStyle, boolean firstpass, boolean space) throws ParseException { this.textStyle = textStyle; this.jlmXMLMap = tp.formula.jlmXMLMap; boolean isPartial = tp.getIsPartial(); parser = new TeXParser(isPartial, s, this, firstpass, space); if (isPartial) { try { parser.parse(); } catch (Exception e) { if (root == null) { root = new EmptyAtom(); } } } else { parser.parse(); } } public static TeXFormula getAsText(String text, int alignment) throws ParseException { TeXFormula formula = new TeXFormula(); if (text == null || "".equals(text)) { formula.add(new EmptyAtom()); return formula; } String[] arr = text.split("\n|\\\\\\\\|\\\\cr"); ArrayOfAtoms atoms = new ArrayOfAtoms(); for (String s : arr) { TeXFormula f = new TeXFormula(s, "mathnormal", true, false); atoms.add(new RomanAtom(f.root)); atoms.addRow(); } atoms.checkDimensions(); formula.add(new MatrixAtom(false, atoms, MatrixAtom.ARRAY, alignment)); return formula; } /** * @param a * formula * @return a partial TeXFormula containing the valid part of formula */ public static TeXFormula getPartialTeXFormula(String formula) { TeXFormula f = new TeXFormula(); if (formula == null) { f.add(new EmptyAtom()); return f; } TeXParser parser = new TeXParser(true, formula, f); try { parser.parse(); } catch (Exception e) { if (f.root == null) { f.root = new EmptyAtom(); } } return f; } /** * @param b * true if the fonts should be registered (Java 1.6 only) to be * used with FOP. */ public static void registerFonts(boolean b) { DefaultTeXFontParser.registerFonts(b); } /** * Change the text of the TeXFormula and regenerate the root * * @param ltx * the latex formula */ public void setLaTeX(String ltx) throws ParseException { parser.reset(ltx); if (ltx != null && ltx.length() != 0) parser.parse(); } /** * Inserts an atom at the end of the current formula */ public TeXFormula add(Atom el) { if (el != null) { if (el instanceof MiddleAtom) middle.add((MiddleAtom) el); if (root == null) { root = el; } else { if (!(root instanceof RowAtom)) { root = new RowAtom(root); } ((RowAtom) root).add(el); if (el instanceof TypedAtom) { TypedAtom ta = (TypedAtom) el; int rtype = ta.getRightType(); if (rtype == TeXConstants.TYPE_BINARY_OPERATOR || rtype == TeXConstants.TYPE_RELATION) { ((RowAtom) root).add(new BreakMarkAtom()); } } } } return this; } /** * Parses the given string and inserts the resulting formula at the end of * the current TeXFormula. * * @param s * the string to be parsed and inserted * @throws ParseException * if the string could not be parsed correctly * @return the modified TeXFormula */ public TeXFormula add(String s) throws ParseException { if (s != null && s.length() != 0) { // reset parsing variables textStyle = null; // parse and add the string add(new TeXFormula(s)); } return this; } public TeXFormula append(String s) throws ParseException { return append(false, s); } public TeXFormula append(boolean isPartial, String s) throws ParseException { if (s != null && s.length() != 0) { TeXParser tp = new TeXParser(isPartial, s, this); tp.parse(); } return this; } /** * Inserts the given TeXFormula at the end of the current TeXFormula. * * @param f * the TeXFormula to be inserted * @return the modified TeXFormula */ public TeXFormula add(TeXFormula f) { addImpl(f); return this; } private void addImpl(TeXFormula f) { if (f.root != null) { // special copy-treatment for Mrow as a root!! if (f.root instanceof RowAtom) add(new RowAtom(f.root)); else add(f.root); } } public void setLookAtLastAtom(boolean b) { if (root instanceof RowAtom) ((RowAtom) root).lookAtLastAtom = b; } public boolean getLookAtLastAtom() { if (root instanceof RowAtom) return ((RowAtom) root).lookAtLastAtom; return false; } /** * Centers the current TeXformula vertically on the axis (defined by the * parameter "axisheight" in the resource "DefaultTeXFont.xml". * * @return the modified TeXFormula */ public TeXFormula centerOnAxis() { root = new VCenteredAtom(root); return this; } public static void addPredefinedTeXFormula(InputStream xmlFile) throws ResourceParseException, IOException { new PredefinedTeXFormulaParser(xmlFile, "TeXFormula") .parse(predefinedTeXFormulas); } public static void addPredefinedCommands(InputStream xmlFile) throws ResourceParseException, IOException { new PredefinedTeXFormulaParser(xmlFile, "Command") .parse(MacroInfo.Commands); } /** * Inserts a strut box (whitespace) with the given width, height and depth * (in the given unit) at the end of the current TeXFormula. * * @param unit * a unit constant (from {@link TeXConstants}) * @param width * the width of the strut box * @param height * the height of the strut box * @param depth * the depth of the strut box * @return the modified TeXFormula * @throws InvalidUnitException * if the given integer value does not represent a valid unit */ public TeXFormula addStrut(int unit, float width, float height, float depth) throws InvalidUnitException { return add(new SpaceAtom(unit, width, height, depth)); } /** * Inserts a strut box (whitespace) with the given width, height and depth * (in the given unit) at the end of the current TeXFormula. * * @param type * thinmuskip, medmuskip or thickmuskip (from * {@link TeXConstants}) * @return the modified TeXFormula * @throws InvalidUnitException * if the given integer value does not represent a valid unit */ public TeXFormula addStrut(int type) throws InvalidUnitException { return add(new SpaceAtom(type)); } /** * Inserts a strut box (whitespace) with the given width (in widthUnits), * height (in heightUnits) and depth (in depthUnits) at the end of the * current TeXFormula. * * @param widthUnit * a unit constant used for the width (from {@link TeXConstants}) * @param width * the width of the strut box * @param heightUnit * a unit constant used for the height (from TeXConstants) * @param height * the height of the strut box * @param depthUnit * a unit constant used for the depth (from TeXConstants) * @param depth * the depth of the strut box * @return the modified TeXFormula * @throws InvalidUnitException * if the given integer value does not represent a valid unit */ public TeXFormula addStrut(int widthUnit, float width, int heightUnit, float height, int depthUnit, float depth) throws InvalidUnitException { return add(new SpaceAtom(widthUnit, width, heightUnit, height, depthUnit, depth)); } /* * Convert this TeXFormula into a box, starting form the given style */ private Box createBox(TeXEnvironment style) { if (root == null) return new StrutBox(0, 0, 0, 0); else return root.createBox(style); } private DefaultTeXFont createFont(float size, int type) { DefaultTeXFont dtf = new DefaultTeXFont(size); if (type == 0) { dtf.setSs(false); } if ((type & ROMAN) != 0) { dtf.setRoman(true); } if ((type & TYPEWRITER) != 0) { dtf.setTt(true); } if ((type & SANSSERIF) != 0) { dtf.setSs(true); } if ((type & ITALIC) != 0) { dtf.setIt(true); } if ((type & BOLD) != 0) { dtf.setBold(true); } return dtf; } /** * Apply the Builder pattern instead of using the createTeXIcon(...) * factories * * @author Felix Natter * */ public class TeXIconBuilder { private Integer style; private Float size; private Integer type; private Integer fgcolor; private boolean trueValues = false; private Integer widthUnit; private Float textWidth; private Integer align; private boolean isMaxWidth = false; private Integer interLineUnit; private Float interLineSpacing; /** * Specify the style for rendering the given TeXFormula * * @param style * the style * @return the builder, used for chaining */ public TeXIconBuilder setStyle(final int style) { this.style = style; return this; } /** * Specify the font size for rendering the given TeXFormula * * @param size * the size * @return the builder, used for chaining */ public TeXIconBuilder setSize(final float size) { this.size = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, size / PIXELS_PER_POINT, AjLatexMath.getContext().getResources().getDisplayMetrics()); return this; } /** * Specify the font type for rendering the given TeXFormula * * @param type * the font type * @return the builder, used for chaining */ public TeXIconBuilder setType(final int type) { this.type = type; return this; } /** * Specify the background color for rendering the given TeXFormula * * @param fgcolor * the foreground color * @return the builder, used for chaining */ public TeXIconBuilder setFGColor(final Integer fgcolor) { this.fgcolor = fgcolor; return this; } /** * Specify the "true values" parameter for rendering the given * TeXFormula * * @param trueValues * the "true values" value * @return the builder, used for chaining */ public TeXIconBuilder setTrueValues(final boolean trueValues) { this.trueValues = trueValues; return this; } /** * Specify the width of the formula (may be exact or maximum width, see * {@link #setIsMaxWidth(boolean)}) * * @param widthUnit * the width unit * @param textWidth * the width * @param align * the alignment * @return the builder, used for chaining */ public TeXIconBuilder setWidth(final int widthUnit, final float textWidth, final int align) { this.widthUnit = widthUnit; this.textWidth = textWidth; this.align = align; trueValues = true; // TODO: is this necessary? return this; } /** * Specifies whether the width is the exact or the maximum width * * @param isMaxWidth * whether the width is a maximum width * @return the builder, used for chaining */ public TeXIconBuilder setIsMaxWidth(final boolean isMaxWidth) { if (widthUnit == null) { throw new IllegalStateException( "Cannot set 'isMaxWidth' without having specified a width!"); } if (isMaxWidth) { // NOTE: Currently isMaxWidth==true does not work with // ALIGN_CENTER or ALIGN_RIGHT (see HorizontalBox ctor) // The case (1) we don't support by setting align := ALIGN_LEFT // here is this: // \text{hello world\\hello} with align=ALIGN_CENTER (but forced // to ALIGN_LEFT) and isMaxWidth==true results in: // [hello world] // [hello ] // and NOT: // [hello world] // [ hello ] // However, this case (2) is currently not supported anyway // (ALIGN_CENTER with isMaxWidth==false): // [ hello world ] // [ hello ] // and NOT: // [ hello world ] // [ hello ] // => until (2) is solved, we stick with the hack to set align // := ALIGN_LEFT! this.align = TeXConstants.ALIGN_LEFT; } this.isMaxWidth = isMaxWidth; return this; } /** * Specify the inter line spacing unit and value. NOTE: this is required * for automatic linebreaks to work! * * @param interLineUnit * the unit * @param interLineSpacing * the value * @return the builder, used for chaining */ public TeXIconBuilder setInterLineSpacing(final int interLineUnit, final float interLineSpacing) { if (widthUnit == null) { throw new IllegalStateException( "Cannot set inter line spacing without having specified a width!"); } this.interLineUnit = interLineUnit; this.interLineSpacing = interLineSpacing; return this; } /** * Create a TeXIcon from the information gathered by the (chained) * setXXX() methods. (see Builder pattern) * * @return the TeXIcon */ public TeXIcon build() { if (style == null) { throw new IllegalStateException( "A style is required. Use setStyle()"); } if (size == null) { throw new IllegalStateException( "A size is required. Use setStyle()"); } DefaultTeXFont font = (type == null) ? new DefaultTeXFont(size) : createFont(size, type); TeXEnvironment te; if (widthUnit != null) { te = new TeXEnvironment(style, font, widthUnit, textWidth); } else { te = new TeXEnvironment(style, font); } if (interLineUnit != null) { te.setInterline(interLineUnit, interLineSpacing); } Box box = createBox(te); TeXIcon ti; if (widthUnit != null) { HorizontalBox hb; if (interLineUnit != null) { float il = interLineSpacing * SpaceAtom.getFactor(interLineUnit, te); Box b = BreakFormula.split(box, te.getTextwidth(), il); hb = new HorizontalBox(b, isMaxWidth ? b.getWidth() : te.getTextwidth(), align); } else { hb = new HorizontalBox(box, isMaxWidth ? box.getWidth() : te.getTextwidth(), align); } ti = new TeXIcon(hb, size, trueValues); } else { ti = new TeXIcon(box, size, trueValues); } if (fgcolor != null) { ti.setForeground(fgcolor); } ti.isColored = te.isColored; return ti; } } /** * Creates a TeXIcon from this TeXFormula using the default TeXFont in the * given point size and starting from the given TeX style. If the given * integer value does not represent a valid TeX style, the default style * TeXConstants.STYLE_DISPLAY will be used. * * @param style * a TeX style constant (from {@link TeXConstants}) to start from * @param size * the default TeXFont's point size * @return the created TeXIcon */ public TeXIcon createTeXIcon(int style, float size) { return new TeXIconBuilder().setStyle(style).setSize(size).build(); } public TeXIcon createTeXIcon(int style, float size, int type) { return new TeXIconBuilder().setStyle(style).setSize(size).setType(type) .build(); } public TeXIcon createTeXIcon(int style, float size, int type, Integer fgcolor) { return new TeXIconBuilder().setStyle(style).setSize(size).setType(type) .setFGColor(fgcolor).build(); } public TeXIcon createTeXIcon(int style, float size, boolean trueValues) { return new TeXIconBuilder().setStyle(style).setSize(size) .setTrueValues(trueValues).build(); } public TeXIcon createTeXIcon(int style, float size, int widthUnit, float textwidth, int align) { return createTeXIcon(style, size, 0, widthUnit, textwidth, align); } public TeXIcon createTeXIcon(int style, float size, int type, int widthUnit, float textwidth, int align) { return new TeXIconBuilder().setStyle(style).setSize(size).setType(type) .setWidth(widthUnit, textwidth, align).build(); } public TeXIcon createTeXIcon(int style, float size, int widthUnit, float textwidth, int align, int interlineUnit, float interline) { return createTeXIcon(style, size, 0, widthUnit, textwidth, align, interlineUnit, interline); } public TeXIcon createTeXIcon(int style, float size, int type, int widthUnit, float textwidth, int align, int interlineUnit, float interline) { return new TeXIconBuilder().setStyle(style).setSize(size).setType(type) .setWidth(widthUnit, textwidth, align) .setInterLineSpacing(interlineUnit, interline).build(); } public void createImage(Bitmap.CompressFormat format, int style, float size, String out, Integer bg, Integer fg, boolean transparency) throws IOException { TeXIcon icon = createTeXIcon(style, size); icon.setInsets(new Insets(1, 1, 1, 1)); int w = icon.getIconWidth(), h = icon.getIconHeight(); Bitmap image = Bitmap.createBitmap(w, h, Config.ARGB_8888); Canvas g2 = new Canvas(image); if (bg != null) { Paint st = new Paint(); st.setStyle(Style.FILL_AND_STROKE); st.setColor(bg); g2.drawRect(0, 0, w, h, st); } icon.setForeground(fg == null ? Color.BLACK : fg); icon.paintIcon(g2, 0, 0); File file = new File(out); FileOutputStream imout = new FileOutputStream(file); image.compress(format, 90, imout); imout.flush(); imout.close(); } public void createPNG(int style, float size, String out, Integer bg, Integer fg) throws IOException { createImage(Bitmap.CompressFormat.PNG, style, size, out, bg, fg, bg == null); } @SuppressLint("NewApi") public void createWEBP(int style, float size, String out, Integer bg, Integer fg) throws IOException { createImage(Bitmap.CompressFormat.WEBP, style, size, out, bg, fg, bg == null); } public void createJPEG(int style, float size, String out, Integer bg, Integer fg) throws IOException { createImage(Bitmap.CompressFormat.JPEG, style, size, out, bg, fg, false); } /** * @param formula * the formula * @param style * the style * @param size * the size * @param transparency * , if true the background is transparent * @return the generated image */ public static Bitmap createBufferedImage(String formula, int style, float size, Integer fg, Integer bg) throws ParseException { TeXFormula f = new TeXFormula(formula); TeXIcon icon = f.createTeXIcon(style, size); icon.setInsets(new Insets(2, 2, 2, 2)); int w = icon.getIconWidth(), h = icon.getIconHeight(); Bitmap image = Bitmap.createBitmap(w, h, Config.ARGB_8888); Canvas g2 = new Canvas(image); if (bg != null) { Paint st = new Paint(); st.setStyle(Style.FILL_AND_STROKE); st.setColor(bg); g2.drawRect(0, 0, w, h, st); } icon.setForeground(fg == null ? Color.BLACK : fg); icon.paintIcon(g2, 0, 0); return image; } /** * @param formula * the formula * @param style * the style * @param size * the size * @param transparency * , if true the background is transparent * @return the generated image */ public Bitmap createBufferedImage(int style, float size, Integer fg, Integer bg) throws ParseException { TeXIcon icon = createTeXIcon(style, size); icon.setInsets(new Insets(2, 2, 2, 2)); int w = icon.getIconWidth(), h = icon.getIconHeight(); Bitmap image = Bitmap.createBitmap(w, h, Config.ARGB_8888); Canvas g2 = new Canvas(image); if (bg != null) { Paint st = new Paint(); st.setStyle(Style.FILL_AND_STROKE); st.setColor(bg); g2.drawRect(0, 0, w, h, st); } icon.setForeground(fg == null ? Color.BLACK : fg); icon.paintIcon(g2, 0, 0); return image; } public void setDEBUG(boolean b) { Box.DEBUG = b; } /** * Changes the background color of the <i>current</i> TeXFormula into the * given color. By default, a TeXFormula has no background color, it's * transparent. The backgrounds of subformula's will be painted on top of * the background of the whole formula! Any changes that will be made to * this TeXFormula after this background color was set, will have the * default background color (unless it will also be changed into another * color afterwards)! * * @param c * the desired background color for the <i>current</i> TeXFormula * @return the modified TeXFormula */ public TeXFormula setBackground(Integer c) { if (c != null) { if (root instanceof ColorAtom) root = new ColorAtom(c, null, (ColorAtom) root); else root = new ColorAtom(root, c, null); } return this; } /** * Changes the (foreground) color of the <i>current</i> TeXFormula into the * given color. By default, the foreground color of a TeXFormula is the * foreground color of the component on which the TeXIcon (created from this * TeXFormula) will be painted. The color of subformula's overrides the * color of the whole formula. Any changes that will be made to this * TeXFormula after this color was set, will be painted in the default color * (unless the color will also be changed afterwards into another color)! * * @param c * the desired foreground color for the <i>current</i> TeXFormula * @return the modified TeXFormula */ public TeXFormula setColor(Integer c) { if (c != null) { if (root instanceof ColorAtom) root = new ColorAtom(null, c, (ColorAtom) root); else root = new ColorAtom(root, null, c); } return this; } /** * Sets a fixed left and right type of the current TeXFormula. This has an * influence on the glue that will be inserted before and after this * TeXFormula. * * @param leftType * atom type constant (from {@link TeXConstants}) * @param rightType * atom type constant (from TeXConstants) * @return the modified TeXFormula * @throws InvalidAtomTypeException * if the given integer value does not represent a valid atom * type */ public TeXFormula setFixedTypes(int leftType, int rightType) throws InvalidAtomTypeException { root = new TypedAtom(leftType, rightType, root); return this; } /** * Get a predefined TeXFormula. * * @param name * the name of the predefined TeXFormula * @return a copy of the predefined TeXFormula * @throws FormulaNotFoundException * if no predefined TeXFormula is found with the given name */ public static TeXFormula get(String name) throws FormulaNotFoundException { TeXFormula formula = predefinedTeXFormulas.get(name); if (formula == null) { String f = predefinedTeXFormulasAsString.get(name); if (f == null) { throw new FormulaNotFoundException(name); } TeXFormula tf = new TeXFormula(f); predefinedTeXFormulas.put(name, tf); return tf; } else { return new TeXFormula(formula); } } static class FontInfos { String sansserif; String serif; FontInfos(String sansserif, String serif) { this.sansserif = sansserif; this.serif = serif; } } }