Package org.apache.batik.bridge

Source Code of org.apache.batik.bridge.SVGImageElementBridge

/*****************************************************************************
* Copyright (C) The Apache Software Foundation. All rights reserved.        *
* ------------------------------------------------------------------------- *
* This software is published under the terms of the Apache Software License *
* version 1.1, a copy of which has been included with this distribution in  *
* the LICENSE file.                                                         *
*****************************************************************************/

package org.apache.batik.bridge;

import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.color.ColorSpace;
import java.awt.color.ICC_Profile;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.awt.geom.Rectangle2D;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Map;

import org.apache.batik.dom.svg.SVGOMDocument;
import org.apache.batik.dom.util.XLinkSupport;
import org.apache.batik.ext.awt.color.ICCColorSpaceExt;
import org.apache.batik.ext.awt.image.renderable.ClipRable8Bit;
import org.apache.batik.ext.awt.image.renderable.Filter;
import org.apache.batik.ext.awt.image.spi.ImageTagRegistry;
import org.apache.batik.gvt.CompositeGraphicsNode;
import org.apache.batik.gvt.GraphicsNode;
import org.apache.batik.gvt.ImageNode;
import org.apache.batik.gvt.RasterImageNode;
import org.apache.batik.gvt.filter.GraphicsNodeRable8Bit;
import org.apache.batik.util.ParsedURL;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.css.CSSPrimitiveValue;
import org.w3c.dom.css.CSSStyleDeclaration;
import org.w3c.dom.svg.SVGDocument;
import org.w3c.dom.svg.SVGSVGElement;

/**
* Bridge class for the <image> element.
*
* @author <a href="mailto:tkormann@apache.org">Thierry Kormann</a>
* @version $Id: SVGImageElementBridge.java,v 1.29 2001/10/09 22:17:10 deweese Exp $
*/
public class SVGImageElementBridge extends AbstractGraphicsNodeBridge {

    /**
     * Constructs a new bridge for the &lt;image> element.
     */
    public SVGImageElementBridge() {}

    /**
     * Returns 'image'.
     */
    public String getLocalName() {
        return SVG_IMAGE_TAG;
    }

    /**
     * Creates a graphics node using the specified BridgeContext and for the
     * specified element.
     *
     * @param ctx the bridge context to use
     * @param e the element that describes the graphics node to build
     * @return a graphics node that represents the specified element
     */
    public GraphicsNode createGraphicsNode(BridgeContext ctx, Element e) {

        ImageNode imageNode = (ImageNode)super.createGraphicsNode(ctx, e);

        // 'xlink:href' attribute - required
        String uriStr = XLinkSupport.getXLinkHref(e);
        if (uriStr.length() == 0) {
            throw new BridgeException(e, ERR_ATTRIBUTE_MISSING,
                                      new Object[] {"xlink:href"});
        }
        if (uriStr.indexOf('#') != -1) {
            throw new BridgeException(e, ERR_ATTRIBUTE_VALUE_MALFORMED,
                                      new Object[] {"xlink:href", uriStr});
        }
        GraphicsNode node = null;
        // try to load the image as an svg document
        SVGDocument svgDoc = (SVGDocument)e.getOwnerDocument();
        URL baseURL = ((SVGOMDocument)svgDoc).getURLObject();
        ParsedURL purl = new ParsedURL(baseURL, uriStr);

        // try to load an SVG document
        DocumentLoader loader = ctx.getDocumentLoader();
        URIResolver resolver = new URIResolver(svgDoc, loader);
        try {
            Node n = resolver.getNode(purl.toString(), e);
            if (n.getNodeType() == n.DOCUMENT_NODE) {
                SVGDocument imgDocument = (SVGDocument)n;
                node = createSVGImageNode(ctx, e, imgDocument);
            }
        } catch (BridgeException ex) {
            throw ex;
        } catch (Exception ex) {
            /* Nothing to do */
        }

        if (node == null) {
            // try to load the image as a raster image (JPG or PNG)
            node = createRasterImageNode(ctx, e, purl);
        }

        if (node == null) {
            throw new BridgeException(e, ERR_URI_IMAGE_INVALID,
                                      new Object[] {uriStr});
        }

        // 'image-rendering' and 'color-rendering'
        Map imageHints = CSSUtilities.convertImageRendering(e);
        Map colorHints = CSSUtilities.convertColorRendering(e);
        if (imageHints != null || colorHints != null) {
            RenderingHints hints;
            if (imageHints == null) {
                hints = new RenderingHints(colorHints);
            } else if (colorHints == null) {
                hints = new RenderingHints(imageHints);
            } else {
                hints = new RenderingHints(imageHints);
                hints.putAll(colorHints);
            }
            node.setRenderingHints(hints);
        }

        imageNode.setImage(node);
        return imageNode;
    }

    /**
     * Creates an <tt>ImageNode</tt>.
     */
    protected GraphicsNode instantiateGraphicsNode() {
        return new ImageNode();
    }

    /**
     * Returns false as image is not a container.
     */
    public boolean isComposite() {
        return false;
    }

    /**
     * Returns a GraphicsNode that represents an raster image in JPEG or PNG
     * format.
     *
     * @param ctx the bridge context
     * @param e the image element
     * @param uriStr the uri of the image
     */
    protected static GraphicsNode createRasterImageNode(BridgeContext ctx,
                                                        Element       e,
                                                        ParsedURL     purl) {

        RasterImageNode node = new RasterImageNode();

        ImageTagRegistry reg = ImageTagRegistry.getRegistry();
        Filter           img = reg.readURL(purl, extractColorSpace(e, ctx));
        Object           obj = img.getProperty
            (SVGBrokenLinkProvider.SVG_BROKEN_LINK_DOCUMENT_PROPERTY);
        if ((obj != null) && (obj instanceof SVGDocument)) {
            // Ok so we are dealing with a broken link.
            return createSVGImageNode(ctx, e, (SVGDocument)obj);
        }
        node.setImage(img);
  Rectangle2D imgBounds = img.getBounds2D();
  node.setImageBounds(imgBounds);
        Rectangle2D bounds = getImageBounds(ctx, e);

  // create the implicit viewBox for the raster image. The viewBox for a
  // raster image is the size of the image
  float [] vb = new float[4];
  vb[0] = 0; // x
  vb[1] = 0; // y
  vb[2] = (float)imgBounds.getWidth(); // width
  vb[3] = (float)imgBounds.getHeight(); // height

  // handles the 'preserveAspectRatio', 'overflow' and 'clip' and sets the
  // appropriate AffineTransform to the image node
  initializeViewport(ctx, e, node, vb, bounds);

        return node;
    }

    /**
     * Returns a GraphicsNode that represents a svg document as an image.
     *
     * @param ctx the bridge context
     * @param e the image element
     * @param imgDocument the SVG document that represents the image
     */
    protected static GraphicsNode createSVGImageNode(BridgeContext ctx,
                                                     Element e,
                                                     SVGDocument imgDocument) {

        CompositeGraphicsNode result = new CompositeGraphicsNode();
        CSSStyleDeclaration decl = CSSUtilities.getComputedStyle(e);
        UnitProcessor.Context uctx = UnitProcessor.createContext(ctx, e);

        Rectangle2D r
            = CSSUtilities.convertEnableBackground(e, uctx);
        if (r != null) {
            result.setBackgroundEnable(r);
        }

        SVGSVGElement svgElement = imgDocument.getRootElement();
        GraphicsNode node = ctx.getGVTBuilder().build(ctx, svgElement);
  // HACK: remove the clip set by the SVGSVGElement as the overflow
  // and clip properties must be ignored. The clip will be set later
  // using the overflow and clip of the <image> element.
  node.setClip(null);
        result.getChildren().add(node);

  // create the implicit viewBox for the SVG image. The viewBox for a
  // SVG image is the viewBox of the outermost SVG element of the SVG file
  String viewBox =
      svgElement.getAttributeNS(null, SVG_VIEW_BOX_ATTRIBUTE);
  float [] vb = ViewBox.parseViewBoxAttribute(e, viewBox);
 
  // handles the 'preserveAspectRatio', 'overflow' and 'clip' and sets the
  // appropriate AffineTransform to the image node
        Rectangle2D bounds = getImageBounds(ctx, e);
  initializeViewport(ctx, e, result, vb, bounds);
        return result;
    }

    /**
     * Initializes according to the specified element, the specified graphics
     * node with the specified bounds. This method takes into account the
     * 'viewBox', 'preserveAspectRatio', and 'clip' properties. According to
     * those properties, a AffineTransform and a clip is set.
     *
     * @param ctx the bridge context
     * @param e the image element that defines the properties
     * @param node the graphics node
     * @param vb the implicit viewBox definition
     * @param bounds the bounds of the image element
     */
    protected static void initializeViewport(BridgeContext ctx,
               Element e,
               GraphicsNode node,
               float [] vb,
               Rectangle2D bounds) {
 
        float x = (float)bounds.getX();
        float y = (float)bounds.getY();
        float w = (float)bounds.getWidth();
        float h = (float)bounds.getHeight();

        AffineTransform at
            = ViewBox.getPreserveAspectRatioTransform(e, vb, w, h);
        at.preConcatenate(AffineTransform.getTranslateInstance(x, y));
        node.setTransform(at);

        // 'overflow' and 'clip'
        Shape clip = null;
        if (CSSUtilities.convertOverflow(e)) { // overflow:hidden
            float [] offsets = CSSUtilities.convertClip(e);
            if (offsets == null) { // clip:auto
                clip = new Rectangle2D.Float(x, y, w, h);
            } else { // clip:rect(<x> <y> <w> <h>)
                // offsets[0] = top
                // offsets[1] = right
                // offsets[2] = bottom
                // offsets[3] = left
                clip = new Rectangle2D.Float(x+offsets[3],
                                             y+offsets[0],
                                             w-offsets[1]-offsets[3],
                                             h-offsets[2]-offsets[0]);
            }
        }

        if (clip != null) {
      try {
    at = at.createInverse(); // clip in user space
    Filter filter = node.getGraphicsNodeRable();
    clip = at.createTransformedShape(clip);
    node.setClip(new ClipRable8Bit(filter, clip));
      } catch (java.awt.geom.NoninvertibleTransformException ex) {}
  }
    }

    /**
     * Analyzes the color-profile property and builds an ICCColorSpaceExt
     * object from it.
     *
     * @param element the element with the color-profile property
     * @param ctx the bridge context
     */
    protected static ICCColorSpaceExt extractColorSpace(Element element,
                                                        BridgeContext ctx) {

        CSSStyleDeclaration decl = CSSUtilities.getComputedStyle(element);
        String colorProfileProperty
            = ((CSSPrimitiveValue)decl.getPropertyCSSValue
               (CSS_COLOR_PROFILE_PROPERTY)).getStringValue();

        // The only cases that need special handling are 'sRGB' and 'name'
        ICCColorSpaceExt colorSpace = null;
        if (CSS_SRGB_VALUE.equalsIgnoreCase(colorProfileProperty)) {

            colorSpace = new ICCColorSpaceExt
                (ICC_Profile.getInstance(ColorSpace.CS_sRGB),
                 ICCColorSpaceExt.AUTO);

        } else if (!CSS_AUTO_VALUE.equalsIgnoreCase(colorProfileProperty)
                   && !"".equalsIgnoreCase(colorProfileProperty)){

            // The value is neither 'sRGB' nor 'auto': it is a profile name.
            SVGColorProfileElementBridge profileBridge =
                (SVGColorProfileElementBridge) ctx.getBridge
                (SVG_NAMESPACE_URI, SVG_COLOR_PROFILE_TAG);
            if (profileBridge != null) {
                colorSpace = profileBridge.createICCColorSpaceExt
                    (ctx, element, colorProfileProperty);

            }
        }
        return colorSpace;
    }

    /**
     * Returns the bounds of the specified image element.
     *
     * @param ctx the bridge context
     * @param element the image element
     */
    protected static
        Rectangle2D getImageBounds(BridgeContext ctx, Element element) {

        UnitProcessor.Context uctx = UnitProcessor.createContext(ctx, element);

        // 'x' attribute - default is 0
        String s = element.getAttributeNS(null, SVG_X_ATTRIBUTE);
        float x = 0;
        if (s.length() != 0) {
            x = UnitProcessor.svgHorizontalCoordinateToUserSpace
                (s, SVG_X_ATTRIBUTE, uctx);
        }

        // 'y' attribute - default is 0
        s = element.getAttributeNS(null, SVG_Y_ATTRIBUTE);
        float y = 0;
        if (s.length() != 0) {
            y = UnitProcessor.svgVerticalCoordinateToUserSpace
                (s, SVG_Y_ATTRIBUTE, uctx);
        }

        // 'width' attribute - required
        s = element.getAttributeNS(null, SVG_WIDTH_ATTRIBUTE);
        float w;
        if (s.length() == 0) {
            throw new BridgeException(element, ERR_ATTRIBUTE_MISSING,
                                      new Object[] {SVG_WIDTH_ATTRIBUTE});
        } else {
            w = UnitProcessor.svgHorizontalLengthToUserSpace
                (s, SVG_WIDTH_ATTRIBUTE, uctx);
        }

        // 'height' attribute - required
        s = element.getAttributeNS(null, SVG_HEIGHT_ATTRIBUTE);
        float h;
        if (s.length() == 0) {
            throw new BridgeException(element, ERR_ATTRIBUTE_MISSING,
                                      new Object[] {SVG_HEIGHT_ATTRIBUTE});
        } else {
            h = UnitProcessor.svgVerticalLengthToUserSpace
                (s, SVG_HEIGHT_ATTRIBUTE, uctx);
        }

        return new Rectangle2D.Float(x, y, w, h);
    }

    static {
        ImageTagRegistry.setBrokenLinkProvider(new SVGBrokenLinkProvider());
    }
}
TOP

Related Classes of org.apache.batik.bridge.SVGImageElementBridge

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.