001/** 002 * Copyright (c) 2011, The University of Southampton and the individual contributors. 003 * All rights reserved. 004 * 005 * Redistribution and use in source and binary forms, with or without modification, 006 * are permitted provided that the following conditions are met: 007 * 008 * * Redistributions of source code must retain the above copyright notice, 009 * this list of conditions and the following disclaimer. 010 * 011 * * Redistributions in binary form must reproduce the above copyright notice, 012 * this list of conditions and the following disclaimer in the documentation 013 * and/or other materials provided with the distribution. 014 * 015 * * Neither the name of the University of Southampton nor the names of its 016 * contributors may be used to endorse or promote products derived from this 017 * software without specific prior written permission. 018 * 019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 020 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 021 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 022 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 023 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 026 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 028 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 029 */ 030/** 031 * 032 */ 033package org.openimaj.image.typography.mathml; 034 035import java.awt.image.BufferedImage; 036import java.io.ByteArrayInputStream; 037import java.io.IOException; 038 039import javax.xml.parsers.DocumentBuilderFactory; 040 041import net.sourceforge.jeuclid.converter.Converter; 042 043import org.openimaj.image.DisplayUtilities; 044import org.openimaj.image.FImage; 045import org.openimaj.image.ImageUtilities; 046import org.openimaj.image.MBFImage; 047import org.openimaj.image.colour.ColourSpace; 048import org.openimaj.image.colour.RGBColour; 049import org.openimaj.image.renderer.FImageRenderer; 050import org.openimaj.image.renderer.ImageRenderer; 051import org.openimaj.image.renderer.MBFImageRenderer; 052import org.openimaj.image.typography.FontRenderer; 053import org.openimaj.image.typography.FontStyle.HorizontalAlignment; 054import org.openimaj.image.typography.FontStyle.VerticalAlignment; 055import org.openimaj.math.geometry.shape.Rectangle; 056import org.w3c.dom.Element; 057import org.w3c.dom.Node; 058import org.w3c.dom.NodeList; 059 060import uk.ac.ed.ph.snuggletex.SnuggleEngine; 061import uk.ac.ed.ph.snuggletex.SnuggleInput; 062import uk.ac.ed.ph.snuggletex.SnuggleSession; 063 064/** 065 * @param <T> 066 */ 067public class MathMLFontRenderer<T> extends FontRenderer<T, MathMLFontStyle<T>> 068{ 069 070 @Override 071 public void renderText(ImageRenderer<T, ?> renderer, String text, int x,int y, MathMLFontStyle<T> sty) { 072 MBFImage img = renderToMBFImage(text, sty); 073 074 // if we have a non-standard horizontal alignment 075 if ((sty.getHorizontalAlignment() != HorizontalAlignment.HORIZONTAL_LEFT)) { 076 // find the length of the string in pixels ... 077 float len = img.getWidth(); 078 // if we are center aligned 079 if (sty.getHorizontalAlignment() == HorizontalAlignment.HORIZONTAL_CENTER) { 080 x -= len/2; 081 } else { 082 x -= len; 083 } 084 085 } 086 087 if(sty.getVerticalAlignment() != VerticalAlignment.VERTICAL_TOP){ 088 switch (sty.getVerticalAlignment()) { 089 case VERTICAL_BOTTOM: 090 y -= img.getHeight(); 091 break; 092 case VERTICAL_HALF: 093 y -= img.getHeight()/2f; 094 break; 095 default: 096 break; 097 } 098 } 099 100 if(renderer instanceof MBFImageRenderer){ 101 MBFImageRenderer render = (MBFImageRenderer) renderer; 102 render.drawImage(img, x, y); 103 } 104 else if (renderer instanceof FImageRenderer){ 105 FImageRenderer render = (FImageRenderer) renderer; 106 render.drawImage(img.flatten(), x, y); 107 } 108 } 109 110 private MBFImage renderToMBFImage(String text, MathMLFontStyle<T> style) { 111 Converter c = Converter.getInstance(); 112 Node node = null; 113 switch (style.getMathInput()){ 114 case LATEX: 115 if(style.isTextMode()){ 116 text = String.format("$\\mathrm{%s}$",text); 117 } else { 118 text = String.format("$%s$",text); 119 } 120 node = latexToNode(text); 121 break; 122 case MATHML: 123 node = mathmlToNode(text); 124 break; 125 } 126 127 BufferedImage rend = null; 128 try { 129 rend = c.render(node, style.getLayoutContext()); 130 } catch (IOException e) { 131 throw new RuntimeException(e); 132 } 133 MBFImage img = ImageUtilities.createMBFImage(rend, true); 134 return img; 135 } 136 137 @Override 138 public Rectangle getSize(String string, MathMLFontStyle<T> style) { 139 MBFImage mbf = renderToMBFImage(string,style); 140 return mbf.getBounds(); 141 } 142 143 private Node latexToNode(String latex){ 144 SnuggleEngine engine = new SnuggleEngine(); 145 try { 146 SnuggleSession createSession = engine.createSession(); 147 createSession.parseInput(new SnuggleInput(latex)); 148 NodeList dst = createSession.buildDOMSubtree(); 149 return dst.item(0); 150 } catch (IOException e) { 151 throw new RuntimeException(e); 152 } 153 154 } 155 156 private Element mathmlToNode(String string) { 157 try { 158 return DocumentBuilderFactory 159 .newInstance() 160 .newDocumentBuilder() 161 .parse(new ByteArrayInputStream(string.getBytes())) 162 .getDocumentElement(); 163 } catch (Throwable e) { 164 throw new RuntimeException(e); 165 } 166 } 167 168 /** 169 * @param args 170 */ 171 public static void main(String[] args) { 172 MathMLFontRenderer<Float[]> rend = new MathMLFontRenderer<Float[]>(); 173 174 String mathML = "x = 2\\mathrm{wang}wang" ; 175 176 MBFImage img = new MBFImage(300, 300, ColourSpace.RGB); 177 img.fill(RGBColour.WHITE); 178 MBFImageRenderer renderer = img.createRenderer(); 179 MathMLFontStyle<Float[]> style = new MathMLFontStyle<Float[]>(new MathMLFont(), RGBColour.WHITE); 180 style.setColour(RGBColour.RED); 181 style.setFontSize(30); 182 rend.renderText(renderer, mathML, 0, 100, style); 183 DisplayUtilities.display(img); 184 185 MathMLFontRenderer<Float> rendf = new MathMLFontRenderer<Float>(); 186 187 FImage imgf = new FImage(300, 300); 188 imgf.fill(0f); 189 FImageRenderer rendererf = imgf.createRenderer(); 190 MathMLFontStyle<Float> stylef = new MathMLFontStyle<Float>(new MathMLFont(), 0.5f); 191 stylef.setFontSize(30); 192 rendf.renderText(rendererf, mathML, 0, 100, stylef); 193 DisplayUtilities.display(imgf); 194 } 195 196}