Package org.apache.fop.render.svg

Source Code of org.apache.fop.render.svg.SVGRenderer

/*
* $Id: SVGRenderer.java,v 1.3.2.8 2003/03/02 16:55:18 pietsch Exp $
* ============================================================================
*                    The Apache Software License, Version 1.1
* ============================================================================
*
* Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modifica-
* tion, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
*    this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
*    this list of conditions and the following disclaimer in the documentation
*    and/or other materials provided with the distribution.
*
* 3. The end-user documentation included with the redistribution, if any, must
*    include the following acknowledgment: "This product includes software
*    developed by the Apache Software Foundation (http://www.apache.org/)."
*    Alternately, this acknowledgment may appear in the software itself, if
*    and wherever such third-party acknowledgments normally appear.
*
* 4. The names "FOP" and "Apache Software Foundation" must not be used to
*    endorse or promote products derived from this software without prior
*    written permission. For written permission, please contact
*    apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache", nor may
*    "Apache" appear in their name, without prior written permission of the
*    Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
* DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ============================================================================
*
* This software consists of voluntary contributions made by many individuals
* on behalf of the Apache Software Foundation and was originally created by
* James Tauber <jtauber@jtauber.com>. For more information on the Apache
* Software Foundation, please see <http://www.apache.org/>.
*/
package org.apache.fop.render.svg;

import org.apache.fop.layout.*;
import org.apache.fop.layout.inline.*;
import org.apache.fop.datatypes.IDReferences;
import org.apache.fop.datatypes.ColorType;
import org.apache.fop.image.*;
import org.apache.fop.svg.SVGArea;
import org.apache.fop.svg.SVGUtilities;
import org.apache.fop.apps.FOPException;

import org.w3c.dom.Node;
import org.w3c.dom.ProcessingInstruction;
import org.w3c.dom.svg.SVGSVGElement;
import org.w3c.dom.svg.SVGDocument;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.DOMImplementation;

import org.apache.batik.dom.svg.SVGDOMImplementation;
import org.apache.batik.dom.util.XMLSupport;
import org.apache.batik.transcoder.svg2svg.SVGTranscoder;
import org.apache.batik.transcoder.TranscoderInput;
import org.apache.batik.transcoder.TranscoderOutput;
import org.apache.batik.transcoder.TranscoderException;

import java.awt.Color;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.awt.geom.Rectangle2D;
import java.util.Map;
import java.net.URL;
import java.net.MalformedURLException;
import java.io.OutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import javax.swing.ImageIcon;

import org.apache.fop.render.AbstractRenderer;

public class SVGRenderer extends AbstractRenderer {
    static final String svgNS = SVGDOMImplementation.SVG_NAMESPACE_URI;
    Document svgDocument;
    Element svgRoot;
    Element currentPageG = null;
    Element lastLink = null;

    float totalWidth = 0;
    float totalHeight = 0;

    protected int pageWidth = 0;
    protected int pageHeight = 0;
    protected int pageNumber = 0;

    protected Map fontNames = new java.util.HashMap();
    protected Map fontStyles = new java.util.HashMap();
    protected Color saveColor = null;

    /**
     * The current (internal) font name
     */
    protected String currentFontName;

    /**
     * The current font size in millipoints
     */
    protected int currentFontSize;

    /**
     * The current colour's red, green and blue component
     */
    protected float currentRed = 0;
    protected float currentGreen = 0;
    protected float currentBlue = 0;

    /**
     * options
     */
    protected java.util.Map options;

    /**
     * set up renderer options
     */
    public void setOptions(java.util.Map options) {
        this.options = options;
    }

    public SVGRenderer() {
    }

    /**
     * add a line to the current stream
     *
     * @param x1 the start x location in millipoints
     * @param y1 the start y location in millipoints
     * @param x2 the end x location in millipoints
     * @param y2 the end y location in millipoints
     * @param th the thickness in millipoints
     * @param r the red component
     * @param g the green component
     * @param b the blue component
     */
    protected void addLine(int x1, int y1, int x2, int y2, int th, float r,
                           float g, float b) {
        Element line = SVGUtilities.createLine(svgDocument, x1 / 1000f, pageHeight - (y1 / 1000f), x2 / 1000f, pageHeight - (y2 / 1000f));
        line.setAttributeNS(null, "style", "stroke-width:" + (Math.abs(th) / 1000f)
                            + ";stroke:rgb(" + ((int)(255 * r)) + "," + ((int)(255 * g)) + "," + ((int)(255 * b)) + ")");
        currentPageG.appendChild(line);
    }

    /**
     * draw a rectangle
     *
     * @param x the x position of left edge in millipoints
     * @param y the y position of top edge in millipoints
     * @param w the width in millipoints
     * @param h the height in millipoints
     * @param r the red component
     * @param g the green component
     * @param b the blue component
     */
    protected void addRect(int x, int y, int w, int h, float r, float g,
                           float b) {
        Element rect = SVGUtilities.createRect(svgDocument, x / 1000f, pageHeight - (y / 1000f), w / 1000f, h / 1000f);
        rect.setAttributeNS(null, "style", "stroke:rgb(" + ((int)(255 * r)) + "," + ((int)(255 * g)) + "," + ((int)(255 * b)) + ")");
        currentPageG.appendChild(rect);
    }

    /**
     * draw a filled rectangle
     *
     * @param x the x position of left edge in millipoints
     * @param y the y position of top edge in millipoints
     * @param w the width in millipoints
     * @param h the height in millipoints
     * @param r the red component of edges
     * @param g the green component of edges
     * @param b the blue component of edges
     * @param fr the red component of the fill
     * @param fg the green component of the fill
     * @param fb the blue component of the fill
     */
    protected void addRect(int x, int y, int w, int h, float r, float g,
                           float b, float fr, float fg, float fb) {
        Element rect = SVGUtilities.createRect(svgDocument, x / 1000f, pageHeight - (y / 1000f), w / 1000f, h / 1000f);
        rect.setAttributeNS(null, "style", "stroke:rgb(" + ((int)(255 * r)) + "," + ((int)(255 * g)) + "," + ((int)(255 * b)) + ");fill:rgb(" + ((int)(255 * fr)) + "," + ((int)(255 * fg)) + "," + ((int)(255 * fb)) + ")");
        currentPageG.appendChild(rect);
    }

    /**
     * draw a filled rectangle in the current color
     *
     * @param x the x position of left edge in millipoints
     * @param y the y position of top edge in millipoints
     * @param w the width in millipoints
     * @param h the height in millipoints
     * @param drawAsOutline true for draw, false for fill
     */
    protected void addRect(int x, int y, int w, int h,
                           boolean drawAsOutline) {
        int startx = (x + 500) / 1000;
        int starty = pageHeight - ((y + 500) / 1000);
        int endx = (x + w + 500) / 1000;
        int endy = pageHeight - ((y + h + 500) / 1000);
        if (drawAsOutline) {
            Element rect = SVGUtilities.createRect(svgDocument, startx, starty, endx - startx, endy - starty);
            rect.setAttributeNS(null, "style", "fill:none");
            currentPageG.appendChild(rect);
        } else {
            Element rect = SVGUtilities.createRect(svgDocument, startx, starty, endx - startx, starty - endy);
            rect.setAttributeNS(null, "style", "stroke:none");
            currentPageG.appendChild(rect);
        }
    }

    protected void addFilledRect(int x, int y, int w, int h,
                                 ColorType col) {
        float r = col.red();
        float g = col.green();
        float b = col.blue();
        addRect(x, y, w, h, r, g, b, r, g, b);
    }

    protected void drawFrame() {
        int width = pageWidth;
        int height = pageHeight;
        Element rect = SVGUtilities.createRect(svgDocument, 0, 0, width, height);
        rect.setAttributeNS(null, "style", "fill:none;stroke:black");
        currentPageG.appendChild(rect);
    }

    public void render(Page page, OutputStream stream)
    throws IOException {
        pageNumber++;
        this.render(page);
    }

    public void render(Page page)
    throws IOException {
        idReferences = page.getIDReferences();

        int lastWidth = pageWidth;
        int lastHeight = pageHeight;

        pageWidth = (int)((float)page.getWidth() / 1000f + .5);
        pageHeight = (int)((float)page.getHeight() / 1000f + .5);

        if(lastLink != null && currentPageG != null) {
            lastLink.setAttributeNS(null, "xlink:href", "#svgView(viewBox(0, "+ (totalHeight) + ", " + pageWidth + ", " + pageHeight + "))");
            currentPageG.appendChild(lastLink);
        }

        totalHeight += pageHeight;
        if(totalWidth < pageWidth) {
            totalWidth = pageWidth;
        }

        currentPageG = SVGUtilities.createG(svgDocument);
        currentPageG.setAttributeNS(null, "id", /*title + */"Page-" + pageNumber);
        currentPageG.setAttributeNS(null, "style", "font-family:sanserif;font-size:12");
        svgRoot.appendChild(currentPageG);

        drawFrame();

        renderPage(page);

        currentPageG.setAttributeNS(null, "transform", "translate(0," + (totalHeight - pageHeight) + ")");

        Element lastPageLink = svgDocument.createElementNS(svgNS, "a");
        if(lastLink != null) {
            lastPageLink.setAttributeNS(null, "xlink:href", "#svgView(viewBox(0, " + (totalHeight - pageHeight - lastHeight) + ", " + lastWidth + ", " + lastHeight + "))");
        } else {
            lastPageLink.setAttributeNS(null, "xlink:href", "#svgView(viewBox(0, " + (totalHeight - pageHeight) + ", " + pageWidth + ", " + pageHeight + "))");
        }
        currentPageG.appendChild(lastPageLink);
        Element rect = SVGUtilities.createRect(svgDocument, 0, 0, pageWidth / 2, pageHeight);
        rect.setAttributeNS(null, "style", "fill:blue;visibility:hidden");
        lastPageLink.appendChild(rect);

        lastLink = svgDocument.createElementNS(svgNS, "a");
        rect = SVGUtilities.createRect(svgDocument, pageWidth / 2, 0, pageWidth / 2, pageHeight);
        rect.setAttributeNS(null, "style", "fill:blue;visibility:hidden");
        lastLink.appendChild(rect);

        /*
         * if (page.hasLinks()) {
         * ....
         * }
         */

    }

    public void renderPage(Page page) {

        this.currentFontName = "";
        this.currentFontSize = 0;

        renderRegions(page);
    }

    protected void doFrame(org.apache.fop.layout.Area area) {
        int w, h;
        int rx = this.currentAreaContainerXPosition;
        w = area.getContentWidth();

        if (area instanceof BlockArea) {
            rx += ((BlockArea)area).getStartIndent();
        }

        h = area.getContentHeight();
        int ry = this.currentYPosition;

        rx = rx - area.getPaddingLeft();
        ry = ry + area.getPaddingTop();
        w = w + area.getPaddingLeft() + area.getPaddingRight();
        h = h + area.getPaddingTop() + area.getPaddingBottom();

    doBackground(area, rx, ry, w, h);

        rx = rx - area.getBorderLeftWidth();
        ry = ry + area.getBorderTopWidth();
        w = w + area.getBorderLeftWidth() + area.getBorderRightWidth();
        h = h + area.getBorderTopWidth() + area.getBorderBottomWidth();

        BorderAndPadding bp = area.getBorderAndPadding();
        ColorType borderColor;

        if (area.getBorderTopWidth() != 0) {
            borderColor = bp.getBorderColor(BorderAndPadding.TOP);
            addLine(rx, ry, rx + w, ry, area.getBorderTopWidth(),
                    borderColor.red(), borderColor.green(),
                    borderColor.blue());
        }

        if (area.getBorderLeftWidth() != 0) {
            borderColor = bp.getBorderColor(BorderAndPadding.LEFT);
            addLine(rx, ry, rx, ry - h, area.getBorderLeftWidth(),
                    borderColor.red(), borderColor.green(),
                    borderColor.blue());
        }

        if (area.getBorderRightWidth() != 0) {
            borderColor = bp.getBorderColor(BorderAndPadding.RIGHT);
            addLine(rx + w, ry, rx + w, ry - h,
                    area.getBorderRightWidth(), borderColor.red(),
                    borderColor.green(),
                    borderColor.blue());
        }

        if (area.getBorderBottomWidth() != 0) {
            borderColor = bp.getBorderColor(BorderAndPadding.BOTTOM);
            addLine(rx, ry - h, rx + w, ry - h, area.getBorderBottomWidth(),
                    borderColor.red(), borderColor.green(),
                    borderColor.blue());
        }
    }

    protected Rectangle2D getBounds(org.apache.fop.layout.Area a) {
        return new Rectangle2D.Double(currentAreaContainerXPosition,
                                      currentYPosition,
                                      a.getAllocationWidth(), a.getHeight());
    }

    public void setupFontInfo(FontInfo fontInfo) throws FOPException {
        // create a temp Image to test font metrics on
        BufferedImage fontImage =
            new BufferedImage(100, 100, BufferedImage.TYPE_INT_RGB);
        org.apache.fop.render.awt.FontSetup.setup(fontInfo, fontImage.createGraphics());
    }

    public void renderDisplaySpace(DisplaySpace space) {
        int d = space.getSize();
        this.currentYPosition -= d;
    }

    /**
     * Renders an image, scaling it to the given width and height.
     * If the scaled width and height is the same intrinsic size
     * of the image, the image is not scaled.
     *
     * @param x the x position of left edge in millipoints
     * @param y the y position of top edge in millipoints
     * @param w the width in millipoints
     * @param h the height in millipoints
     * @param image the image to be rendered
     * @param fs the font state to use when rendering text
     *           in non-bitmapped images.
     */
    protected void drawImageScaled(int x, int y, int w, int h,
                   FopImage image,
                   FontState fs) {
    // XXX: implement this
    }

    /**
     * Renders an image, clipping it as specified.
     *
     * @param x the x position of left edge in millipoints.
     * @param y the y position of top edge in millipoints.
     * @param clipX the left edge of the clip in millipoints
     * @param clipY the top edge of the clip in millipoints
     * @param clipW the clip width in millipoints
     * @param clipH the clip height in millipoints
     * @param fill the image to be rendered
     * @param fs the font state to use when rendering text
     *           in non-bitmapped images.
     */
    protected void drawImageClipped(int x, int y,
                    int clipX, int clipY,
                    int clipW, int clipH,
                    FopImage image,
                    FontState fs) {
    // XXX: implement this
    }

    public void renderImageArea(ImageArea area) {

        int x = currentXPosition + area.getXOffset();
        int y = currentYPosition;
        int w = area.getContentWidth();
        int h = area.getHeight();
        this.currentYPosition -= h;

        FopImage img = area.getImage();

        if (img == null) {
            log.error("Error while loading image : area.getImage() is null");

            addRect(x, y, w, h, true);    // use helper function

        } else {
            if (img instanceof SVGImage) {
                try {
                    SVGDocument svg = ((SVGImage)img).getSVGDocument();
                    renderSVGDocument(svg, x / 1000f, pageHeight - y / 1000f);
                } catch (FopImageException e) {}

            } else {

                String urlString = img.getURL();
                try {
                    URL url = new URL(urlString);

                    ImageIcon icon = new ImageIcon(url);
                    Image image = icon.getImage();

                    int startx = (x + 500) / 1000;
                    int starty = pageHeight - ((y + 500) / 1000);
                    int endx = (x + w + 500) / 1000;
                    int endy = pageHeight - ((y + h + 500) / 1000);

                    // reverse start and end y because h is positive
                    //graphics.drawImage(image, startx, starty, endx - startx,
                    //                   starty - endy, null);

                } catch (MalformedURLException mue) {
                    // cannot normally occur because, if URL is wrong, constructing FopImage
                    // will already have failed earlier on
                }
            }
        }

        this.currentXPosition += area.getContentWidth();
    }

    public void renderWordArea(WordArea area) {
        char ch;
        StringBuffer pdf = new StringBuffer();

        String name = area.getFontState().getFontFamily();
        int size = area.getFontState().getFontSize();
        boolean underlined = area.getUnderlined();

        float red = area.getRed();
        float green = area.getGreen();
        float blue = area.getBlue();

        if ((!name.equals(this.currentFontName))
                || (size != this.currentFontSize)) {
            this.currentFontName = name;
            this.currentFontSize = size;
        }

        if ((red != this.currentRed) || (green != this.currentGreen)
                || (blue != this.currentBlue)) {
            this.currentRed = red;
            this.currentGreen = green;
            this.currentBlue = blue;
        }

        int rx = this.currentXPosition;
        int bl = this.currentYPosition;

        String s = area.getText();

        if (saveColor != null) {
            if (saveColor.getRed() != red || saveColor.getGreen() != green
                    || saveColor.getBlue() != blue) {
                saveColor = new Color(red, green, blue);
            }
        } else {
            saveColor = new Color(red, green, blue);
        }

        Element text = SVGUtilities.createText(svgDocument, rx / 1000f, pageHeight - bl / 1000f, s);
        String st = null;
        if(!"sans-serif".equals(this.currentFontName)) {
            st = "font-family:" + this.currentFontName;
        }
        if(this.currentFontSize != 12000) {
            if(st == null) {
                st = "";
            } else {
                st += ";";
            }
            st += "font-size:" + (this.currentFontSize / 1000f);
        }
        if(red != 0 || green != 0 || blue != 0) {
            if(st == null) {
                st = "";
            } else {
                st += ";";
            }
            st += "fill:rgb(" + ((int)(255 * red)) + "," + ((int)(255 * green)) + "," + ((int)(255 * blue)) + ")";
        }
        String fweight = area.getFontState().getFontWeight();
        if(!"normal".equals(fweight)) {
            if(st == null) {
                st = "";
            } else {
                st += ";";
            }
            st += "font-weight:" + fweight;
        }
        String fstyle = area.getFontState().getFontStyle();
        if(!"normal".equals(fstyle)) {
            if(st == null) {
                st = "";
            } else {
                st += ";";
            }
            st += "font-style:" + fstyle;
        }

        if(st != null) {
            text.setAttributeNS(null, "style", st);
        }
        currentPageG.appendChild(text);

        this.currentXPosition += area.getContentWidth();
    }

    public void renderInlineSpace(InlineSpace space) {
        this.currentXPosition += space.getSize();
    }

    /**
     *
     * @param area area to render
     */
    public void renderLeaderArea(LeaderArea area) {

        int rx = this.currentXPosition;
        int ry = this.currentYPosition;
        int w = area.getLeaderLength();
        int h = area.getHeight();
        int th = area.getRuleThickness();
        int st = area.getRuleStyle();    // not used at the moment
        float r = area.getRed();
        float g = area.getGreen();
        float b = area.getBlue();

        //graphics.setColor(new Color(r, g, b));

        addRect(rx, ry, w, th, false);

        this.currentXPosition += area.getContentWidth();
    }

    public void renderSVGArea(SVGArea area) {

        float x = this.currentXPosition / 1000f;
        float y = pageHeight - this.currentYPosition / 1000f;
        int w = area.getContentWidth();
        int h = area.getHeight();

        Document doc = area.getSVGDocument();
        renderSVGDocument(doc, x, y);
        this.currentXPosition += area.getContentWidth();
    }

    protected void renderSVGDocument(Document doc, float x, float y) {
        SVGSVGElement svg = ((SVGDocument)doc).getRootElement();
        Element view = svgDocument.createElementNS(svgNS, "svg");
        Node newsvg = svgDocument.importNode(svg, true);
        //view.setAttributeNS(null, "viewBox", "0 0 ");
        view.setAttributeNS(null, "x", "" + x);
        view.setAttributeNS(null, "y", "" + y);

        // this fixes a problem where the xmlns is repeated sometimes
        Element ele = (Element)newsvg;
        ele.setAttributeNS(XMLSupport.XMLNS_NAMESPACE_URI, "xmlns", svgNS);
        if(ele.hasAttributeNS(null, "xmlns")) {
           ele.removeAttributeNS(null, "xmlns");
        }

        view.appendChild(newsvg);
        currentPageG.appendChild(view);
    }

    public void setProducer(String producer) {
        // defined in Renderer Interface
    }

    public static Color colorType2Color(ColorType ct) {
        if (ct == null) {
            return null;
        }
        return new Color(ct.red(), ct.green(), ct.blue());
    }

    public void renderForeignObjectArea(ForeignObjectArea area) {
        area.getObject().render(this);
    }

    public void startRenderer(OutputStream outputStream)
              throws IOException {
        DOMImplementation impl = SVGDOMImplementation.getDOMImplementation();
        svgDocument = impl.createDocument(svgNS, "svg", null);
        ProcessingInstruction pi =
                 svgDocument.createProcessingInstruction(
                         "xml",
                         " version=\"1.0\" encoding=\"ISO-8859-1\"");
                svgRoot = svgDocument.getDocumentElement();
        svgDocument.insertBefore(pi, svgRoot);
        }

    public void stopRenderer(OutputStream outputStream)
    throws IOException {
        svgRoot.setAttributeNS(null, "width", "" + totalWidth);
        svgRoot.setAttributeNS(null, "height", "" + totalHeight);
        //svgRoot.setAttributeNS(null, "viewBox", "0 0 " + pageWidth + " " + pageHeight);
        SVGTranscoder svgT = new SVGTranscoder();
        TranscoderInput input = new TranscoderInput(svgDocument);
        TranscoderOutput output = new TranscoderOutput(new OutputStreamWriter(outputStream));
        try {
            svgT.transcode(input, output);
        } catch(TranscoderException e) {
            log.error("could not write svg file :" + e.getMessage(), e);
        }
        outputStream.flush();

        svgDocument = null;
        svgRoot = null;
        currentPageG = null;
        lastLink = null;

        totalWidth = 0;
        totalHeight = 0;

        pageNumber = 0;
    }

}
TOP

Related Classes of org.apache.fop.render.svg.SVGRenderer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.