001: /*
002:
003: Licensed to the Apache Software Foundation (ASF) under one or more
004: contributor license agreements. See the NOTICE file distributed with
005: this work for additional information regarding copyright ownership.
006: The ASF licenses this file to You under the Apache License, Version 2.0
007: (the "License"); you may not use this file except in compliance with
008: the License. You may obtain a copy of the License at
009:
010: http://www.apache.org/licenses/LICENSE-2.0
011:
012: Unless required by applicable law or agreed to in writing, software
013: distributed under the License is distributed on an "AS IS" BASIS,
014: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015: See the License for the specific language governing permissions and
016: limitations under the License.
017:
018: */
019: package org.apache.batik.bridge;
020:
021: import java.awt.geom.Rectangle2D;
022: import java.util.Map;
023: import java.util.StringTokenizer;
024:
025: import org.apache.batik.ext.awt.image.PadMode;
026: import org.apache.batik.ext.awt.image.renderable.Filter;
027: import org.apache.batik.ext.awt.image.renderable.MorphologyRable8Bit;
028: import org.apache.batik.ext.awt.image.renderable.PadRable;
029: import org.apache.batik.ext.awt.image.renderable.PadRable8Bit;
030: import org.apache.batik.gvt.GraphicsNode;
031: import org.w3c.dom.Element;
032:
033: /**
034: * Bridge class for the <feMorphology> element.
035: *
036: * @author <a href="mailto:tkormann@apache.org">Thierry Kormann</a>
037: * @version $Id: SVGFeMorphologyElementBridge.java 501922 2007-01-31 17:47:47Z dvholten $
038: */
039: public class SVGFeMorphologyElementBridge extends
040: AbstractSVGFilterPrimitiveElementBridge {
041:
042: /**
043: * Constructs a new bridge for the <feMorphology> element.
044: */
045: public SVGFeMorphologyElementBridge() {
046: }
047:
048: /**
049: * Returns 'feMorphology'.
050: */
051: public String getLocalName() {
052: return SVG_FE_MORPHOLOGY_TAG;
053: }
054:
055: /**
056: * Creates a <tt>Filter</tt> primitive according to the specified
057: * parameters.
058: *
059: * @param ctx the bridge context to use
060: * @param filterElement the element that defines a filter
061: * @param filteredElement the element that references the filter
062: * @param filteredNode the graphics node to filter
063: *
064: * @param inputFilter the <tt>Filter</tt> that represents the current
065: * filter input if the filter chain.
066: * @param filterRegion the filter area defined for the filter chain
067: * the new node will be part of.
068: * @param filterMap a map where the mediator can map a name to the
069: * <tt>Filter</tt> it creates. Other <tt>FilterBridge</tt>s
070: * can then access a filter node from the filterMap if they
071: * know its name.
072: */
073: public Filter createFilter(BridgeContext ctx,
074: Element filterElement, Element filteredElement,
075: GraphicsNode filteredNode, Filter inputFilter,
076: Rectangle2D filterRegion, Map filterMap) {
077:
078: // 'radius' attribute - default is [0, 0]
079: float[] radii = convertRadius(filterElement, ctx);
080: if (radii[0] == 0 || radii[1] == 0) {
081: return null; // disable the filter
082: }
083:
084: // 'operator' attribute - default is 'erode'
085: boolean isDilate = convertOperator(filterElement, ctx);
086:
087: // 'in' attribute
088: Filter in = getIn(filterElement, filteredElement, filteredNode,
089: inputFilter, filterMap, ctx);
090: if (in == null) {
091: return null; // disable the filter
092: }
093:
094: // Default region is the size of in (if in is SourceGraphic or
095: // SourceAlpha it will already include a pad/crop to the
096: // proper filter region size).
097: Rectangle2D defaultRegion = in.getBounds2D();
098: Rectangle2D primitiveRegion = SVGUtilities
099: .convertFilterPrimitiveRegion(filterElement,
100: filteredElement, filteredNode, defaultRegion,
101: filterRegion, ctx);
102:
103: // Take the filter primitive region into account, we need to
104: // pad/crop the input and output.
105: PadRable pad = new PadRable8Bit(in, primitiveRegion,
106: PadMode.ZERO_PAD);
107:
108: // build tfilter
109: Filter morphology = new MorphologyRable8Bit(pad, radii[0],
110: radii[1], isDilate);
111:
112: // handle the 'color-interpolation-filters' property
113: handleColorInterpolationFilters(morphology, filterElement);
114:
115: PadRable filter = new PadRable8Bit(morphology, primitiveRegion,
116: PadMode.ZERO_PAD);
117:
118: // update the filter Map
119: updateFilterMap(filterElement, filter, filterMap);
120:
121: return filter;
122: }
123:
124: /**
125: * Returns the radius (or radii) of the specified feMorphology
126: * filter primitive.
127: *
128: * @param filterElement the feMorphology filter primitive
129: * @param ctx the BridgeContext to use for error information
130: */
131: protected static float[] convertRadius(Element filterElement,
132: BridgeContext ctx) {
133: String s = filterElement.getAttributeNS(null,
134: SVG_RADIUS_ATTRIBUTE);
135: if (s.length() == 0) {
136: return new float[] { 0, 0 };
137: }
138: float[] radii = new float[2];
139: StringTokenizer tokens = new StringTokenizer(s, " ,");
140: try {
141: radii[0] = SVGUtilities
142: .convertSVGNumber(tokens.nextToken());
143: if (tokens.hasMoreTokens()) {
144: radii[1] = SVGUtilities.convertSVGNumber(tokens
145: .nextToken());
146: } else {
147: radii[1] = radii[0];
148: }
149: } catch (NumberFormatException nfEx) {
150: throw new BridgeException(ctx, filterElement, nfEx,
151: ERR_ATTRIBUTE_VALUE_MALFORMED, new Object[] {
152: SVG_RADIUS_ATTRIBUTE, s, nfEx });
153: }
154: if (tokens.hasMoreTokens() || radii[0] < 0 || radii[1] < 0) {
155: throw new BridgeException(ctx, filterElement,
156: ERR_ATTRIBUTE_VALUE_MALFORMED, new Object[] {
157: SVG_RADIUS_ATTRIBUTE, s });
158: }
159: return radii;
160: }
161:
162: /**
163: * Returns the 'operator' of the specified feMorphology filter
164: * primitive.
165: *
166: * @param filterElement the feMorphology filter primitive
167: * @param ctx the BridgeContext to use for error information
168: */
169: protected static boolean convertOperator(Element filterElement,
170: BridgeContext ctx) {
171: String s = filterElement.getAttributeNS(null,
172: SVG_OPERATOR_ATTRIBUTE);
173: if (s.length() == 0) {
174: return false;
175: }
176: if (SVG_ERODE_VALUE.equals(s)) {
177: return false;
178: }
179: if (SVG_DILATE_VALUE.equals(s)) {
180: return true;
181: }
182: throw new BridgeException(ctx, filterElement,
183: ERR_ATTRIBUTE_VALUE_MALFORMED, new Object[] {
184: SVG_OPERATOR_ATTRIBUTE, s });
185: }
186: }
|