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.ColorMatrixRable;
027: import org.apache.batik.ext.awt.image.renderable.ColorMatrixRable8Bit;
028: import org.apache.batik.ext.awt.image.renderable.Filter;
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 <feColorMatrix> element.
035: *
036: * @author <a href="mailto:tkormann@apache.org">Thierry Kormann</a>
037: * @version $Id: SVGFeColorMatrixElementBridge.java 504084 2007-02-06 11:24:46Z dvholten $
038: */
039: public class SVGFeColorMatrixElementBridge extends
040: AbstractSVGFilterPrimitiveElementBridge {
041:
042: /**
043: * Constructs a new bridge for the <feColorMatrix> element.
044: */
045: public SVGFeColorMatrixElementBridge() {
046: }
047:
048: /**
049: * Returns 'feColorMatrix'.
050: */
051: public String getLocalName() {
052: return SVG_FE_COLOR_MATRIX_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: // 'in' attribute
079: Filter in = getIn(filterElement, filteredElement, filteredNode,
080: inputFilter, filterMap, ctx);
081: if (in == null) {
082: return null; // disable the filter
083: }
084:
085: // Default region is the size of in (if in is SourceGraphic or
086: // SourceAlpha it will already include a pad/crop to the
087: // proper filter region size).
088: Rectangle2D defaultRegion = in.getBounds2D();
089: Rectangle2D primitiveRegion = SVGUtilities
090: .convertFilterPrimitiveRegion(filterElement,
091: filteredElement, filteredNode, defaultRegion,
092: filterRegion, ctx);
093:
094: int type = convertType(filterElement, ctx);
095: ColorMatrixRable colorMatrix;
096: switch (type) {
097: case ColorMatrixRable.TYPE_HUE_ROTATE:
098: float a = convertValuesToHueRotate(filterElement, ctx);
099: colorMatrix = ColorMatrixRable8Bit.buildHueRotate(a);
100: break;
101: case ColorMatrixRable.TYPE_LUMINANCE_TO_ALPHA:
102: colorMatrix = ColorMatrixRable8Bit.buildLuminanceToAlpha();
103: break;
104: case ColorMatrixRable.TYPE_MATRIX:
105: float[][] matrix = convertValuesToMatrix(filterElement, ctx);
106: colorMatrix = ColorMatrixRable8Bit.buildMatrix(matrix);
107: break;
108: case ColorMatrixRable.TYPE_SATURATE:
109: float s = convertValuesToSaturate(filterElement, ctx);
110: colorMatrix = ColorMatrixRable8Bit.buildSaturate(s);
111: break;
112: default:
113: throw new Error("invalid convertType:" + type); // can't be reached
114: }
115: colorMatrix.setSource(in);
116:
117: // handle the 'color-interpolation-filters' property
118: handleColorInterpolationFilters(colorMatrix, filterElement);
119:
120: Filter filter = new PadRable8Bit(colorMatrix, primitiveRegion,
121: PadMode.ZERO_PAD);
122:
123: // update the filter Map
124: updateFilterMap(filterElement, filter, filterMap);
125:
126: return filter;
127: }
128:
129: /**
130: * Converts the 'values' attribute of the specified feColorMatrix
131: * filter primitive element for the 'matrix' type.
132: *
133: * @param filterElement the filter element
134: * @param ctx the BridgeContext to use for error information
135: */
136: protected static float[][] convertValuesToMatrix(
137: Element filterElement, BridgeContext ctx) {
138: String s = filterElement.getAttributeNS(null,
139: SVG_VALUES_ATTRIBUTE);
140: float[][] matrix = new float[4][5];
141: if (s.length() == 0) {
142: matrix[0][0] = 1;
143: matrix[1][1] = 1;
144: matrix[2][2] = 1;
145: matrix[3][3] = 1;
146: return matrix;
147: }
148: StringTokenizer tokens = new StringTokenizer(s, " ,");
149: int n = 0;
150: try {
151: while (n < 20 && tokens.hasMoreTokens()) {
152: matrix[n / 5][n % 5] = SVGUtilities
153: .convertSVGNumber(tokens.nextToken());
154: n++;
155: }
156: } catch (NumberFormatException nfEx) {
157: throw new BridgeException(ctx, filterElement, nfEx,
158: ERR_ATTRIBUTE_VALUE_MALFORMED, new Object[] {
159: SVG_VALUES_ATTRIBUTE, s, nfEx });
160: }
161: if (n != 20 || tokens.hasMoreTokens()) {
162: throw new BridgeException(ctx, filterElement,
163: ERR_ATTRIBUTE_VALUE_MALFORMED, new Object[] {
164: SVG_VALUES_ATTRIBUTE, s });
165: }
166:
167: for (int i = 0; i < 4; ++i) {
168: matrix[i][4] *= 255;
169: }
170: return matrix;
171: }
172:
173: /**
174: * Converts the 'values' attribute of the specified feColorMatrix
175: * filter primitive element for the 'saturate' type.
176: *
177: * @param filterElement the filter element
178: * @param ctx the BridgeContext to use for error information
179: */
180: protected static float convertValuesToSaturate(
181: Element filterElement, BridgeContext ctx) {
182: String s = filterElement.getAttributeNS(null,
183: SVG_VALUES_ATTRIBUTE);
184: if (s.length() == 0)
185: return 1; // default is 1
186: try {
187: return SVGUtilities.convertSVGNumber(s);
188: } catch (NumberFormatException nfEx) {
189: throw new BridgeException(ctx, filterElement, nfEx,
190: ERR_ATTRIBUTE_VALUE_MALFORMED, new Object[] {
191: SVG_VALUES_ATTRIBUTE, s });
192: }
193: }
194:
195: /**
196: * Converts the 'values' attribute of the specified feColorMatrix
197: * filter primitive element for the 'hueRotate' type.
198: *
199: * @param filterElement the filter element
200: * @param ctx the BridgeContext to use for error information
201: */
202: protected static float convertValuesToHueRotate(
203: Element filterElement, BridgeContext ctx) {
204: String s = filterElement.getAttributeNS(null,
205: SVG_VALUES_ATTRIBUTE);
206: if (s.length() == 0)
207: return 0; // default is 0
208: try {
209: return (float) Math.toRadians(SVGUtilities
210: .convertSVGNumber(s));
211: } catch (NumberFormatException nfEx) {
212: throw new BridgeException(ctx, filterElement, nfEx,
213: ERR_ATTRIBUTE_VALUE_MALFORMED, new Object[] {
214: SVG_VALUES_ATTRIBUTE, s });
215: }
216: }
217:
218: /**
219: * Converts the type of the specified color matrix filter primitive.
220: *
221: * @param filterElement the filter element
222: * @param ctx the BridgeContext to use for error information
223: */
224: protected static int convertType(Element filterElement,
225: BridgeContext ctx) {
226: String s = filterElement.getAttributeNS(null,
227: SVG_TYPE_ATTRIBUTE);
228: if (s.length() == 0) {
229: return ColorMatrixRable.TYPE_MATRIX;
230: }
231: if (SVG_HUE_ROTATE_VALUE.equals(s)) {
232: return ColorMatrixRable.TYPE_HUE_ROTATE;
233: }
234: if (SVG_LUMINANCE_TO_ALPHA_VALUE.equals(s)) {
235: return ColorMatrixRable.TYPE_LUMINANCE_TO_ALPHA;
236: }
237: if (SVG_MATRIX_VALUE.equals(s)) {
238: return ColorMatrixRable.TYPE_MATRIX;
239: }
240: if (SVG_SATURATE_VALUE.equals(s)) {
241: return ColorMatrixRable.TYPE_SATURATE;
242: }
243: throw new BridgeException(ctx, filterElement,
244: ERR_ATTRIBUTE_VALUE_MALFORMED, new Object[] {
245: SVG_TYPE_ATTRIBUTE, s });
246: }
247: }
|