001    /*
002     * Copyright 2002 - 2008 JEuclid, http://jeuclid.sf.net
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     *      http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    
017    /* $Id: PreloaderMathML.java,v 32023847f457 2009/03/20 14:20:15 maxberger $ */
018    
019    package net.sourceforge.jeuclid.xmlgraphics;
020    
021    import java.awt.Graphics2D;
022    import java.awt.Image;
023    import java.awt.image.BufferedImage;
024    import java.io.IOException;
025    import java.io.InputStream;
026    
027    import javax.xml.transform.Source;
028    import javax.xml.transform.dom.DOMSource;
029    import javax.xml.transform.stream.StreamSource;
030    
031    import net.sourceforge.jeuclid.Constants;
032    import net.sourceforge.jeuclid.context.LayoutContextImpl;
033    import net.sourceforge.jeuclid.elements.AbstractJEuclidElement;
034    import net.sourceforge.jeuclid.elements.generic.MathImpl;
035    import net.sourceforge.jeuclid.layout.JEuclidView;
036    import net.sourceforge.jeuclid.parser.Parser;
037    
038    import org.apache.commons.logging.Log;
039    import org.apache.commons.logging.LogFactory;
040    import org.apache.fop.util.UnclosableInputStream;
041    import org.apache.xmlgraphics.image.loader.ImageContext;
042    import org.apache.xmlgraphics.image.loader.ImageException;
043    import org.apache.xmlgraphics.image.loader.ImageInfo;
044    import org.apache.xmlgraphics.image.loader.ImageSize;
045    import org.apache.xmlgraphics.image.loader.impl.AbstractImagePreloader;
046    import org.apache.xmlgraphics.image.loader.impl.ImageXMLDOM;
047    import org.apache.xmlgraphics.image.loader.util.ImageUtil;
048    import org.w3c.dom.Document;
049    import org.w3c.dom.Element;
050    import org.xml.sax.SAXException;
051    
052    /**
053     * @version $Revision: 32023847f457 $
054     */
055    public class PreloaderMathML extends AbstractImagePreloader {
056        /**
057         * Convert from point to millipoint.
058         */
059        public static final float MPT_FACTOR = 1000.0f;
060    
061        /**
062         * Logger for this class
063         */
064        private static final Log LOGGER = LogFactory
065                .getLog(PreloaderMathML.class);
066    
067        /**
068         * Default Constructor.
069         */
070        public PreloaderMathML() {
071            // Empty on purpose
072        }
073    
074        /** {@inheritDoc} */
075        public ImageInfo preloadImage(final String uri, final Source src,
076                final ImageContext context) throws ImageException, IOException {
077            final Document n = this.parseSource(src);
078            if (n != null) {
079                return this.createImageInfo(uri, context, n);
080            }
081    
082            return null;
083        }
084    
085        @SuppressWarnings("unchecked")
086        private ImageInfo createImageInfo(final String uri,
087                final ImageContext context, final Document n) {
088            final ImageInfo info = new ImageInfo(uri, Constants.MATHML_MIMETYPE);
089            final ImageSize size = new ImageSize();
090            final Image tempimage = new BufferedImage(1, 1,
091                    BufferedImage.TYPE_INT_ARGB);
092            final Graphics2D tempg = (Graphics2D) tempimage.getGraphics();
093            final JEuclidView view = new JEuclidView(n, LayoutContextImpl
094                    .getDefaultLayoutContext(), tempg);
095            final int descentMpt = (int) (view.getDescentHeight() * PreloaderMathML.MPT_FACTOR);
096            final int ascentMpt = (int) (view.getAscentHeight() * PreloaderMathML.MPT_FACTOR);
097    
098            size.setSizeInMillipoints(
099                    (int) (view.getWidth() * PreloaderMathML.MPT_FACTOR),
100                    ascentMpt + descentMpt);
101            size.setBaselinePositionFromBottom(descentMpt);
102            // Set the resolution to that of the FOUserAgent
103            size.setResolution(context.getSourceResolution());
104            size.calcPixelsFromSize();
105            info.setSize(size);
106    
107            // The whole image had to be loaded for this, so keep it
108            final ImageXMLDOM xmlImage = new ImageXMLDOM(info, n,
109                    AbstractJEuclidElement.URI);
110            info.getCustomObjects().put(ImageInfo.ORIGINAL_IMAGE, xmlImage);
111            return info;
112        }
113    
114        private Document parseSource(final Source src) {
115            Document n = null;
116            InputStream in = null;
117            try {
118                if (src instanceof DOMSource) {
119                    final DOMSource domSrc = (DOMSource) src;
120                    n = (Document) domSrc.getNode();
121                } else {
122                    in = new UnclosableInputStream(ImageUtil.needInputStream(src));
123                    final int length = in.available();
124                    in.mark(length + 1);
125                    n = Parser.getInstance().parseStreamSource(
126                            new StreamSource(in));
127                }
128                final Element rootNode = n.getDocumentElement();
129                if (!(AbstractJEuclidElement.URI.equals(rootNode
130                        .getNamespaceURI()) || MathImpl.ELEMENT.equals(rootNode
131                        .getNodeName()))) {
132                    n = null;
133                }
134            } catch (final IOException e) {
135                n = null;
136            } catch (final SAXException e) {
137                n = null;
138            } catch (final IllegalArgumentException e) {
139                n = null;
140            } catch (final NullPointerException e) {
141                // Due to a bug in xmlgraphics-commons 1.3.1 which sometimes
142                // creates wrapper around null streams if files do not exist.
143                n = null;
144            }
145            try {
146                if (in != null) {
147                    in.reset();
148                }
149            } catch (final IOException ioe) {
150                PreloaderMathML.LOGGER.warn("Should never happen: "
151                        + ioe.getMessage());
152            } catch (final NullPointerException e) {
153                // Due to a bug in xmlgraphics-commons 1.3.1 which sometimes
154                // creates wrapper around null streams if files do not exist.
155                n = null;
156            }
157            return n;
158        }
159    }