Coverage Report - net.sourceforge.jeuclid.converter.Converter
 
Classes in this File Line Coverage Branch Coverage Complexity
Converter
69%
69/100
50%
12/24
2
Converter$SingletonHolder
57%
4/7
N/A
2
 
 1  
 /*
 2  
  * Copyright 2007 - 2008 JEuclid, http://jeuclid.sf.net
 3  
  * 
 4  
  * Licensed under the Apache License, Version 2.0 (the "License");
 5  
  * you may not use this file except in compliance with the License.
 6  
  * You may obtain a copy of the License at
 7  
  *
 8  
  *      http://www.apache.org/licenses/LICENSE-2.0
 9  
  *
 10  
  * Unless required by applicable law or agreed to in writing, software
 11  
  * distributed under the License is distributed on an "AS IS" BASIS,
 12  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  
  * See the License for the specific language governing permissions and
 14  
  * limitations under the License.
 15  
  */
 16  
 
 17  
 /* $Id: Converter.java,v 0bed7fec74b0 2010/08/06 15:59:34 max $ */
 18  
 
 19  
 package net.sourceforge.jeuclid.converter;
 20  
 
 21  
 import java.awt.Color;
 22  
 import java.awt.Dimension;
 23  
 import java.awt.Graphics2D;
 24  
 import java.awt.Image;
 25  
 import java.awt.image.BufferedImage;
 26  
 import java.io.BufferedOutputStream;
 27  
 import java.io.File;
 28  
 import java.io.FileOutputStream;
 29  
 import java.io.IOException;
 30  
 import java.io.OutputStream;
 31  
 
 32  
 import javax.xml.parsers.ParserConfigurationException;
 33  
 
 34  
 import net.sourceforge.jeuclid.LayoutContext;
 35  
 import net.sourceforge.jeuclid.MathMLParserSupport;
 36  
 import net.sourceforge.jeuclid.MutableLayoutContext;
 37  
 import net.sourceforge.jeuclid.context.LayoutContextImpl;
 38  
 import net.sourceforge.jeuclid.converter.ConverterPlugin.DocumentWithDimension;
 39  
 import net.sourceforge.jeuclid.layout.JEuclidView;
 40  
 
 41  
 import org.apache.commons.logging.Log;
 42  
 import org.apache.commons.logging.LogFactory;
 43  
 import org.w3c.dom.Document;
 44  
 import org.w3c.dom.Node;
 45  
 import org.xml.sax.SAXException;
 46  
 
 47  
 /**
 48  
  * Generic converter which uses the registry to do its conversions.
 49  
  * 
 50  
  * @version $Revision: 0bed7fec74b0 $
 51  
  */
 52  
 public final class Converter {
 53  
 
 54  
     /**
 55  
      * Mime type for SVG.
 56  
      */
 57  
     public static final String TYPE_SVG = "image/svg+xml";
 58  
 
 59  
     /**
 60  
      * File extension for SVG.
 61  
      */
 62  
     public static final String EXTENSION_SVG = "svg";
 63  
 
 64  
     private static final String UNSUPPORTED_OUTPUT_TYPE = "Unsupported output type: ";
 65  
 
 66  6240
     private static final int MAX_RGB_VALUE = 255;
 67  195
 
 68  448
     private static final class SingletonHolder {
 69  14
         private static final Converter INSTANCE = new Converter();
 70  0
 
 71  0
         private SingletonHolder() {
 72  0
         }
 73  
     }
 74  
 
 75  
     /**
 76  195
      * Logger for this class
 77  
      */
 78  14
     private static final Log LOGGER = LogFactory.getLog(Converter.class);
 79  
 
 80  
     /**
 81  195
      * Default constructor.
 82  
      */
 83  209
     protected Converter() {
 84  
         // Empty on purpose.
 85  14
     }
 86  
 
 87  
     /**
 88  
      * Retrieve an instance of the converter singleton class.
 89  
      * 
 90  
      * @return a Converter object.
 91  6240
      */
 92  
     public static Converter getInstance() {
 93  448
         return Converter.SingletonHolder.INSTANCE;
 94  
     }
 95  
 
 96  
     /**
 97  
      * @return Converter instance
 98  
      * @deprecated use {@link #getInstance()} instead.
 99  
      */
 100  0
     @Deprecated
 101  
     public static Converter getConverter() {
 102  0
         return Converter.getInstance();
 103  
     }
 104  
 
 105  
     /**
 106  
      * Converts an existing file from MathML or ODF to the given type.
 107  
      * 
 108  
      * @param inFile
 109  
      *            input file.
 110  
      * @param outFile
 111  
      *            output file.
 112  
      * @param outFileType
 113  
      *            mimetype for the output file.
 114  
      * @return Dimension of converted image upon success, null otherwise
 115  
      * @throws IOException
 116  
      *             if an I/O error occurred during read or write.
 117  
      */
 118  0
     public Dimension convert(final File inFile, final File outFile,
 119  
             final String outFileType) throws IOException {
 120  0
         final MutableLayoutContext params = new LayoutContextImpl(
 121  
                 LayoutContextImpl.getDefaultLayoutContext());
 122  0
         return this.convert(inFile, outFile, outFileType, params);
 123  
     }
 124  
 
 125  
     /**
 126  
      * Converts an existing file from MathML or ODF to the given type.
 127  
      * 
 128  
      * @param inFile
 129  
      *            input file.
 130  
      * @param outFile
 131  
      *            output file.
 132  
      * @param outFileType
 133  
      *            mimetype for the output file.
 134  
      * @param params
 135  
      *            rendering parameters.
 136  
      * @return Dimension of converted image upon success, null otherwise
 137  
      * @throws IOException
 138  
      *             if an I/O error occurred during read or write.
 139  
      */
 140  
     public Dimension convert(final File inFile, final File outFile,
 141  
             final String outFileType, final LayoutContext params)
 142  
             throws IOException {
 143  0
         Document doc;
 144  0
         try {
 145  0
             doc = MathMLParserSupport.parseFile(inFile);
 146  0
             return this.convert(doc, outFile, outFileType, params);
 147  0
         } catch (final SAXException e) {
 148  0
             Converter.LOGGER.error("Failed to parse file:" + inFile, e);
 149  0
             return null;
 150  
         }
 151  
     }
 152  
 
 153  
     /**
 154  
      * Converts an existing document from MathML to the given type and store it
 155  
      * in a file.
 156  
      * 
 157  
      * @param doc
 158  
      *            input document. See
 159  
      *            {@link net.sourceforge.jeuclid.DOMBuilder#DOMBuilder(Node, MathBase)}
 160  
      *            for the list of valid node types.
 161  
      * @param outFile
 162  
      *            output file.
 163  
      * @param outFileType
 164  
      *            mimetype for the output file.
 165  
      * @param params
 166  
      *            parameter set to use for conversion.
 167  
      * @return Dimension of converted image upon success, null otherwise
 168  
      * @throws IOException
 169  
      *             if an I/O error occurred during read or write.
 170  
      */
 171  
     public Dimension convert(final Node doc, final File outFile,
 172  
             final String outFileType, final LayoutContext params)
 173  2925
             throws IOException {
 174  
 
 175  3135
         final OutputStream outStream = new BufferedOutputStream(
 176  
                 new FileOutputStream(outFile));
 177  3135
         final Dimension result = this.convert(doc, outStream, outFileType,
 178  0
                 params);
 179  210
         if (result == null) {
 180  0
             if (!outFile.delete()) {
 181  0
                 Converter.LOGGER.debug("Could not delete " + outFile);
 182  
             }
 183  
         } else {
 184  2925
             // should be closed by wrapper image streams, but just in case...
 185  0
             try {
 186  210
                 outStream.close();
 187  2925
             } catch (final IOException e) {
 188  0
                 Converter.LOGGER.debug(e);
 189  3135
             }
 190  
         }
 191  210
         return result;
 192  
     }
 193  
 
 194  
     /**
 195  
      * Converts an existing document from MathML to the given XML based type and
 196  
      * store it in a DOM document.
 197  
      * 
 198  
      * @param doc
 199  
      *            input document. See
 200  
      *            {@link net.sourceforge.jeuclid.DOMBuilder#DOMBuilder(Node, MathBase)}
 201  
      *            for the list of valid node types.
 202  
      * @param outFileType
 203  
      *            mimetype for the output file.
 204  
      * @param params
 205  
      *            parameter set to use for conversion.
 206  
      * @return an instance of Document, or the appropriate subtype for this
 207  
      *         format (e.g. SVGDocument). If conversion is not supported to this
 208  
      *         type, it may return null.
 209  
      */
 210  195
     public DocumentWithDimension convert(final Node doc,
 211  
             final String outFileType, final LayoutContext params) {
 212  209
         final ConverterPlugin plugin = ConverterRegistry.getInstance()
 213  195
                 .getConverter(outFileType);
 214  209
         DocumentWithDimension result = null;
 215  14
         if (plugin != null) {
 216  209
             result = plugin.convert(doc, params);
 217  0
         }
 218  14
         if (result == null) {
 219  0
             Converter.LOGGER.fatal(Converter.UNSUPPORTED_OUTPUT_TYPE
 220  195
                     + outFileType);
 221  
         }
 222  14
         return result;
 223  
     }
 224  
 
 225  
     /**
 226  
      * Converts an existing document from MathML to the given XML based type and
 227  
      * writes it to the provided output stream.
 228  
      * 
 229  
      * @param doc
 230  
      *            input document. See
 231  
      *            {@link net.sourceforge.jeuclid.DOMBuilder#DOMBuilder(Node, MathBase)}
 232  
      *            for the list of valid node types.
 233  
      * @param outStream
 234  
      *            output stream.
 235  
      * @param outFileType
 236  
      *            mimetype for the output file.
 237  
      * @param params
 238  
      *            parameter set to use for conversion.
 239  
      * @return Dimension of converted image upon success, null otherwise
 240  
      * @throws IOException
 241  
      *             if an I/O error occurred during read or write.
 242  
      */
 243  2925
     public Dimension convert(final Node doc, final OutputStream outStream,
 244  
             final String outFileType, final LayoutContext params)
 245  2925
             throws IOException {
 246  3135
         final ConverterPlugin plugin = ConverterRegistry.getInstance()
 247  0
                 .getConverter(outFileType);
 248  210
         Dimension result = null;
 249  210
         if (plugin == null) {
 250  0
             Converter.LOGGER.fatal(Converter.UNSUPPORTED_OUTPUT_TYPE
 251  2925
                     + outFileType);
 252  0
         } else {
 253  0
             try {
 254  210
                 result = plugin.convert(doc, params, outStream);
 255  2925
             } catch (final IOException ex) {
 256  0
                 Converter.LOGGER.fatal("Failed to process: " + ex.getMessage(),
 257  2925
                         ex);
 258  210
             }
 259  
         }
 260  210
         return result;
 261  
     }
 262  
 
 263  
     /**
 264  
      * Converts an XML string from MathML to the given XML based type and writes
 265  
      * it to the provided output stream.
 266  
      * 
 267  
      * @param docString
 268  
      *            XML string representing a valid document
 269  
      * @param outStream
 270  
      *            output stream.
 271  
      * @param outFileType
 272  
      *            mimetype for the output file.
 273  390
      * @param params
 274  
      *            parameter set to use for conversion.
 275  
      * @return Dimension of converted image upon success, null otherwise
 276  
      * @throws IOException
 277  
      *             if an I/O error occurred during read or write.
 278  
      */
 279  
     public Dimension convert(final String docString,
 280  
             final OutputStream outStream, final String outFileType,
 281  
             final LayoutContext params) throws IOException {
 282  
 
 283  0
         Dimension result = null;
 284  
 
 285  
         try {
 286  0
             final Document doc = MathMLParserSupport.parseString(docString);
 287  0
             result = this.convert(doc, outStream, outFileType, params);
 288  0
         } catch (final SAXException e) {
 289  0
             Converter.LOGGER.error("SAXException converting:" + docString, e);
 290  0
             result = null;
 291  3120
         } catch (final ParserConfigurationException e) {
 292  3120
             Converter.LOGGER.error("ParserConfigurationException converting:"
 293  
                     + docString, e);
 294  3120
             result = null;
 295  0
         }
 296  3120
 
 297  3120
         return result;
 298  3120
     }
 299  
 
 300  
     /**
 301  3120
      * Renders a document into an image.
 302  3120
      * 
 303  
      * @param node
 304  
      *            Document / Node to render
 305  3120
      * @param context
 306  2535
      *            LayoutContext to use.
 307  
      * @return the rendered image
 308  
      * @throws IOException
 309  585
      *             if an I/O error occurred.
 310  
      */
 311  3120
     public BufferedImage render(final Node node, final LayoutContext context)
 312  3120
             throws IOException {
 313  3148
         return this.render(node, context, BufferedImage.TYPE_INT_ARGB);
 314  
     }
 315  3120
 
 316  3120
     /**
 317  
      * Renders a document into an image.
 318  
      * 
 319  
      * @param node
 320  
      *            Document / Node to render
 321  
      * @param context
 322  
      *            LayoutContext to use.
 323  
      * @param imageType
 324  
      *            ImageType as defined by {@link BufferedImage}
 325  
      * @return the rendered image
 326  
      * @throws IOException
 327  
      *             if an I/O error occurred.
 328  
      */
 329  
     public BufferedImage render(final Node node, final LayoutContext context,
 330  
             final int imageType) throws IOException {
 331  224
         final Image tempimage = new BufferedImage(1, 1, imageType);
 332  224
         final Graphics2D tempg = (Graphics2D) tempimage.getGraphics();
 333  
 
 334  224
         final JEuclidView view = new JEuclidView(node, context, tempg);
 335  
 
 336  224
         final int width = Math.max(1, (int) Math.ceil(view.getWidth()));
 337  224
         final int ascent = (int) Math.ceil(view.getAscentHeight());
 338  224
         final int height = Math.max(1, (int) Math.ceil(view.getDescentHeight())
 339  
                 + ascent);
 340  
 
 341  224
         final BufferedImage image = new BufferedImage(width, height, imageType);
 342  224
         final Graphics2D g = image.createGraphics();
 343  
 
 344  
         final Color background;
 345  224
         if (image.getColorModel().hasAlpha()) {
 346  182
             background = new Color(Converter.MAX_RGB_VALUE,
 347  
                     Converter.MAX_RGB_VALUE, Converter.MAX_RGB_VALUE, 0);
 348  
         } else {
 349  42
             background = Color.WHITE;
 350  
         }
 351  224
         g.setColor(background);
 352  224
         g.fillRect(0, 0, width, height);
 353  224
         g.setColor(Color.black);
 354  
 
 355  224
         view.draw(g, 0, ascent);
 356  224
         return image;
 357  
     }
 358  
 }