vhardy 2003/07/09 10:37:16 Modified: sources/org/apache/batik/bridge SVGFeImageElementBridge.java Added: samples/tests/spec/filters feImage2.svg Log: Resolved bug #8854 on feImage complete implementation. Added new regression test on feImage Revision Changes Path 1.1 xml-batik/samples/tests/spec/filters/feImage2.svg Index: feImage2.svg =================================================================== <?xml version="1.0" standalone="no"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> <!-- ========================================================================= --> <!-- 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. --> <!-- ========================================================================= --> <!-- ========================================================================= --> <!-- Drill down test on feImage --> <!-- --> <!-- @author [EMAIL PROTECTED] --> <!-- @version $Id $ --> <!-- ========================================================================= --> <?xml-stylesheet type="text/css" href="../../resources/style/test.css" ?> <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="body" width="450" height="500" viewBox="0 0 450 500"> <title>feImage Test</title> <!-- ============================================================= --> <!-- Test content --> <!-- ============================================================= --> <g id="testContent"> <text x="225" y="40" class="title"> feImage Test </text> <defs> <symbol id="symbol" viewBox="0 0 1 1"> <circle cx="0.5" cy="0.5" r="0.5" fill="orange" /> </symbol> <svg id="svg" viewBox="0 0 1 1"> <circle cx="0.5" cy="0.5" r="0.5" fill="crimson" /> </svg> <g id="common"> <circle cx="20" cy="20" r="20" fill="gold" /> </g> <g id="commonBB"> <circle cx="0.5" cy="0.5" r="0.5" fill="gold" /> </g> <filter id="symbolFilter" filterUnits="userSpaceOnUse" x="40" y="40" width="40" height="40"> <feImage xlink:href="#symbol" result="image"/> </filter> <filter id="svgFilter" filterUnits="userSpaceOnUse" x="40" y="40" width="40" height="40"> <feImage xlink:href="#svg" result="image"/> </filter> <filter id="commonFilter" filterUnits="userSpaceOnUse" x="0" y="0" width="40" height="40"> <feImage xlink:href="#common" result="image"/> </filter> <filter id="symbolFilterBB" primitiveUnits="objectBoundingBox" filterUnits="userSpaceOnUse" x="40" y="40" width="40" height="40"> <feImage xlink:href="#symbol" result="image" x="1" y="1" width="1" height="1"/> </filter> <filter id="svgFilterBB" primitiveUnits="objectBoundingBox" filterUnits="userSpaceOnUse" x="40" y="40" width="40" height="40"> <feImage xlink:href="#svg" result="image" x="1" y="1" width="1" height="1"/> </filter> <filter id="commonFilterBB" primitiveUnits="objectBoundingBox" filterUnits="userSpaceOnUse" x="0" y="0" width="40" height="40"> <feImage xlink:href="#commonBB" result="image" x="0" y="0" width="1" height="1"/> </filter> </defs> <g transform="translate(0,50)"> <g transform="translate(50, 50)"> <use id="useSymbol" xlink:href="#symbol" x="40" y="40" width="40" height="40" /> <text x="60" y="30" text-anchor="middle"><symbol></text> </g> <g transform="translate(150, 50)"> <use id="useSvg" xlink:href="#svg" x="40" y="40" width="40" height="40" /> <text x="60" y="30" text-anchor="middle"><svg></text> </g> <g transform="translate(250, 50)"> <use xlink:href="#common" x="40" y="40"/> <text x="60" y="30" text-anchor="middle"><g></text> </g> </g> <g transform="translate(0, 150)"> <g transform="translate(50, 50)"> <g filter="url(#symbolFilter)" /> <text x="60" y="30" text-anchor="middle"><tspan x="60" y="15">feImage</tspan> <tspan x="60" y="30"><symbol></tspan></text> </g> <g transform="translate(150, 50)"> <g filter="url(#svgFilter)" /> <text x="60" y="30" text-anchor="middle"><tspan x="60" y="15">feImage</tspan> <tspan x="60" y="30"><svg></tspan></text> </g> <g transform="translate(250, 50)"> <g transform="translate(40, 40)" filter="url(#commonFilter)" /> <text x="60" y="30" text-anchor="middle"><tspan x="60" y="15">feImage</tspan> <tspan x="60" y="30"><g></tspan></text> </g> </g> <g transform="translate(0, 250)"> <g transform="translate(50, 50)"> <g filter="url(#symbolFilterBB)"> <rect width="40" height="40" /> </g> <text x="60" y="30" text-anchor="middle"><tspan x="60" y="15">feImage ObjBBox</tspan> <tspan x="60" y="30"><symbol></tspan></text> </g> <g transform="translate(150, 50)"> <g filter="url(#svgFilterBB)"> <rect width="40" height="40" /> </g> <text x="60" y="30" text-anchor="middle"><tspan x="60" y="15">feImage ObjBBox</tspan> <tspan x="60" y="30"><svg></tspan></text> </g> <g transform="translate(250, 50)"> <g transform="translate(40, 40)" filter="url(#commonFilterBB)"> <rect width="40" height="40" /> </g> <text x="60" y="30" text-anchor="middle"><tspan x="60" y="15">feImage ObjBBox</tspan> <tspan x="60" y="30"><g></tspan></text> </g> </g> </g> <!-- ============================================================= --> <!-- Batik sample mark --> <!-- ============================================================= --> <use xlink:href="../../../batikLogo.svg#Batik_Tag_Box" /> </svg> 1.19 +84 -45 xml-batik/sources/org/apache/batik/bridge/SVGFeImageElementBridge.java Index: SVGFeImageElementBridge.java =================================================================== RCS file: /home/cvs/xml-batik/sources/org/apache/batik/bridge/SVGFeImageElementBridge.java,v retrieving revision 1.18 retrieving revision 1.19 diff -u -r1.18 -r1.19 --- SVGFeImageElementBridge.java 11 Apr 2003 13:54:47 -0000 1.18 +++ SVGFeImageElementBridge.java 9 Jul 2003 17:37:16 -0000 1.19 @@ -9,12 +9,14 @@ package org.apache.batik.bridge; import java.awt.geom.AffineTransform; +import java.awt.geom.NoninvertibleTransformException; import java.awt.geom.Rectangle2D; 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.util.XMLConstants; import org.apache.batik.ext.awt.image.PadMode; import org.apache.batik.ext.awt.image.renderable.AffineRable8Bit; import org.apache.batik.ext.awt.image.renderable.Filter; @@ -22,6 +24,7 @@ import org.apache.batik.ext.awt.image.spi.ImageTagRegistry; import org.apache.batik.gvt.GraphicsNode; 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.svg.SVGDocument; @@ -80,68 +83,104 @@ new Object[] {"xlink:href"}); } + // + // According the the SVG specification, feImage behaves like + // <image> if it references an SVG document or a raster image + // and it behaves like a <use> if it references a document + // fragment. + // + // To provide this behavior, depending on whether the uri + // contains a fragment identifier, we create either an + // <image> or a <use> element and request the corresponding + // bridges to build the corresponding GraphicsNode for us. + // + // Then, we take care of the possible transformation needed + // from objectBoundingBox space to user space. + // + + GraphicsNode gn = null; + Document document = filterElement.getOwnerDocument(); + boolean isUse = (uriStr.indexOf("#") != -1); + Element contentElement = null; + if (isUse) { + contentElement = document.createElementNS(SVG_NAMESPACE_URI, + SVG_USE_TAG); + } else { + contentElement = document.createElementNS(SVG_NAMESPACE_URI, + SVG_IMAGE_TAG); + } + + + contentElement.setAttributeNS(XLinkSupport.XLINK_NAMESPACE_URI, XMLConstants.XLINK_PREFIX + + ":" + SVG_HREF_ATTRIBUTE, + uriStr); + + Element proxyElement = document.createElementNS(SVG_NAMESPACE_URI, + SVG_G_TAG); + proxyElement.appendChild(contentElement); + // feImage's default region is that of the filter chain. Rectangle2D defaultRegion = filterRegion; + // Compute the transform from object bounding box to user + // space if needed. + AffineTransform at = new AffineTransform(); + + // 'primitiveUnits' attribute - default is userSpaceOnUse + short coordSystemType; + Element filterDefElement = (Element)(filterElement.getParentNode()); + boolean isBBox = false; + String s = SVGUtilities.getChainableAttributeNS + (filterDefElement, null, SVG_PRIMITIVE_UNITS_ATTRIBUTE, ctx); + if (s.length() == 0) { + coordSystemType = SVGUtilities.USER_SPACE_ON_USE; + } else { + coordSystemType = SVGUtilities.parseCoordinateSystem + (filterDefElement, SVG_PRIMITIVE_UNITS_ATTRIBUTE, s); + } + + if (coordSystemType == SVGUtilities.OBJECT_BOUNDING_BOX) { + isBBox = true; + at = SVGUtilities.toObjectBBox(at, filteredNode); + } + // get filter primitive chain region - Rectangle2D primitiveRegion + Rectangle2D primitiveRegionUserSpace = SVGUtilities.convertFilterPrimitiveRegion(filterElement, filteredElement, filteredNode, defaultRegion, filterRegion, ctx); + Rectangle2D primitiveRegion = primitiveRegionUserSpace; - Filter filter = null; - // try to load the image as an svg document - SVGDocument svgDoc = (SVGDocument)filterElement.getOwnerDocument(); - ParsedURL purl; - URL baseURL = ((SVGOMDocument)svgDoc).getURLObject(); - if (baseURL != null) - purl = new ParsedURL(baseURL.toString(), uriStr); - else - purl = new ParsedURL(uriStr); - - // try to load an SVG document - DocumentLoader loader = ctx.getDocumentLoader(); - URIResolver resolver = new URIResolver(svgDoc, loader); - boolean toBBoxNeeded = false; - try { - Element refElement = null; - Node n = resolver.getNode(purl.toString(), filterElement); - if (n.getNodeType() == n.DOCUMENT_NODE) { - refElement = ((SVGDocument)n).getRootElement(); - } else if (n.getNodeType() == Node.ELEMENT_NODE) { - refElement = (Element)n; - toBBoxNeeded = true; - } else { - throw new BridgeException - (filterElement, ERR_URI_IMAGE_INVALID, - new Object[] {uriStr}); + if (isBBox) { + try { + AffineTransform ati = at.createInverse(); + primitiveRegion = ati.createTransformedShape(primitiveRegion).getBounds2D(); + } catch (NoninvertibleTransformException nite) { + // Should never happen, seem above + throw new Error(); } - filter = createSVGFeImage - (ctx, primitiveRegion, refElement, toBBoxNeeded, filterElement, filteredNode); - } catch (BridgeException ex) { - throw ex; - } catch (SecurityException ex) { - throw new BridgeException(filterElement, ERR_URI_UNSECURE, - new Object[] {uriStr}); - } catch (Exception ex) {/* Nothing to do */ } - - if (filter == null) { - // try to load the image as a raster image (JPG or PNG) - filter = createRasterFeImage(ctx, primitiveRegion, purl); } - if (filter == null) { - throw new BridgeException(filterElement, ERR_URI_IMAGE_INVALID, - new Object[] {"xlink:href", uriStr}); - } + contentElement.setAttributeNS(null, SVG_X_ATTRIBUTE, "" + primitiveRegion.getX()); + contentElement.setAttributeNS(null, SVG_Y_ATTRIBUTE, "" + primitiveRegion.getY()); + contentElement.setAttributeNS(null, SVG_WIDTH_ATTRIBUTE, "" + primitiveRegion.getWidth()); + contentElement.setAttributeNS(null, SVG_HEIGHT_ATTRIBUTE, "" + primitiveRegion.getHeight()); + + // System.err.println(">>>>>>>>>>>> primitiveRegion : " + primitiveRegion); + // System.err.println(">>>>>>>>>>>> at : " + at); + + GraphicsNode node = ctx.getGVTBuilder().build(ctx, proxyElement); + Filter filter = node.getGraphicsNodeRable(true); + + filter = new AffineRable8Bit(filter, at); // handle the 'color-interpolation-filters' property handleColorInterpolationFilters(filter, filterElement); - filter = new PadRable8Bit(filter, primitiveRegion, PadMode.ZERO_PAD); + filter = new PadRable8Bit(filter, primitiveRegionUserSpace, PadMode.ZERO_PAD); // update the filter Map updateFilterMap(filterElement, filter, filterMap);
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]