/** * Returns a Filter that represents a svg document or element as an image. * * @param ctx the bridge context * @param primitiveRegion the primitive region * @param refElement the referenced element * @param toBBoxNeeded true if there is a need to transform to ObjectBoundingBox space * @param filterElement parent filter element * @param filteredNode node to which the filter applies */ protected static Filter createSVGFeImage( BridgeContext ctx, Rectangle2D primitiveRegion, Element refElement, boolean toBBoxNeeded, Element filterElement, GraphicsNode filteredNode) { // // <!> FIX ME // Unresolved issue on the feImage behavior when referencing an // image (PNG, JPEG or SVG image). // VH & TK, 03/08/2002 // Furthermore, for feImage referencing doc fragment, should act // like a <use>, i.e., CSS cascading and the whole zing bang. // GraphicsNode node = ctx.getGVTBuilder().build(ctx, refElement); Filter filter = node.getGraphicsNodeRable(true); AffineTransform at = new AffineTransform(); if (toBBoxNeeded) { // 'primitiveUnits' attribute - default is userSpaceOnUse short coordSystemType; Element filterDefElement = (Element) (filterElement.getParentNode()); 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, ctx); } if (coordSystemType == SVGUtilities.OBJECT_BOUNDING_BOX) { at = SVGUtilities.toObjectBBox(at, filteredNode); } Rectangle2D bounds = filteredNode.getGeometryBounds(); at.preConcatenate( AffineTransform.getTranslateInstance( primitiveRegion.getX() - bounds.getX(), primitiveRegion.getY() - bounds.getY())); } else { // Need to translate the image to the x, y coordinate to // have the same behavior as the <use> element at.translate(primitiveRegion.getX(), primitiveRegion.getY()); } return new AffineRable8Bit(filter, at); }
/** * Returns the specular exponent of the specular feSpecularLighting filter primitive element. * * @param filterElement the feSpecularLighting filter primitive element * @param ctx the BridgeContext to use for error information */ protected static float convertSpecularExponent(Element filterElement, BridgeContext ctx) { String s = filterElement.getAttributeNS(null, SVG_SPECULAR_EXPONENT_ATTRIBUTE); if (s.length() == 0) { return 1; // default is 1 } else { try { float v = SVGUtilities.convertSVGNumber(s); if (v < 1 || v > 128) { throw new BridgeException( ctx, filterElement, ERR_ATTRIBUTE_VALUE_MALFORMED, new Object[] {SVG_SPECULAR_CONSTANT_ATTRIBUTE, s}); } return v; } catch (NumberFormatException nfEx) { throw new BridgeException( ctx, filterElement, nfEx, ERR_ATTRIBUTE_VALUE_MALFORMED, new Object[] {SVG_SPECULAR_CONSTANT_ATTRIBUTE, s, nfEx}); } } }
/** * Creates a <code>Filter</code> primitive according to the specified parameters. * * @param ctx the bridge context to use * @param filterElement the element that defines a filter * @param filteredElement the element that references the filter * @param filteredNode the graphics node to filter * @param inputFilter the <code>Filter</code> that represents the current filter input if the * filter chain. * @param filterRegion the filter area defined for the filter chain the new node will be part of. * @param filterMap a map where the mediator can map a name to the <code>Filter</code> it creates. * Other <code>FilterBridge</code>s can then access a filter node from the filterMap if they * know its name. */ public Filter createFilter( BridgeContext ctx, Element filterElement, Element filteredElement, GraphicsNode filteredNode, Filter inputFilter, Rectangle2D filterRegion, Map filterMap) { // 'scale' attribute - default is 0 float scale = convertNumber(filterElement, SVG_SCALE_ATTRIBUTE, 0, ctx); // 'xChannelSelector' attribute - default is 'A' ARGBChannel xChannelSelector = convertChannelSelector(filterElement, SVG_X_CHANNEL_SELECTOR_ATTRIBUTE, ARGBChannel.A, ctx); // 'yChannelSelector' attribute - default is 'A' ARGBChannel yChannelSelector = convertChannelSelector(filterElement, SVG_Y_CHANNEL_SELECTOR_ATTRIBUTE, ARGBChannel.A, ctx); // 'in' attribute Filter in = getIn(filterElement, filteredElement, filteredNode, inputFilter, filterMap, ctx); if (in == null) { return null; // disable the filter } // 'in2' attribute - required Filter in2 = getIn2(filterElement, filteredElement, filteredNode, inputFilter, filterMap, ctx); if (in2 == null) { return null; // disable the filter } Rectangle2D defaultRegion; defaultRegion = (Rectangle2D) in.getBounds2D().clone(); defaultRegion.add(in2.getBounds2D()); // get filter primitive chain region Rectangle2D primitiveRegion = SVGUtilities.convertFilterPrimitiveRegion( filterElement, filteredElement, filteredNode, defaultRegion, filterRegion, ctx); PadRable pad = new PadRable8Bit(in, primitiveRegion, PadMode.ZERO_PAD); // build the displacement map filter List srcs = new ArrayList(2); srcs.add(pad); srcs.add(in2); Filter displacementMap = new DisplacementMapRable8Bit(srcs, scale, xChannelSelector, yChannelSelector); // handle the 'color-interpolation-filters' property handleColorInterpolationFilters(displacementMap, filterElement); PadRable filter = new PadRable8Bit(displacementMap, primitiveRegion, PadMode.ZERO_PAD); // update the filter Map updateFilterMap(filterElement, filter, filterMap); return filter; }
/** * Creates a <code>Filter</code> primitive according to the specified parameters. * * @param ctx the bridge context to use * @param filterElement the element that defines a filter * @param filteredElement the element that references the filter * @param filteredNode the graphics node to filter * @param inputFilter the <code>Filter</code> that represents the current filter input if the * filter chain. * @param filterRegion the filter area defined for the filter chain the new node will be part of. * @param filterMap a map where the mediator can map a name to the <code>Filter</code> it creates. * Other <code>FilterBridge</code>s can then access a filter node from the filterMap if they * know its name. */ public Filter createFilter( BridgeContext ctx, Element filterElement, Element filteredElement, GraphicsNode filteredNode, Filter inputFilter, Rectangle2D filterRegion, Map filterMap) { // 'surfaceScale' attribute - default is 1 float surfaceScale = convertNumber(filterElement, SVG_SURFACE_SCALE_ATTRIBUTE, 1, ctx); // 'specularConstant' attribute - default is 1 float specularConstant = convertNumber(filterElement, SVG_SPECULAR_CONSTANT_ATTRIBUTE, 1, ctx); // 'specularExponent' attribute - default is 1 float specularExponent = convertSpecularExponent(filterElement, ctx); // extract the light definition from the filterElement's children list Light light = extractLight(filterElement, ctx); // 'kernelUnitLength' attribute double[] kernelUnitLength = convertKernelUnitLength(filterElement, ctx); // 'in' attribute Filter in = getIn(filterElement, filteredElement, filteredNode, inputFilter, filterMap, ctx); if (in == null) { return null; // disable the filter } // Default region is the size of in (if in is SourceGraphic or // SourceAlpha it will already include a pad/crop to the // proper filter region size). Rectangle2D defaultRegion = in.getBounds2D(); Rectangle2D primitiveRegion = SVGUtilities.convertFilterPrimitiveRegion( filterElement, filteredElement, filteredNode, defaultRegion, filterRegion, ctx); Filter filter = new SpecularLightingRable8Bit( in, primitiveRegion, light, specularConstant, specularExponent, surfaceScale, kernelUnitLength); // handle the 'color-interpolation-filters' property handleColorInterpolationFilters(filter, filterElement); // update the filter Map updateFilterMap(filterElement, filter, filterMap); return filter; }
/** * Converts on the specified filter primitive element, the specified attribute that represents an * integer and with the specified default value. * * @param filterElement the filter primitive element * @param attrName the name of the attribute * @param defaultValue the default value of the attribute * @param ctx the BridgeContext to use for error information */ protected static int convertInteger( Element filterElement, String attrName, int defaultValue, BridgeContext ctx) { String s = filterElement.getAttributeNS(null, attrName); if (s.length() == 0) { return defaultValue; } else { try { return SVGUtilities.convertSVGInteger(s); } catch (NumberFormatException nfEx) { throw new BridgeException( ctx, filterElement, nfEx, ERR_ATTRIBUTE_VALUE_MALFORMED, new Object[] {attrName, s}); } } }
/** * Creates a <tt>Filter</tt> primitive according to the specified parameters. * * @param ctx the bridge context to use * @param filterElement the element that defines a filter * @param filteredElement the element that references the filter * @param filteredNode the graphics node to filter * @param inputFilter the <tt>Filter</tt> that represents the current filter input if the filter * chain. * @param filterRegion the filter area defined for the filter chain the new node will be part of. * @param filterMap a map where the mediator can map a name to the <tt>Filter</tt> it creates. * Other <tt>FilterBridge</tt>s can then access a filter node from the filterMap if they know * its name. */ public Filter createFilter( BridgeContext ctx, Element filterElement, Element filteredElement, GraphicsNode filteredNode, Filter inputFilter, Rectangle2D filterRegion, Map filterMap) { List srcs = extractFeMergeNode( filterElement, filteredElement, filteredNode, inputFilter, filterMap, ctx); if (srcs == null) { return null; // <!> FIXME: no subelement found, result unspecified } if (srcs.size() == 0) { return null; // <!> FIXME: no subelement found, result unspecified } // the default region is the input sources regions union Iterator iter = srcs.iterator(); Rectangle2D defaultRegion = (Rectangle2D) ((Filter) iter.next()).getBounds2D().clone(); while (iter.hasNext()) { defaultRegion.add(((Filter) iter.next()).getBounds2D()); } // get filter primitive chain region Rectangle2D primitiveRegion = SVGUtilities.convertFilterPrimitiveRegion( filterElement, filteredElement, filteredNode, defaultRegion, filterRegion, ctx); Filter filter = new CompositeRable8Bit(srcs, CompositeRule.OVER, true); // handle the 'color-interpolation-filters' property handleColorInterpolationFilters(filter, filterElement); filter = new PadRable8Bit(filter, primitiveRegion, PadMode.ZERO_PAD); // update the filter Map updateFilterMap(filterElement, filter, filterMap); return filter; }
/** * Creates a <tt>Filter</tt> primitive according to the specified parameters. * * @param ctx the bridge context to use * @param filterElement the element that defines a filter * @param filteredElement the element that references the filter * @param filteredNode the graphics node to filter * @param inputFilter the <tt>Filter</tt> that represents the current filter input if the filter * chain. * @param filterRegion the filter area defined for the filter chain the new node will be part of. * @param filterMap a map where the mediator can map a name to the <tt>Filter</tt> it creates. * Other <tt>FilterBridge</tt>s can then access a filter node from the filterMap if they know * its name. */ public Filter createFilter( BridgeContext ctx, Element filterElement, Element filteredElement, GraphicsNode filteredNode, Filter inputFilter, Rectangle2D filterRegion, Map filterMap) { // 'xlink:href' attribute String uriStr = XLinkSupport.getXLinkHref(filterElement); if (uriStr.length() == 0) { throw new BridgeException( ctx, filterElement, ERR_ATTRIBUTE_MISSING, 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. // 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(XLINK_NAMESPACE_URI, XLINK_HREF_QNAME, 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; Element filterDefElement = (Element) (filterElement.getParentNode()); Rectangle2D primitiveRegion = SVGUtilities.getBaseFilterPrimitiveRegion( filterElement, filteredElement, filteredNode, defaultRegion, ctx); // System.err.println(">>>>>>>> primitiveRegion : " + primitiveRegion); contentElement.setAttributeNS(null, SVG_X_ATTRIBUTE, String.valueOf(primitiveRegion.getX())); contentElement.setAttributeNS(null, SVG_Y_ATTRIBUTE, String.valueOf(primitiveRegion.getY())); contentElement.setAttributeNS( null, SVG_WIDTH_ATTRIBUTE, String.valueOf(primitiveRegion.getWidth())); contentElement.setAttributeNS( null, SVG_HEIGHT_ATTRIBUTE, String.valueOf(primitiveRegion.getHeight())); GraphicsNode node = ctx.getGVTBuilder().build(ctx, proxyElement); Filter filter = node.getGraphicsNodeRable(true); // 'primitiveUnits' attribute - default is userSpaceOnUse short coordSystemType; 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, ctx); } // Compute the transform from object bounding box to user // space if needed. AffineTransform at = new AffineTransform(); if (coordSystemType == SVGUtilities.OBJECT_BOUNDING_BOX) { at = SVGUtilities.toObjectBBox(at, filteredNode); } filter = new AffineRable8Bit(filter, at); // handle the 'color-interpolation-filters' property handleColorInterpolationFilters(filter, filterElement); // get filter primitive chain region Rectangle2D primitiveRegionUserSpace = SVGUtilities.convertFilterPrimitiveRegion( filterElement, filteredElement, filteredNode, defaultRegion, filterRegion, ctx); filter = new PadRable8Bit(filter, primitiveRegionUserSpace, PadMode.ZERO_PAD); // update the filter Map updateFilterMap(filterElement, filter, filterMap); return filter; }