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.ComponentTransferFunction;
026: import org.apache.batik.ext.awt.image.ConcreteComponentTransferFunction;
027: import org.apache.batik.ext.awt.image.PadMode;
028: import org.apache.batik.ext.awt.image.renderable.ComponentTransferRable8Bit;
029: import org.apache.batik.ext.awt.image.renderable.Filter;
030: import org.apache.batik.ext.awt.image.renderable.PadRable8Bit;
031: import org.apache.batik.gvt.GraphicsNode;
032: import org.w3c.dom.Element;
033: import org.w3c.dom.Node;
034:
035: /**
036: * Bridge class for the <feComponentTransfer> element.
037: *
038: * @author <a href="mailto:tkormann@apache.org">Thierry Kormann</a>
039: * @version $Id: SVGFeComponentTransferElementBridge.java 504084 2007-02-06 11:24:46Z dvholten $
040: */
041: public class SVGFeComponentTransferElementBridge extends
042: AbstractSVGFilterPrimitiveElementBridge {
043:
044: /**
045: * Constructs a new bridge for the <feComponentTransfer> element.
046: */
047: public SVGFeComponentTransferElementBridge() {
048: }
049:
050: /**
051: * Returns 'feComponentTransfer'.
052: */
053: public String getLocalName() {
054: return SVG_FE_COMPONENT_TRANSFER_TAG;
055: }
056:
057: /**
058: * Creates a <tt>Filter</tt> primitive according to the specified
059: * parameters.
060: *
061: * @param ctx the bridge context to use
062: * @param filterElement the element that defines a filter
063: * @param filteredElement the element that references the filter
064: * @param filteredNode the graphics node to filter
065: *
066: * @param inputFilter the <tt>Filter</tt> that represents the current
067: * filter input if the filter chain.
068: * @param filterRegion the filter area defined for the filter chain
069: * the new node will be part of.
070: * @param filterMap a map where the mediator can map a name to the
071: * <tt>Filter</tt> it creates. Other <tt>FilterBridge</tt>s
072: * can then access a filter node from the filterMap if they
073: * know its name.
074: */
075: public Filter createFilter(BridgeContext ctx,
076: Element filterElement, Element filteredElement,
077: GraphicsNode filteredNode, Filter inputFilter,
078: Rectangle2D filterRegion, Map filterMap) {
079:
080: // 'in' attribute
081: Filter in = getIn(filterElement, filteredElement, filteredNode,
082: inputFilter, filterMap, ctx);
083: if (in == null) {
084: return null; // disable the filter
085: }
086:
087: // Default region is the size of in (if in is SourceGraphic or
088: // SourceAlpha it will already include a pad/crop to the
089: // proper filter region size).
090: Rectangle2D defaultRegion = in.getBounds2D();
091: Rectangle2D primitiveRegion = SVGUtilities
092: .convertFilterPrimitiveRegion(filterElement,
093: filteredElement, filteredNode, defaultRegion,
094: filterRegion, ctx);
095:
096: // Now, extract the various transfer functions. They are
097: // defined in the filterElement's children.
098: // Functions are ordered as follow: r, g, b, a.
099: ComponentTransferFunction funcR = null;
100: ComponentTransferFunction funcG = null;
101: ComponentTransferFunction funcB = null;
102: ComponentTransferFunction funcA = null;
103:
104: for (Node n = filterElement.getFirstChild(); n != null; n = n
105: .getNextSibling()) {
106:
107: if (n.getNodeType() != Node.ELEMENT_NODE) {
108: continue;
109: }
110:
111: Element e = (Element) n;
112: Bridge bridge = ctx.getBridge(e);
113: if (bridge == null
114: || !(bridge instanceof SVGFeFuncElementBridge)) {
115: continue;
116: }
117: SVGFeFuncElementBridge funcBridge = (SVGFeFuncElementBridge) bridge;
118: ComponentTransferFunction func = funcBridge
119: .createComponentTransferFunction(filterElement, e);
120: if (funcBridge instanceof SVGFeFuncRElementBridge) {
121: funcR = func;
122: } else if (funcBridge instanceof SVGFeFuncGElementBridge) {
123: funcG = func;
124: } else if (funcBridge instanceof SVGFeFuncBElementBridge) {
125: funcB = func;
126: } else if (funcBridge instanceof SVGFeFuncAElementBridge) {
127: funcA = func;
128: }
129: }
130:
131: Filter filter = new ComponentTransferRable8Bit(in, funcA,
132: funcR, funcG, funcB);
133:
134: // handle the 'color-interpolation-filters' property
135: handleColorInterpolationFilters(filter, filterElement);
136:
137: filter = new PadRable8Bit(filter, primitiveRegion,
138: PadMode.ZERO_PAD);
139:
140: // update the filter Map
141: updateFilterMap(filterElement, filter, filterMap);
142:
143: return filter;
144: }
145:
146: /**
147: * Bridge class for the <feFuncA> element.
148: */
149: public static class SVGFeFuncAElementBridge extends
150: SVGFeFuncElementBridge {
151:
152: /**
153: * Constructs a new bridge for the <tt>feFuncA</tt> element.
154: */
155: public SVGFeFuncAElementBridge() {
156: }
157:
158: /**
159: * Returns 'feFuncA'.
160: */
161: public String getLocalName() {
162: return SVG_FE_FUNC_A_TAG;
163: }
164: }
165:
166: /**
167: * Bridge class for the <feFuncR> element.
168: */
169: public static class SVGFeFuncRElementBridge extends
170: SVGFeFuncElementBridge {
171:
172: /**
173: * Constructs a new bridge for the <tt>feFuncR</tt> element.
174: */
175: public SVGFeFuncRElementBridge() {
176: }
177:
178: /**
179: * Returns 'feFuncR'.
180: */
181: public String getLocalName() {
182: return SVG_FE_FUNC_R_TAG;
183: }
184: }
185:
186: /**
187: * Bridge class for the <feFuncG> element.
188: */
189: public static class SVGFeFuncGElementBridge extends
190: SVGFeFuncElementBridge {
191:
192: /**
193: * Constructs a new bridge for the <tt>feFuncG</tt> element.
194: */
195: public SVGFeFuncGElementBridge() {
196: }
197:
198: /**
199: * Returns 'feFuncG'.
200: */
201: public String getLocalName() {
202: return SVG_FE_FUNC_G_TAG;
203: }
204: }
205:
206: /**
207: * Bridge class for the <feFuncB> element.
208: */
209: public static class SVGFeFuncBElementBridge extends
210: SVGFeFuncElementBridge {
211:
212: /**
213: * Constructs a new bridge for the <tt>feFuncB</tt> element.
214: */
215: public SVGFeFuncBElementBridge() {
216: }
217:
218: /**
219: * Returns 'feFuncB'.
220: */
221: public String getLocalName() {
222: return SVG_FE_FUNC_B_TAG;
223: }
224: }
225:
226: /**
227: * The base bridge class for component transfer function.
228: */
229: protected abstract static class SVGFeFuncElementBridge extends
230: AnimatableGenericSVGBridge {
231:
232: /**
233: * Constructs a new bridge for component transfer function.
234: */
235: protected SVGFeFuncElementBridge() {
236: }
237:
238: /**
239: * Creates a <tt>ComponentTransferFunction</tt> according to
240: * the specified parameters.
241: *
242: * @param filterElement the feComponentTransfer filter primitive element
243: * @param funcElement the feFuncX element
244: */
245: public ComponentTransferFunction createComponentTransferFunction(
246: Element filterElement, Element funcElement) {
247:
248: int type = convertType(funcElement, ctx);
249: switch (type) {
250: case ComponentTransferFunction.DISCRETE: {
251: float[] v = convertTableValues(funcElement, ctx);
252: if (v == null) {
253: return ConcreteComponentTransferFunction
254: .getIdentityTransfer();
255: } else {
256: return ConcreteComponentTransferFunction
257: .getDiscreteTransfer(v);
258: }
259: }
260: case ComponentTransferFunction.IDENTITY: {
261: return ConcreteComponentTransferFunction
262: .getIdentityTransfer();
263: }
264: case ComponentTransferFunction.GAMMA: {
265: // 'amplitude' attribute - default is 1
266: float amplitude = convertNumber(funcElement,
267: SVG_AMPLITUDE_ATTRIBUTE, 1, ctx);
268: // 'exponent' attribute - default is 1
269: float exponent = convertNumber(funcElement,
270: SVG_EXPONENT_ATTRIBUTE, 1, ctx);
271: // 'offset' attribute - default is 0
272: float offset = convertNumber(funcElement,
273: SVG_OFFSET_ATTRIBUTE, 0, ctx);
274:
275: return ConcreteComponentTransferFunction
276: .getGammaTransfer(amplitude, exponent, offset);
277: }
278: case ComponentTransferFunction.LINEAR: {
279: // 'slope' attribute - default is 1
280: float slope = convertNumber(funcElement,
281: SVG_SLOPE_ATTRIBUTE, 1, ctx);
282: // 'intercept' attribute - default is 0
283: float intercept = convertNumber(funcElement,
284: SVG_INTERCEPT_ATTRIBUTE, 0, ctx);
285:
286: return ConcreteComponentTransferFunction
287: .getLinearTransfer(slope, intercept);
288: }
289: case ComponentTransferFunction.TABLE: {
290: float[] v = convertTableValues(funcElement, ctx);
291: if (v == null) {
292: return ConcreteComponentTransferFunction
293: .getIdentityTransfer();
294: } else {
295: return ConcreteComponentTransferFunction
296: .getTableTransfer(v);
297: }
298: }
299: default:
300: throw new Error("invalid convertType:" + type); // can't be reached
301: }
302:
303: }
304:
305: /**
306: * Converts the 'tableValues' attribute of the specified component
307: * transfer function element.
308: *
309: * @param e the element that represents a component transfer function
310: * @param ctx the BridgeContext to use for error information
311: */
312: protected static float[] convertTableValues(Element e,
313: BridgeContext ctx) {
314: String s = e.getAttributeNS(null,
315: SVG_TABLE_VALUES_ATTRIBUTE);
316: if (s.length() == 0) {
317: return null;
318: }
319: StringTokenizer tokens = new StringTokenizer(s, " ,");
320: float[] v = new float[tokens.countTokens()];
321: try {
322: for (int i = 0; tokens.hasMoreTokens(); ++i) {
323: v[i] = SVGUtilities.convertSVGNumber(tokens
324: .nextToken());
325: }
326: } catch (NumberFormatException nfEx) {
327: throw new BridgeException(ctx, e, nfEx,
328: ERR_ATTRIBUTE_VALUE_MALFORMED, new Object[] {
329: SVG_TABLE_VALUES_ATTRIBUTE, s });
330: }
331: return v;
332: }
333:
334: /**
335: * Converts the type of the specified component transfert
336: * function element.
337: *
338: * @param e the element that represents a component transfer function
339: * @param ctx the BridgeContext to use for error information
340: */
341: protected static int convertType(Element e, BridgeContext ctx) {
342: String s = e.getAttributeNS(null, SVG_TYPE_ATTRIBUTE);
343: if (s.length() == 0) {
344: throw new BridgeException(ctx, e,
345: ERR_ATTRIBUTE_MISSING,
346: new Object[] { SVG_TYPE_ATTRIBUTE });
347: }
348: if (SVG_DISCRETE_VALUE.equals(s)) {
349: return ComponentTransferFunction.DISCRETE;
350: }
351: if (SVG_IDENTITY_VALUE.equals(s)) {
352: return ComponentTransferFunction.IDENTITY;
353: }
354: if (SVG_GAMMA_VALUE.equals(s)) {
355: return ComponentTransferFunction.GAMMA;
356: }
357: if (SVG_LINEAR_VALUE.equals(s)) {
358: return ComponentTransferFunction.LINEAR;
359: }
360: if (SVG_TABLE_VALUE.equals(s)) {
361: return ComponentTransferFunction.TABLE;
362: }
363: throw new BridgeException(ctx, e,
364: ERR_ATTRIBUTE_VALUE_MALFORMED, new Object[] {
365: SVG_TYPE_ATTRIBUTE, s });
366: }
367: }
368: }
|