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}