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.svggen;
020:
021: import java.awt.Rectangle;
022: import java.awt.image.BufferedImageOp;
023: import java.awt.image.RescaleOp;
024:
025: import org.w3c.dom.Document;
026: import org.w3c.dom.Element;
027:
028: /**
029: * Utility class that converts a RescaleOp object into
030: * an SVG filter descriptor. The SVG filter corresponding
031: * to a RescaleOp is an feComponentTransfer, with a type
032: * set to 'linear', the slopes equal to the RescapeOp
033: * scaleFactors and the intercept equal to the RescapeOp
034: * offsets.
035: *
036: * @author <a href="mailto:vincent.hardy@eng.sun.com">Vincent Hardy</a>
037: * @version $Id: SVGRescaleOp.java 476924 2006-11-19 21:13:26Z dvholten $
038: * @see org.apache.batik.svggen.SVGBufferedImageOp
039: */
040: public class SVGRescaleOp extends AbstractSVGFilterConverter {
041:
042: /**
043: * @param generatorContext used to build Elements
044: */
045: public SVGRescaleOp(SVGGeneratorContext generatorContext) {
046: super (generatorContext);
047: }
048:
049: /**
050: * Converts a Java 2D API BufferedImageOp into
051: * a set of attribute/value pairs and related definitions
052: *
053: * @param filter BufferedImageOp filter to be converted
054: * @param filterRect Rectangle, in device space, that defines the area
055: * to which filtering applies. May be null, meaning that the
056: * area is undefined.
057: * @return descriptor of the attributes required to represent
058: * the input filter
059: * @see org.apache.batik.svggen.SVGFilterDescriptor
060: */
061: public SVGFilterDescriptor toSVG(BufferedImageOp filter,
062: Rectangle filterRect) {
063: if (filter instanceof RescaleOp)
064: return toSVG((RescaleOp) filter);
065: else
066: return null;
067: }
068:
069: /**
070: * @param rescaleOp the RescaleOp to be converted
071: * @return a description of the SVG filter corresponding to
072: * rescaleOp. The definition of the feComponentTransfer
073: * filter in put in feComponentTransferDefSet
074: */
075: public SVGFilterDescriptor toSVG(RescaleOp rescaleOp) {
076: // Reuse definition if rescaleOp has already been converted
077: SVGFilterDescriptor filterDesc = (SVGFilterDescriptor) descMap
078: .get(rescaleOp);
079:
080: Document domFactory = generatorContext.domFactory;
081:
082: if (filterDesc == null) {
083: //
084: // First time filter is converted: create its corresponding
085: // SVG filter
086: //
087: Element filterDef = domFactory.createElementNS(
088: SVG_NAMESPACE_URI, SVG_FILTER_TAG);
089: Element feComponentTransferDef = domFactory
090: .createElementNS(SVG_NAMESPACE_URI,
091: SVG_FE_COMPONENT_TRANSFER_TAG);
092:
093: // Append transfer function for each component, setting
094: // the attributes corresponding to the scale and offset.
095: // Because we are using a RescaleOp as a BufferedImageOp,
096: // the scaleFactors must be either:
097: // + 1, in which case the same scale is applied to the
098: // Red, Green and Blue components,
099: // + 3, in which case the scale factors apply to the
100: // Red, Green and Blue components
101: // + 4, in which case the scale factors apply to the
102: // Red, Green, Blue and Alpha components
103: float[] offsets = rescaleOp.getOffsets(null);
104: float[] scaleFactors = rescaleOp.getScaleFactors(null);
105: if (offsets.length != scaleFactors.length)
106: throw new SVGGraphics2DRuntimeException(
107: ERR_SCALE_FACTORS_AND_OFFSETS_MISMATCH);
108:
109: if (offsets.length != 1 && offsets.length != 3
110: && offsets.length != 4)
111: throw new SVGGraphics2DRuntimeException(
112: ERR_ILLEGAL_BUFFERED_IMAGE_RESCALE_OP);
113:
114: Element feFuncR = domFactory.createElementNS(
115: SVG_NAMESPACE_URI, SVG_FE_FUNC_R_TAG);
116: Element feFuncG = domFactory.createElementNS(
117: SVG_NAMESPACE_URI, SVG_FE_FUNC_G_TAG);
118: Element feFuncB = domFactory.createElementNS(
119: SVG_NAMESPACE_URI, SVG_FE_FUNC_B_TAG);
120: Element feFuncA = null;
121: String type = SVG_LINEAR_VALUE;
122:
123: if (offsets.length == 1) {
124: String slope = doubleString(scaleFactors[0]);
125: String intercept = doubleString(offsets[0]);
126: feFuncR.setAttributeNS(null, SVG_TYPE_ATTRIBUTE, type);
127: feFuncG.setAttributeNS(null, SVG_TYPE_ATTRIBUTE, type);
128: feFuncB.setAttributeNS(null, SVG_TYPE_ATTRIBUTE, type);
129: feFuncR
130: .setAttributeNS(null, SVG_SLOPE_ATTRIBUTE,
131: slope);
132: feFuncG
133: .setAttributeNS(null, SVG_SLOPE_ATTRIBUTE,
134: slope);
135: feFuncB
136: .setAttributeNS(null, SVG_SLOPE_ATTRIBUTE,
137: slope);
138: feFuncR.setAttributeNS(null, SVG_INTERCEPT_ATTRIBUTE,
139: intercept);
140: feFuncG.setAttributeNS(null, SVG_INTERCEPT_ATTRIBUTE,
141: intercept);
142: feFuncB.setAttributeNS(null, SVG_INTERCEPT_ATTRIBUTE,
143: intercept);
144: } else if (offsets.length >= 3) {
145: feFuncR.setAttributeNS(null, SVG_TYPE_ATTRIBUTE, type);
146: feFuncG.setAttributeNS(null, SVG_TYPE_ATTRIBUTE, type);
147: feFuncB.setAttributeNS(null, SVG_TYPE_ATTRIBUTE, type);
148: feFuncR.setAttributeNS(null, SVG_SLOPE_ATTRIBUTE,
149: doubleString(scaleFactors[0]));
150: feFuncG.setAttributeNS(null, SVG_SLOPE_ATTRIBUTE,
151: doubleString(scaleFactors[1]));
152: feFuncB.setAttributeNS(null, SVG_SLOPE_ATTRIBUTE,
153: doubleString(scaleFactors[2]));
154: feFuncR.setAttributeNS(null, SVG_INTERCEPT_ATTRIBUTE,
155: doubleString(offsets[0]));
156: feFuncG.setAttributeNS(null, SVG_INTERCEPT_ATTRIBUTE,
157: doubleString(offsets[1]));
158: feFuncB.setAttributeNS(null, SVG_INTERCEPT_ATTRIBUTE,
159: doubleString(offsets[2]));
160:
161: if (offsets.length == 4) {
162: feFuncA = domFactory.createElementNS(
163: SVG_NAMESPACE_URI, SVG_FE_FUNC_A_TAG);
164: feFuncA.setAttributeNS(null, SVG_TYPE_ATTRIBUTE,
165: type);
166: feFuncA.setAttributeNS(null, SVG_SLOPE_ATTRIBUTE,
167: doubleString(scaleFactors[3]));
168: feFuncA.setAttributeNS(null,
169: SVG_INTERCEPT_ATTRIBUTE,
170: doubleString(offsets[3]));
171: }
172: }
173:
174: feComponentTransferDef.appendChild(feFuncR);
175: feComponentTransferDef.appendChild(feFuncG);
176: feComponentTransferDef.appendChild(feFuncB);
177: if (feFuncA != null)
178: feComponentTransferDef.appendChild(feFuncA);
179:
180: filterDef.appendChild(feComponentTransferDef);
181:
182: filterDef
183: .setAttributeNS(
184: null,
185: SVG_ID_ATTRIBUTE,
186: generatorContext.idGenerator
187: .generateID(ID_PREFIX_FE_COMPONENT_TRANSFER));
188:
189: //
190: // Create a filter descriptor
191: //
192:
193: // Process filter attribute
194: // StringBuffer filterAttrBuf = new StringBuffer(URL_PREFIX);
195: // filterAttrBuf.append(SIGN_POUND);
196: // filterAttrBuf.append(filterDef.getAttributeNS(null, SVG_ID_ATTRIBUTE));
197: // filterAttrBuf.append(URL_SUFFIX);
198:
199: String filterAttrBuf = URL_PREFIX + SIGN_POUND
200: + filterDef.getAttributeNS(null, SVG_ID_ATTRIBUTE)
201: + URL_SUFFIX;
202:
203: filterDesc = new SVGFilterDescriptor(filterAttrBuf,
204: filterDef);
205:
206: defSet.add(filterDef);
207: descMap.put(rescaleOp, filterDesc);
208: }
209:
210: return filterDesc;
211: }
212: }
|