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.color.ICC_Profile;
022: import java.io.IOException;
023:
024: import org.apache.batik.dom.AbstractNode;
025: import org.apache.batik.dom.util.XLinkSupport;
026: import org.apache.batik.ext.awt.color.ICCColorSpaceExt;
027: import org.apache.batik.ext.awt.color.NamedProfileCache;
028: import org.apache.batik.util.ParsedURL;
029:
030: import org.w3c.dom.Document;
031: import org.w3c.dom.Element;
032: import org.w3c.dom.Node;
033: import org.w3c.dom.NodeList;
034:
035: /**
036: * This class bridges an SVG <tt>color-profile</tt> element with an
037: * <tt>ICC_ColorSpace</tt> object.
038: *
039: * @author <a href="mailto:vincent.hardy@eng.sun.com">Vincent Hardy</a>
040: * @version $Id: SVGColorProfileElementBridge.java 501922 2007-01-31 17:47:47Z dvholten $ */
041: public class SVGColorProfileElementBridge extends AbstractSVGBridge
042: implements ErrorConstants {
043:
044: /**
045: * Profile cache
046: */
047: public NamedProfileCache cache = new NamedProfileCache();
048:
049: /**
050: * Returns 'colorProfile'.
051: */
052: public String getLocalName() {
053: return SVG_COLOR_PROFILE_TAG;
054: }
055:
056: /**
057: * Creates an ICC_ColorSpace according to the specified parameters.
058: *
059: * @param ctx the bridge context to use
060: * @param paintedElement element on which the color is painted
061: * @param iccProfileName name of the profile that should be loaded
062: * that could be a color-profile element or an @color-profile
063: * CSS rule
064: */
065: public ICCColorSpaceExt createICCColorSpaceExt(BridgeContext ctx,
066: Element paintedElement, String iccProfileName) {
067: // Check if there is one if the cache.
068: ICCColorSpaceExt cs = cache.request(iccProfileName
069: .toLowerCase()); // todo locale??
070: if (cs != null) {
071: return cs;
072: }
073:
074: // There was no cached copies for the profile. Load it now.
075: // Search for a color-profile element with specific name
076: Document doc = paintedElement.getOwnerDocument();
077: NodeList list = doc.getElementsByTagNameNS(SVG_NAMESPACE_URI,
078: SVG_COLOR_PROFILE_TAG);
079:
080: int n = list.getLength();
081: Element profile = null;
082: for (int i = 0; i < n; i++) {
083: Node node = list.item(i);
084: if (node.getNodeType() == Node.ELEMENT_NODE) {
085: Element profileNode = (Element) node;
086: String nameAttr = profileNode.getAttributeNS(null,
087: SVG_NAME_ATTRIBUTE);
088:
089: if (iccProfileName.equalsIgnoreCase(nameAttr)) {
090: profile = profileNode;
091: }
092: }
093: }
094:
095: if (profile == null)
096: return null;
097:
098: // Now that we have a profile element,
099: // try to load the corresponding ICC profile xlink:href
100: String href = XLinkSupport.getXLinkHref(profile);
101: ICC_Profile p = null;
102: if (href != null) {
103: String baseURI = ((AbstractNode) profile).getBaseURI();
104: ParsedURL pDocURL = null;
105: if (baseURI != null) {
106: pDocURL = new ParsedURL(baseURI);
107: }
108:
109: ParsedURL purl = new ParsedURL(pDocURL, href);
110: if (!purl.complete())
111: throw new BridgeException(ctx, paintedElement,
112: ERR_URI_MALFORMED, new Object[] { href });
113: try {
114: ctx.getUserAgent().checkLoadExternalResource(purl,
115: pDocURL);
116: p = ICC_Profile.getInstance(purl.openStream());
117: } catch (IOException ioEx) {
118: throw new BridgeException(ctx, paintedElement, ioEx,
119: ERR_URI_IO, new Object[] { href });
120: // ??? IS THAT AN ERROR FOR THE SVG SPEC ???
121: } catch (SecurityException secEx) {
122: throw new BridgeException(ctx, paintedElement, secEx,
123: ERR_URI_UNSECURE, new Object[] { href });
124: }
125: }
126: if (p == null) {
127: return null;
128: }
129:
130: // Extract the rendering intent from profile element
131: int intent = convertIntent(profile, ctx);
132: cs = new ICCColorSpaceExt(p, intent);
133:
134: // Add profile to cache
135: cache.put(iccProfileName.toLowerCase(), cs);
136: return cs;
137: }
138:
139: private static int convertIntent(Element profile, BridgeContext ctx) {
140:
141: String intent = profile.getAttributeNS(null,
142: SVG_RENDERING_INTENT_ATTRIBUTE);
143:
144: if (intent.length() == 0) {
145: return ICCColorSpaceExt.AUTO;
146: }
147: if (SVG_PERCEPTUAL_VALUE.equals(intent)) {
148: return ICCColorSpaceExt.PERCEPTUAL;
149: }
150: if (SVG_AUTO_VALUE.equals(intent)) {
151: return ICCColorSpaceExt.AUTO;
152: }
153: if (SVG_RELATIVE_COLORIMETRIC_VALUE.equals(intent)) {
154: return ICCColorSpaceExt.RELATIVE_COLORIMETRIC;
155: }
156: if (SVG_ABSOLUTE_COLORIMETRIC_VALUE.equals(intent)) {
157: return ICCColorSpaceExt.ABSOLUTE_COLORIMETRIC;
158: }
159: if (SVG_SATURATION_VALUE.equals(intent)) {
160: return ICCColorSpaceExt.SATURATION;
161: }
162: throw new BridgeException(ctx, profile,
163: ERR_ATTRIBUTE_VALUE_MALFORMED, new Object[] {
164: SVG_RENDERING_INTENT_ATTRIBUTE, intent });
165: }
166: }
|