| /* |
| |
| 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. |
| |
| */ |
| package org.apache.batik.ext.awt.image.spi; |
| |
| import java.io.BufferedInputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.StreamCorruptedException; |
| import java.util.Collections; |
| import java.util.Iterator; |
| import java.util.LinkedList; |
| import java.util.List; |
| import java.util.ListIterator; |
| |
| import org.apache.batik.ext.awt.image.URLImageCache; |
| import org.apache.batik.ext.awt.image.renderable.Filter; |
| import org.apache.batik.ext.awt.image.renderable.ProfileRable; |
| import org.apache.batik.util.ParsedURL; |
| import org.apache.batik.util.Service; |
| |
| import org.apache.xmlgraphics.java2d.color.ICCColorSpaceWithIntent; |
| |
| /** |
| * This class handles the registered Image tag handlers. These are |
| * instances of RegistryEntry in this package. |
| * |
| * @author <a href="mailto:Thomas.DeWeeese@Kodak.com">Thomas DeWeese</a> |
| * @version $Id$ |
| */ |
| public class ImageTagRegistry implements ErrorConstants { |
| |
| List entries = new LinkedList(); |
| List extensions = null; |
| List mimeTypes = null; |
| |
| URLImageCache rawCache; |
| URLImageCache imgCache; |
| |
| public ImageTagRegistry() { |
| this(null, null); |
| } |
| |
| public ImageTagRegistry(URLImageCache rawCache, URLImageCache imgCache) { |
| if (rawCache == null) |
| rawCache = new URLImageCache(); |
| if (imgCache == null) |
| imgCache = new URLImageCache(); |
| |
| this.rawCache= rawCache; |
| this.imgCache= imgCache; |
| } |
| |
| /** Removes all decoded raster images from the cache. |
| * All Images will be reloaded from the original source |
| * if decoded again. |
| */ |
| public void flushCache() { |
| rawCache.flush(); |
| imgCache.flush(); |
| } |
| |
| /** Removes the given URL from the cache. Only the Image |
| * associated with that URL will be removed from the cache. |
| */ |
| public void flushImage(ParsedURL purl) { |
| rawCache.clear(purl); |
| imgCache.clear(purl); |
| } |
| |
| public Filter checkCache(ParsedURL purl, ICCColorSpaceWithIntent colorSpace) { |
| // I just realized that this whole thing could |
| boolean needRawData = (colorSpace != null); |
| |
| Filter ret = null; |
| URLImageCache cache; |
| if (needRawData) cache = rawCache; |
| else cache = imgCache; |
| |
| ret = cache.request(purl); |
| if (ret == null) { |
| cache.clear(purl); |
| return null; |
| } |
| |
| // System.out.println("Image came from cache" + purl); |
| if (colorSpace != null) |
| ret = new ProfileRable(ret, colorSpace); |
| return ret; |
| } |
| |
| public Filter readURL(ParsedURL purl) { |
| return readURL(null, purl, null, true, true); |
| } |
| |
| public Filter readURL(ParsedURL purl, ICCColorSpaceWithIntent colorSpace) { |
| return readURL(null, purl, colorSpace, true, true); |
| } |
| |
| public Filter readURL(InputStream is, ParsedURL purl, |
| ICCColorSpaceWithIntent colorSpace, |
| boolean allowOpenStream, |
| boolean returnBrokenLink) { |
| if ((is != null) && !is.markSupported()) |
| // Doesn't support mark so wrap with |
| // BufferedInputStream that does. |
| is = new BufferedInputStream(is); |
| |
| // I just realized that this whole thing could |
| boolean needRawData = (colorSpace != null); |
| |
| Filter ret = null; |
| URLImageCache cache = null; |
| |
| if (purl != null) { |
| if (needRawData) cache = rawCache; |
| else cache = imgCache; |
| |
| ret = cache.request(purl); |
| if (ret != null) { |
| // System.out.println("Image came from cache" + purl); |
| if (colorSpace != null) |
| ret = new ProfileRable(ret, colorSpace); |
| return ret; |
| } |
| } |
| // System.out.println("Image didn't come from cache: " + purl); |
| |
| boolean openFailed = false; |
| List mimeTypes = getRegisteredMimeTypes(); |
| |
| Iterator i; |
| i = entries.iterator(); |
| while (i.hasNext()) { |
| RegistryEntry re = (RegistryEntry)i.next(); |
| if (re instanceof URLRegistryEntry) { |
| if ((purl == null) || !allowOpenStream) continue; |
| |
| URLRegistryEntry ure = (URLRegistryEntry)re; |
| if (ure.isCompatibleURL(purl)) { |
| ret = ure.handleURL(purl, needRawData); |
| |
| // Check if we got an image. |
| if (ret != null) break; |
| } |
| continue; |
| } |
| |
| if (re instanceof StreamRegistryEntry) { |
| StreamRegistryEntry sre = (StreamRegistryEntry)re; |
| // Quick out last time the open didn't work for this |
| // URL so don't try again... |
| if (openFailed) continue; |
| |
| try { |
| if (is == null) { |
| // Haven't opened the stream yet let's try. |
| if ((purl == null) || !allowOpenStream) |
| break; // No purl nothing we can do... |
| try { |
| is = purl.openStream(mimeTypes.iterator()); |
| } catch(IOException ioe) { |
| // Couldn't open the stream, go to next entry. |
| openFailed = true; |
| continue; |
| } |
| |
| if (!is.markSupported()) |
| // Doesn't support mark so wrap with |
| // BufferedInputStream that does. |
| is = new BufferedInputStream(is); |
| } |
| |
| if (sre.isCompatibleStream(is)) { |
| ret = sre.handleStream(is, purl, needRawData); |
| if (ret != null) break; |
| } |
| } catch (StreamCorruptedException sce) { |
| // Stream is messed up so setup to reopen it.. |
| is = null; |
| } |
| continue; |
| } |
| } |
| |
| if (cache != null) |
| cache.put(purl, ret); |
| |
| if (ret == null) { |
| if (!returnBrokenLink) |
| return null; |
| if (openFailed) |
| // Technially it's possible that it's an unknown |
| // 'protocol that caused the open to fail but probably |
| // it's a bad URL... |
| return getBrokenLinkImage(this, ERR_URL_UNREACHABLE, null); |
| |
| // We were able to get to the data we just couldn't |
| // make sense of it... |
| return getBrokenLinkImage(this, ERR_URL_UNINTERPRETABLE, null); |
| } |
| |
| if (BrokenLinkProvider.hasBrokenLinkProperty(ret)) { |
| // Don't Return Broken link image unless requested |
| return (returnBrokenLink)?ret:null; |
| } |
| |
| if (colorSpace != null) |
| ret = new ProfileRable(ret, colorSpace); |
| |
| return ret; |
| } |
| |
| public Filter readStream(InputStream is) { |
| return readStream(is, null); |
| } |
| |
| public Filter readStream(InputStream is, ICCColorSpaceWithIntent colorSpace) { |
| if (!is.markSupported()) |
| // Doesn't support mark so wrap with BufferedInputStream that does. |
| is = new BufferedInputStream(is); |
| |
| boolean needRawData = (colorSpace != null); |
| |
| Filter ret = null; |
| |
| for (Object entry : entries) { |
| RegistryEntry re = (RegistryEntry) entry; |
| |
| if (!(re instanceof StreamRegistryEntry)) |
| continue; |
| StreamRegistryEntry sre = (StreamRegistryEntry) re; |
| |
| try { |
| if (sre.isCompatibleStream(is)) { |
| ret = sre.handleStream(is, null, needRawData); |
| |
| if (ret != null) break; |
| } |
| } catch (StreamCorruptedException sce) { |
| break; |
| } |
| } |
| |
| if (ret == null) |
| return getBrokenLinkImage(this, ERR_STREAM_UNREADABLE, null); |
| |
| if ((colorSpace != null) && |
| (!BrokenLinkProvider.hasBrokenLinkProperty(ret))) |
| ret = new ProfileRable(ret, colorSpace); |
| |
| return ret; |
| } |
| |
| public synchronized void register(RegistryEntry newRE) { |
| float priority = newRE.getPriority(); |
| |
| ListIterator li; |
| li = entries.listIterator(); |
| while (li.hasNext()) { |
| RegistryEntry re = (RegistryEntry)li.next(); |
| if (re.getPriority() > priority) { |
| li.previous(); |
| li.add(newRE); |
| return; |
| } |
| } |
| li.add(newRE); |
| extensions = null; |
| mimeTypes = null; |
| } |
| |
| /** |
| * Returns a List that contains String of all the extensions that |
| * can be handleded by the various registered image format |
| * handlers. |
| */ |
| public synchronized List getRegisteredExtensions() { |
| if (extensions != null) |
| return extensions; |
| |
| extensions = new LinkedList(); |
| for (Object entry : entries) { |
| RegistryEntry re = (RegistryEntry) entry; |
| extensions.addAll(re.getStandardExtensions()); |
| } |
| extensions = Collections.unmodifiableList(extensions); |
| return extensions; |
| } |
| |
| /** |
| * Returns a List that contains String of all the mime types that |
| * can be handleded by the various registered image format |
| * handlers. |
| */ |
| public synchronized List getRegisteredMimeTypes() { |
| if (mimeTypes != null) |
| return mimeTypes; |
| |
| mimeTypes = new LinkedList(); |
| for (Object entry : entries) { |
| RegistryEntry re = (RegistryEntry) entry; |
| mimeTypes.addAll(re.getMimeTypes()); |
| } |
| mimeTypes = Collections.unmodifiableList(mimeTypes); |
| return mimeTypes; |
| } |
| |
| static ImageTagRegistry registry = null; |
| |
| public static synchronized ImageTagRegistry getRegistry() { |
| if (registry != null) |
| return registry; |
| |
| registry = new ImageTagRegistry(); |
| |
| //registry.register(new PNGRegistryEntry()); |
| //registry.register(new TIFFRegistryEntry()); |
| //registry.register(new JPEGRegistryEntry()); |
| registry.register(new JDKRegistryEntry()); |
| |
| Iterator iter = Service.providers(RegistryEntry.class); |
| while (iter.hasNext()) { |
| RegistryEntry re = (RegistryEntry)iter.next(); |
| // System.out.println("RE: " + re); |
| registry.register(re); |
| } |
| |
| return registry; |
| } |
| |
| static BrokenLinkProvider defaultProvider |
| = new DefaultBrokenLinkProvider(); |
| |
| static BrokenLinkProvider brokenLinkProvider = null; |
| |
| public static synchronized Filter |
| getBrokenLinkImage(Object base, String code, Object [] params) { |
| Filter ret = null; |
| if (brokenLinkProvider != null) |
| ret = brokenLinkProvider.getBrokenLinkImage(base, code, params); |
| |
| if (ret == null) |
| ret = defaultProvider.getBrokenLinkImage(base, code, params); |
| |
| return ret; |
| } |
| |
| |
| public static synchronized void |
| setBrokenLinkProvider(BrokenLinkProvider provider) { |
| brokenLinkProvider = provider; |
| } |
| } |
| |