aboutsummaryrefslogtreecommitdiffstats
path: root/src/java/org/apache/fop/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/java/org/apache/fop/util')
-rw-r--r--src/java/org/apache/fop/util/ColorSpaceCache.java110
-rw-r--r--src/java/org/apache/fop/util/DataURIResolver.java78
-rw-r--r--src/java/org/apache/fop/util/DataURLUtil.java67
-rw-r--r--src/java/org/apache/fop/util/WriterOutputStream.java91
4 files changed, 346 insertions, 0 deletions
diff --git a/src/java/org/apache/fop/util/ColorSpaceCache.java b/src/java/org/apache/fop/util/ColorSpaceCache.java
new file mode 100644
index 000000000..92dcf8d55
--- /dev/null
+++ b/src/java/org/apache/fop/util/ColorSpaceCache.java
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.util;
+
+import java.awt.color.ColorSpace;
+import java.awt.color.ICC_ColorSpace;
+import java.awt.color.ICC_Profile;
+import java.util.Collections;
+import java.util.Map;
+
+import javax.xml.transform.Source;
+import javax.xml.transform.URIResolver;
+import javax.xml.transform.stream.StreamSource;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Map with cached ICC based ColorSpace objects.
+ */
+public class ColorSpaceCache {
+ /** logger instance */
+ private static Log log = LogFactory.getLog(ColorSpaceCache.class);
+
+ private URIResolver resolver;
+ private Map colorSpaceMap = Collections.synchronizedMap(new java.util.HashMap());
+
+ /**
+ * Default constructor
+ * @param resolver uri resolver
+ */
+ public ColorSpaceCache(URIResolver resolver) {
+ this.resolver = resolver;
+ }
+
+ /**
+ * Create (if needed) and return an ICC ColorSpace instance.
+ *
+ * The ICC profile source is taken from the src attribute of the color-profile FO element.
+ * If the ICC ColorSpace is not yet in the cache a new one is created and stored in the cache.
+ *
+ * The FOP URI resolver is used to try and locate the ICC file.
+ * If that fails null is returned.
+ *
+ * @param base a base URI to resolve relative URIs
+ * @param iccProfileSrc ICC Profile source to return a ColorSpace for
+ * @return ICC ColorSpace object or null if ColorSpace could not be created
+ */
+ public ColorSpace get(String base, String iccProfileSrc) {
+ ColorSpace colorSpace = null;
+ if (!colorSpaceMap.containsKey(base + iccProfileSrc)) {
+ try {
+ ICC_Profile iccProfile = null;
+ // First attempt to use the FOP URI resolver to locate the ICC
+ // profile
+ Source src = resolver.resolve(iccProfileSrc, base);
+ if (src != null && src instanceof StreamSource) {
+ // FOP URI resolver found ICC profile - create ICC profile
+ // from the Source
+ iccProfile = ICC_Profile.getInstance(((StreamSource) src)
+ .getInputStream());
+ } else {
+ // TODO - Would it make sense to fall back on VM ICC
+ // resolution
+ // Problem is the cache might be more difficult to maintain
+ //
+ // FOP URI resolver did not find ICC profile - perhaps the
+ // Java VM can find it?
+ // iccProfile = ICC_Profile.getInstance(iccProfileSrc);
+ }
+ if (iccProfile != null) {
+ colorSpace = new ICC_ColorSpace(iccProfile);
+ }
+ } catch (Exception e) {
+ // Ignore exception - will be logged a bit further down
+ // (colorSpace == null case)
+ }
+
+ if (colorSpace != null) {
+ // Put in cache (not when VM resolved it as we can't control
+ colorSpaceMap.put(base + iccProfileSrc, colorSpace);
+ } else {
+ // TODO To avoid an excessive amount of warnings perhaps
+ // register a null ColorMap in the colorSpaceMap
+ log.warn("Color profile '" + iccProfileSrc + "' not found.");
+ }
+ } else {
+ colorSpace = (ColorSpace)colorSpaceMap.get(base
+ + iccProfileSrc);
+ }
+ return colorSpace;
+ }
+}
diff --git a/src/java/org/apache/fop/util/DataURIResolver.java b/src/java/org/apache/fop/util/DataURIResolver.java
new file mode 100644
index 000000000..4ae4be156
--- /dev/null
+++ b/src/java/org/apache/fop/util/DataURIResolver.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.util;
+
+import java.io.ByteArrayInputStream;
+
+import javax.xml.transform.Source;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.URIResolver;
+import javax.xml.transform.stream.StreamSource;
+
+// base64 support for "data" urls
+import org.apache.xmlgraphics.util.io.Base64DecodeStream;
+
+/**
+ * Resolves data URLs (described in RFC 2397) returning its data as a StreamSource.
+ *
+ * @see javax.xml.transform.URIResolver
+ * @see <a href="http://www.ietf.org/rfc/rfc2397">RFC 2397</a>
+ */
+public class DataURIResolver implements URIResolver {
+
+ /**
+ * @see javax.xml.transform.URIResolver#resolve(java.lang.String, java.lang.String)
+ */
+ public Source resolve(String href, String base) throws TransformerException {
+ if (href.startsWith("data:")) {
+ return parseDataURI(href);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Parses inline data URIs as generated by MS Word's XML export and FO
+ * stylesheet.
+ *
+ * @see <a href="http://www.ietf.org/rfc/rfc2397">RFC 2397</a>
+ */
+ private Source parseDataURI(String href) {
+ int commaPos = href.indexOf(',');
+ // header is of the form data:[<mediatype>][;base64]
+ String header = href.substring(0, commaPos);
+ String data = href.substring(commaPos + 1);
+ if (header.endsWith(";base64")) {
+ byte[] bytes = data.getBytes();
+ ByteArrayInputStream encodedStream = new ByteArrayInputStream(bytes);
+ Base64DecodeStream decodedStream = new Base64DecodeStream(
+ encodedStream);
+ return new StreamSource(decodedStream);
+ } else {
+ // Note that this is not quite the full story here. But since we are
+ // only interested
+ // in base64-encoded binary data, the next line will probably never
+ // be called.
+ //TODO Handle un-escaping of special URL chars like %20
+ return new StreamSource(new java.io.StringReader(data));
+ }
+ }
+
+}
diff --git a/src/java/org/apache/fop/util/DataURLUtil.java b/src/java/org/apache/fop/util/DataURLUtil.java
new file mode 100644
index 000000000..03236dd45
--- /dev/null
+++ b/src/java/org/apache/fop/util/DataURLUtil.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringWriter;
+import java.io.Writer;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.xmlgraphics.util.io.Base64EncodeStream;
+
+/**
+ * Utility classes for generating RFC 2397 data URLs.
+ */
+public class DataURLUtil {
+
+ /**
+ * Creates a new data URL and returns it as a String.
+ * @param in the InputStream to read the data from
+ * @param mediatype the MIME type of the content, or null
+ * @return the newly created data URL
+ * @throws IOException if an I/O error occurs
+ */
+ public static String createDataURL(InputStream in, String mediatype) throws IOException {
+ StringWriter writer = new StringWriter();
+ writeDataURL(in, mediatype, writer);
+ return writer.toString();
+ }
+
+ /**
+ * Generates a data URL and writes it to a Writer.
+ * @param in the InputStream to read the data from
+ * @param mediatype the MIME type of the content, or null
+ * @param writer the Writer to write to
+ * @throws IOException if an I/O error occurs
+ */
+ public static void writeDataURL(InputStream in, String mediatype, Writer writer)
+ throws IOException {
+ writer.write("data:");
+ if (mediatype != null) {
+ writer.write(mediatype);
+ }
+ writer.write(";base64,");
+ Base64EncodeStream out = new Base64EncodeStream(
+ new WriterOutputStream(writer, "US-ASCII"));
+ IOUtils.copy(in, out);
+ out.flush();
+ }
+}
diff --git a/src/java/org/apache/fop/util/WriterOutputStream.java b/src/java/org/apache/fop/util/WriterOutputStream.java
new file mode 100644
index 000000000..d1908996a
--- /dev/null
+++ b/src/java/org/apache/fop/util/WriterOutputStream.java
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.util;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.Writer;
+
+/**
+ * An OutputStream wrapper for a Writer.
+ */
+public class WriterOutputStream extends OutputStream {
+
+ private Writer writer;
+ private String encoding;
+
+ /**
+ * Creates a new WriterOutputStream.
+ * @param writer the Writer to write to
+ */
+ public WriterOutputStream(Writer writer) {
+ this(writer, null);
+ }
+
+ /**
+ * Creates a new WriterOutputStream.
+ * @param writer the Writer to write to
+ * @param encoding the encoding to use, or null if the default encoding should be used
+ */
+ public WriterOutputStream(Writer writer, String encoding) {
+ this.writer = writer;
+ this.encoding = encoding;
+ }
+
+ /**
+ * @see java.io.OutputStream#close()
+ */
+ public void close() throws IOException {
+ writer.close();
+ }
+
+ /**
+ * @see java.io.OutputStream#flush()
+ */
+ public void flush() throws IOException {
+ writer.flush();
+ }
+
+ /**
+ * @see java.io.OutputStream#write(byte[], int, int)
+ */
+ public void write(byte[] buf, int offset, int length) throws IOException {
+ if (encoding != null) {
+ writer.write(new String(buf, offset, length, encoding));
+ } else {
+ writer.write(new String(buf, offset, length));
+ }
+ }
+
+ /**
+ * @see java.io.OutputStream#write(byte[])
+ */
+ public void write(byte[] buf) throws IOException {
+ write(buf, 0, buf.length);
+ }
+
+ /**
+ * @see java.io.OutputStream#write(int)
+ */
+ public void write(int b) throws IOException {
+ write(new byte[] {(byte)b});
+ }
+
+}