diff options
author | Jeremias Maerki <jeremias@apache.org> | 2005-08-15 10:34:31 +0000 |
---|---|---|
committer | Jeremias Maerki <jeremias@apache.org> | 2005-08-15 10:34:31 +0000 |
commit | a349b7be0b545f1e17dda314d6622d2f60458821 (patch) | |
tree | fb57b8092d8fdbb05a56f854e3cdca34247e531c /src/java/org/apache/fop | |
parent | d432b9cdfb206b1dbaeb51167c40a141af71c4ae (diff) | |
download | xmlgraphics-fop-a349b7be0b545f1e17dda314d6622d2f60458821.tar.gz xmlgraphics-fop-a349b7be0b545f1e17dda314d6622d2f60458821.zip |
Bugzilla #36082
1. Addresses the URI resolving issue as discussed in this bug by providing a
FOP implementation of the URIResolver interface as well as the capabilities to
set a URIResolver on the FOUserAgent object.
2. Modifies the BMPReader to extract the resolution information.
3. Fixes a possible array bounds exception in BMPImage which can happen for BMP
images with extra bytes at the end.
4. Provides some infrastructure in ImageFactory in preparation of external
configuration of multiple prioritised image providers per mime type.
5. Sets a proper base URL in SVGElement.
6. Provides test cases and test images for the different formats and
resolutions.
Submitted by: Manuel Mall <mm.at.arcus.com.au>
Patch slightly modified:
- EPS sample graphic exchanged with a very simple and more importantly much smaller one generated by Barcode4J.
- Enabled resolution checking for some of the format-specific testcases (especially after working around resolution detection for PNG)
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@232786 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/java/org/apache/fop')
-rw-r--r-- | src/java/org/apache/fop/apps/FOURIResolver.java | 135 | ||||
-rw-r--r-- | src/java/org/apache/fop/apps/FOUserAgent.java | 58 | ||||
-rw-r--r-- | src/java/org/apache/fop/fo/extensions/svg/SVGElement.java | 10 | ||||
-rw-r--r-- | src/java/org/apache/fop/image/BmpImage.java | 15 | ||||
-rw-r--r-- | src/java/org/apache/fop/image/ImageFactory.java | 333 | ||||
-rw-r--r-- | src/java/org/apache/fop/image/ImageLoader.java | 4 | ||||
-rw-r--r-- | src/java/org/apache/fop/image/analyser/BMPReader.java | 48 |
7 files changed, 458 insertions, 145 deletions
diff --git a/src/java/org/apache/fop/apps/FOURIResolver.java b/src/java/org/apache/fop/apps/FOURIResolver.java new file mode 100644 index 000000000..57a473752 --- /dev/null +++ b/src/java/org/apache/fop/apps/FOURIResolver.java @@ -0,0 +1,135 @@ +/* + * Copyright 2005 The Apache Software Foundation. + * + * Licensed 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.apps; + +import java.net.MalformedURLException; +import java.net.URL; +import javax.xml.transform.Source; +import javax.xml.transform.stream.StreamSource; + +// commons logging +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Provides FOP specific URI resolution. + * This is the default URIResolver {@link FOUserAgent} will use unless overidden. + * @see javax.xml.transform.URIResolver + */ +public class FOURIResolver + implements javax.xml.transform.URIResolver +{ + private Log log = LogFactory.getLog("FOP"); + + /** + * Called by the processor through {@link FOUserAgent} when it encounters an uri in an external-graphic element. + * (see also {@link javax.xml.transform.URIResolver#resolve(String, String)} + * This resolver will allow URLs without a scheme, i.e. it assumes 'file:' as the default + * scheme. It also allows relative URLs with scheme, e.g. file:../../abc.jpg which is + * not strictly RFC compliant as long as the scheme is the same as the scheme of the + * base URL. If the base URL is null a 'file:' URL referencing the current directory is used as + * the base URL. + * If the method is successful it will return a Source of type + * {@link javax.xml.transform.stream.StreamSource} with its SystemID set to the resolved + * URL used to open the underlying InputStream. + * + * @param href An href attribute, which may be relative or absolute. + * @param base The base URI against which the first argument will be made absolute if the absolute URI is required. + * @return A {@link javax.xml.transform.Source} object, or null if the href cannot be resolved. + * @throws TransformerException Never thrown by this implementation. + * @see javax.xml.transform.URIResolver#resolve(String, String) + */ + public Source resolve(String href, String base) + throws javax.xml.transform.TransformerException + { + URL absoluteURL = null; + URL baseURL = toBaseURL(base); + if (baseURL == null) { + // We don't have a valid baseURL just use the URL as given + try { + absoluteURL = new URL(href); + } catch (MalformedURLException mue) { + try { + // the above failed, we give it another go in case + // the href contains only a path then file: is assumed + absoluteURL = new URL("file:" + href); + } catch (MalformedURLException mfue) { + log.error("Error with URL '" + href + "': " + mue.getMessage(), mue); + return null; + } + } + } else { + try { + /* + This piece of code is based on the following statement in RFC2396 section 5.2: + + 3) If the scheme component is defined, indicating that the reference + starts with a scheme name, then the reference is interpreted as an + absolute URI and we are done. Otherwise, the reference URI's + scheme is inherited from the base URI's scheme component. + + Due to a loophole in prior specifications [RFC1630], some parsers + allow the scheme name to be present in a relative URI if it is the + same as the base URI scheme. Unfortunately, this can conflict + with the correct parsing of non-hierarchical URI. For backwards + compatibility, an implementation may work around such references + by removing the scheme if it matches that of the base URI and the + scheme is known to always use the <hier_part> syntax. + + The URL class does not implement this work around, so we do. + */ + + String scheme = baseURL.getProtocol() + ":"; + if (href.startsWith(scheme)) { + href = href.substring(scheme.length()); + } + absoluteURL = new URL(baseURL, href); + } catch (MalformedURLException mfue) { + log.error("Error with URL '" + href + "': " + mfue.getMessage(), mfue); + return null; + } + } + try { + return new StreamSource(absoluteURL.openStream(), absoluteURL.toExternalForm()); + } catch (java.io.IOException ioe) { + log.error("Error with opening URL '" + href + "': " + ioe.getMessage(), ioe); + } + return null; + } + + /** + * Returns the base URL as a java.net.URL. + * If the base URL is not set a default URL pointing to the + * current directory is returned. + * @param baseURL the base URL + * @returns the base URL as java.net.URL + */ + private URL toBaseURL(String baseURL) + { + try { + return new URL(baseURL == null + ? new java.io.File("").toURL().toExternalForm() + : baseURL); + } catch (MalformedURLException mfue) { + log.error("Error with base URL: " + mfue.getMessage(), mfue); + } + return null; + } + +} diff --git a/src/java/org/apache/fop/apps/FOUserAgent.java b/src/java/org/apache/fop/apps/FOUserAgent.java index a308e6a86..708c39a92 100644 --- a/src/java/org/apache/fop/apps/FOUserAgent.java +++ b/src/java/org/apache/fop/apps/FOUserAgent.java @@ -21,10 +21,13 @@ package org.apache.fop.apps; // Java import java.io.File; import java.io.IOException; -import java.io.InputStream; import java.util.Date; import java.util.List; import java.util.Map; +import javax.xml.transform.Source; +import javax.xml.transform.TransformerException; +import javax.xml.transform.URIResolver; +import javax.xml.transform.stream.StreamSource; // avalon configuration import org.apache.avalon.framework.configuration.Configuration; @@ -71,6 +74,12 @@ public class FOUserAgent { private XMLHandlerRegistry xmlHandlers = new XMLHandlerRegistry(); private String baseURL; + + /** A user settable URI Resolver */ + private URIResolver uriResolver = null; + /** Our default resolver if none is set */ + private URIResolver foURIResolver = new FOURIResolver(); + private PDFEncryptionParams pdfEncryptionParams; private float px2mm = DEFAULT_PX2MM; private Map rendererOptions = new java.util.HashMap(); @@ -384,11 +393,23 @@ public class FOUserAgent { * @return the base URL */ public String getBaseURL() { - if ((this.baseURL == null) || (this.baseURL.trim().equals(""))) { - return "file:."; - } else { - return this.baseURL; - } + return this.baseURL; + } + + /** + * Sets the URI Resolver. + * @param uriResolver the new URI resolver + */ + public void setURIResolver(URIResolver uriResolver) { + this.uriResolver = uriResolver; + } + + /** + * Returns the URI Resolver. + * @return the URI Resolver + */ + public URIResolver getURIResolver() { + return this.uriResolver != null ? this.uriResolver : this.foURIResolver; } /** @@ -410,15 +431,28 @@ public class FOUserAgent { /** - * Get an input stream for a reference. Subclass FOUserAgent and override this method to - * do custom URI to InputStream resolution. + * Get a stream source for a reference. Subclass FOUserAgent and override this method to + * do custom URI to {@link javax.xml.transform.stream.StreamSource} resolution. + * Alternatively set your own {@link javax.xml.transform.URIResolver} on the FOUserAgent. * Temporary solution until the API is better. * @param uri URI to access - * @return InputStream for accessing the resource. + * @return StreamSource for accessing the resource. * @throws IOException in case of an I/O problem */ - public InputStream getStream(String uri) throws IOException { - //The default implementation does noting. Subclass FOUserAgent to add custom behaviour. + public StreamSource getStream(String uri) throws IOException { + Source source = null; + try { + source = getURIResolver().resolve(uri, getBaseURL()); + } catch (TransformerException te) { + log.error("Attempt to resolve URI '" + uri + "' failed: ", te); + } + if (source != null) { + if (source instanceof StreamSource) { + return (StreamSource)source; + } else { + log.error("Attempt to resolve URI returned unknown source"); + } + } return null; } @@ -434,7 +468,7 @@ public class FOUserAgent { * Gets the output File. * @return the output File */ - public File getOutputFile(){ + public File getOutputFile() { return outputFile; } diff --git a/src/java/org/apache/fop/fo/extensions/svg/SVGElement.java b/src/java/org/apache/fop/fo/extensions/svg/SVGElement.java index 7dfd3dd22..19fc06a3a 100644 --- a/src/java/org/apache/fop/fo/extensions/svg/SVGElement.java +++ b/src/java/org/apache/fop/fo/extensions/svg/SVGElement.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2004 The Apache Software Foundation. + * Copyright 1999-2005 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -80,9 +80,11 @@ public class SVGElement extends SVGObj { /* if width and height are zero, get the bounds of the content. */ try { - String baseDir = getUserAgent().getBaseURL(); - if (baseDir != null) { - ((SVGOMDocument)doc).setURLObject(new URL(baseDir)); + URL baseURL = new URL(getUserAgent().getBaseURL() == null + ? new java.io.File("").toURL().toExternalForm() + : getUserAgent().getBaseURL()); + if (baseURL != null) { + ((SVGOMDocument)doc).setURLObject(baseURL); } } catch (Exception e) { getLogger().error("Could not set base URL for svg", e); diff --git a/src/java/org/apache/fop/image/BmpImage.java b/src/java/org/apache/fop/image/BmpImage.java index ea9d0cf14..02346b7e6 100644 --- a/src/java/org/apache/fop/image/BmpImage.java +++ b/src/java/org/apache/fop/image/BmpImage.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2004 The Apache Software Foundation. + * Copyright 1999-2005 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -44,7 +44,6 @@ public class BmpImage extends AbstractFopImage { * Load the bitmap. * This laods the bitmap data from the bitmap image. * - * @param ua the user agent * @return true if it was loaded successfully */ protected boolean loadBitmap() { @@ -52,7 +51,7 @@ public class BmpImage extends AbstractFopImage { int hpos = 22; // offset positioning for w and height in bmp files int[] headermap = new int[54]; int filepos = 0; - byte palette[] = null; + byte[] palette = null; try { boolean eof = false; while ((!eof) && (filepos < 54)) { @@ -75,8 +74,7 @@ public class BmpImage extends AbstractFopImage { if (input == -1) { eof = true; } else if (count2 >= 0) { - palette[countr * 3 + count2] = - (byte)(input & 0xFF); + palette[countr * 3 + count2] = (byte)(input & 0xFF); } count2--; filepos++; @@ -135,7 +133,12 @@ public class BmpImage extends AbstractFopImage { int count = 0; inputStream.skip((long)(imagestart - filepos)); while ((input = inputStream.read()) != -1) { - temp[count++] = input; + if (count >= temp.length) { + log.warn("Data longer than expected while loading image"); + break; + } else { + temp[count++] = input; + } } inputStream.close(); inputStream = null; diff --git a/src/java/org/apache/fop/image/ImageFactory.java b/src/java/org/apache/fop/image/ImageFactory.java index ce287026d..202c224b1 100644 --- a/src/java/org/apache/fop/image/ImageFactory.java +++ b/src/java/org/apache/fop/image/ImageFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2004 The Apache Software Foundation. + * Copyright 1999-2005 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,13 +21,15 @@ package org.apache.fop.image; // Java import java.io.IOException; import java.io.InputStream; -import java.net.URL; -import java.net.MalformedURLException; import java.lang.reflect.Constructor; +import java.util.ArrayList; import java.util.Map; import java.util.Set; import java.util.Collections; +import java.util.HashMap; import java.util.Iterator; +import java.util.List; +import javax.xml.transform.stream.StreamSource; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -41,18 +43,76 @@ import org.apache.fop.apps.FOUserAgent; * Create FopImage objects (with a configuration file - not yet implemented). * @author Eric SCHAEFFER */ -public class ImageFactory { +public final class ImageFactory { /** * logging instance */ protected static Log log = LogFactory.getLog(FopImage.class); - + private static ImageFactory factory = new ImageFactory(); + private HashMap imageMimeTypes = new HashMap(); + private ImageCache cache = new ContextImageCache(true); private ImageFactory() { + /* @todo The mappings set up below of image mime types to implementing + * classes should be made externally configurable + */ + ImageProvider jaiImage = new ImageProvider("JAIImage", "org.apache.fop.image.JAIImage"); + ImageProvider jimiImage = new ImageProvider("JIMIImage", "org.apache.fop.image.JimiImage"); + ImageProvider imageIoImage = new ImageProvider( + "ImageIOImage", "org.apache.fop.image.ImageIoImage"); + ImageProvider gifImage = new ImageProvider("GIFImage", "org.apache.fop.image.GifImage"); + ImageProvider jpegImage = new ImageProvider("JPEGImage", "org.apache.fop.image.JpegImage"); + ImageProvider bmpImage = new ImageProvider("BMPImage", "org.apache.fop.image.BmpImage"); + ImageProvider epsImage = new ImageProvider("EPSImage", "org.apache.fop.image.EPSImage"); + ImageProvider pngImage = new ImageProvider("PNGImage", "org.apache.fop.image.PNGImage"); + ImageProvider tiffImage = new ImageProvider("TIFFImage", "org.apache.fop.image.TIFFImage"); + ImageProvider xmlImage = new ImageProvider("XMLImage", "org.apache.fop.image.XMLImage"); + + ImageMimeType imt = new ImageMimeType("image/gif"); + imageMimeTypes.put(imt.getMimeType(), imt); + imt.addProvider(jaiImage); + imt.addProvider(imageIoImage); + imt.addProvider(jimiImage); + imt.addProvider(gifImage); + + imt = new ImageMimeType("image/jpeg"); + imageMimeTypes.put(imt.getMimeType(), imt); + imt.addProvider(jpegImage); + + imt = new ImageMimeType("image/bmp"); + imageMimeTypes.put(imt.getMimeType(), imt); + imt.addProvider(bmpImage); + + imt = new ImageMimeType("image/eps"); + imageMimeTypes.put(imt.getMimeType(), imt); + imt.addProvider(epsImage); + + imt = new ImageMimeType("image/png"); + imageMimeTypes.put(imt.getMimeType(), imt); + imt.addProvider(pngImage); + + imt = new ImageMimeType("image/tga"); + imageMimeTypes.put(imt.getMimeType(), imt); + imt.addProvider(jaiImage); + imt.addProvider(imageIoImage); + imt.addProvider(jimiImage); + + imt = new ImageMimeType("image/tiff"); + imageMimeTypes.put(imt.getMimeType(), imt); + imt.addProvider(tiffImage); + + imt = new ImageMimeType("image/svg+xml"); + imageMimeTypes.put(imt.getMimeType(), imt); + imt.addProvider(xmlImage); + + imt = new ImageMimeType("text/xml"); + imageMimeTypes.put(imt.getMimeType(), imt); + imt.addProvider(xmlImage); + } /** @@ -134,19 +194,23 @@ public class ImageFactory { * @param ua the user agent context * @return the fop image instance */ - public static FopImage loadImage(String href, FOUserAgent ua) { + public FopImage loadImage(String href, FOUserAgent ua) { - InputStream in = openStream(href, ua); - - if (in == null) { + StreamSource source = openStream(href, ua); + if (source == null) { return null; } - // If not, check image type + InputStream in = source.getInputStream(); + //Make sure the InputStream is decorated with a BufferedInputStream + if (!(in instanceof java.io.BufferedInputStream)) { + in = new java.io.BufferedInputStream(in); + } + + // Check image type FopImage.ImageInfo imgInfo = null; try { - imgInfo = ImageReaderFactory.make( - href, in, ua); + imgInfo = ImageReaderFactory.make(source.getSystemId(), in, ua); } catch (Exception e) { log.error("Error while recovering image information (" + href + ") : " + e.getMessage(), e); @@ -165,8 +229,8 @@ public class ImageFactory { } // Associate mime-type to FopImage class String imgMimeType = imgInfo.mimeType; - String imgClassName = getImageClassName(imgMimeType); - if (imgClassName == null) { + Class imageClass = getImageClass(imgMimeType); + if (imageClass == null) { log.error("Unsupported image type (" + href + "): " + imgMimeType); return null; @@ -175,20 +239,14 @@ public class ImageFactory { // load the right image class // return new <FopImage implementing class> Object imageInstance = null; - Class imageClass = null; try { - imageClass = Class.forName(imgClassName); Class[] imageConstructorParameters = new Class[1]; imageConstructorParameters[0] = org.apache.fop.image.FopImage.ImageInfo.class; - Constructor imageConstructor = - imageClass.getDeclaredConstructor( - imageConstructorParameters); + Constructor imageConstructor = imageClass.getDeclaredConstructor( + imageConstructorParameters); Object[] initArgs = new Object[1]; initArgs[0] = imgInfo; imageInstance = imageConstructor.newInstance(initArgs); - } catch (ClassNotFoundException cnfe) { - log.error("Class " + imgClassName + " not found. Check that Jimi/JAI is in classpath"); - return null; } catch (java.lang.reflect.InvocationTargetException ex) { Throwable t = ex.getTargetException(); String msg; @@ -202,7 +260,7 @@ public class ImageFactory { return null; } catch (InstantiationException ie) { log.error("Error creating FopImage object (" - + href + "): Could not instantiate " + imgClassName + " instance"); + + href + "): Could not instantiate " + imageClass.getName() + " instance"); return null; } catch (Exception ex) { log.error("Error creating FopImage object (" @@ -220,16 +278,14 @@ public class ImageFactory { } /** - * Create an FopImage objects. + * Create a StreamSource objects. * @param href image URL as a String * @param ua user agent - * @return a new FopImage object + * @return a new StreamSource object */ - protected static InputStream openStream(String href, FOUserAgent ua) { + protected StreamSource openStream(String href, FOUserAgent ua) { - // Get the absolute URL - URL absoluteURL = null; - InputStream in = null; + StreamSource in = null; try { in = ua.getStream(href); @@ -238,90 +294,15 @@ public class ImageFactory { + href + "): " + ioe.getMessage(), ioe); return null; } - if (in == null) { - try { - // try url as complete first, this can cause - // a problem with relative uri's if there is an - // image relative to where fop is run and relative - // to the base dir of the document - try { - absoluteURL = new URL(href); - } catch (MalformedURLException mue) { - // if the href contains only a path then file is assumed - absoluteURL = new URL("file:" + href); - } - in = absoluteURL.openStream(); - } catch (MalformedURLException mfue) { - log.error("Error with image URL: " + mfue.getMessage(), mfue); - return null; - } catch (Exception e) { - // maybe relative - if (ua.getBaseURL() == null) { - log.error("Error with image URL: " + e.getMessage() - + " and no base URL is specified", e); - return null; - } - try { - absoluteURL = new URL(ua.getBaseURL() + absoluteURL.getFile()); - } catch (MalformedURLException e_context) { - // pb context url - log.error("Invalid Image URL - error on relative URL: " - + e_context.getMessage(), e_context); - return null; - } - } - } /* if (in == null) */ - - try { - if (in == null && absoluteURL != null) { - in = absoluteURL.openStream(); - } - if (in == null) { - log.error("Could not resolve URI for image: " + href); - return null; - } + return in; + } - //Make sure the InputStream is decorated with a BufferedInputStream - if (in instanceof java.io.BufferedInputStream) { - return in; - } else { - return new java.io.BufferedInputStream(in); - } - } catch (Exception e) { - log.error("Error while opening stream for (" - + href + "): " + e.getMessage(), e); + private Class getImageClass(String imgMimeType) { + ImageMimeType imt = (ImageMimeType)imageMimeTypes.get(imgMimeType); + if (imt == null) { return null; } - } - - private static String getImageClassName(String imgMimeType) { - String imgClassName = null; - if ("image/gif".equals(imgMimeType)) { - imgClassName = "org.apache.fop.image.GifImage"; - // imgClassName = "org.apache.fop.image.JAIImage"; - } else if ("image/jpeg".equals(imgMimeType)) { - imgClassName = "org.apache.fop.image.JpegImage"; - // imgClassName = "org.apache.fop.image.JAIImage"; - } else if ("image/bmp".equals(imgMimeType)) { - imgClassName = "org.apache.fop.image.BmpImage"; - // imgClassName = "org.apache.fop.image.JAIImage"; - } else if ("image/eps".equals(imgMimeType)) { - imgClassName = "org.apache.fop.image.EPSImage"; - } else if ("image/png".equals(imgMimeType)) { - imgClassName = "org.apache.fop.image.PNGImage"; - // imgClassName = "org.apache.fop.image.JAIImage"; - } else if ("image/tga".equals(imgMimeType)) { - imgClassName = "org.apache.fop.image.JimiImage"; - // imgClassName = "org.apache.fop.image.JAIImage"; - } else if ("image/tiff".equals(imgMimeType)) { - imgClassName = "org.apache.fop.image.TIFFImage"; - // imgClassName = "org.apache.fop.image.JAIImage"; - } else if ("image/svg+xml".equals(imgMimeType)) { - imgClassName = "org.apache.fop.image.XMLImage"; - } else if ("text/xml".equals(imgMimeType)) { - imgClassName = "org.apache.fop.image.XMLImage"; - } - return imgClassName; + return imt.getFirstImplementingClass(); } } @@ -332,7 +313,7 @@ public class ImageFactory { class BasicImageCache implements ImageCache { private Set invalid = Collections.synchronizedSet(new java.util.HashSet()); - private Map contextStore = Collections.synchronizedMap(new java.util.HashMap()); + //private Map contextStore = Collections.synchronizedMap(new java.util.HashMap()); public FopImage getImage(String url, FOUserAgent context) { if (invalid.contains(url)) { @@ -523,3 +504,133 @@ class ContextImageCache implements ImageCache { } +/** + * Encapsulates a class of type FopImage by holding its class name. + * This allows dynamic loading of the class at runtime. + */ +class ImageProvider { + + private String name = null; + + private String className = null; + + private boolean checked = false; + + private Class clazz = null; + + /** + * Creates an ImageProvider with a given name and implementing class. + * The class name should refer to a class of type {@link FopImage}. + * However, this is not checked on construction. + * @param name The name of the provider + * @param className The full class name of the class implementing this provider + */ + public ImageProvider(String name, String className) { + setName(name); + setClassName(className); + } + + /** + * Returns the provider name. + * @return The provider name + */ + public String getName() { + return name; + } + + private void setName(String name) { + this.name = name; + } + + /** + * Returns the implementing class name. + * @return The implementing class name + */ + public String getClassName() { + return className; + } + + private void setClassName(String className) { + this.className = className; + } + + /** + * Returns the implementing class as a {@link Class} object. + * @return The implementing class or null if it couldn't be loaded. + */ + public Class getImplementingClass() { + if (!checked) { + try { + clazz = Class.forName(getClassName()); + } catch (ClassNotFoundException cnfe) { + //nop + } + checked = true; + } + return clazz; + } +} + +/** + * Holds a mime type for a particular image format plus a list of + * {@link ImageProvider} objects which support the particular image format. + */ +class ImageMimeType { + + private String mimeType = null; + + private List providers = null; + + /** + * Constructor for a particular mime type. + * @param mimeType The mime type + */ + public ImageMimeType(String mimeType) { + setMimeType(mimeType); + } + + /** + * Returns the mime type. + * @return The mime type + */ + public String getMimeType() { + return mimeType; + } + + private void setMimeType(String mimeType) { + this.mimeType = mimeType; + } + + /** + * Returns the class from the first available provider. + * @return The first available class or null if none can be found + */ + public Class getFirstImplementingClass() { + if (providers == null) { + return null; + } + for (Iterator it = providers.iterator(); it.hasNext();) { + ImageProvider ip = (ImageProvider)it.next(); + Class clazz = ip.getImplementingClass(); + if (clazz != null) { + return clazz; + } + } + return null; + } + + /** + * Adds a new provider. + * The provider is added to the end of the current provider list. + * @param The new provider to add + */ + public void addProvider(ImageProvider provider) { + if (providers == null) { + providers = new ArrayList(4); // Assume we only have a few providers + } + if (!providers.contains(provider)) { + providers.add(provider); + } + } +} + diff --git a/src/java/org/apache/fop/image/ImageLoader.java b/src/java/org/apache/fop/image/ImageLoader.java index 33269c790..ad22c6c2b 100644 --- a/src/java/org/apache/fop/image/ImageLoader.java +++ b/src/java/org/apache/fop/image/ImageLoader.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2004 The Apache Software Foundation. + * Copyright 1999-2005 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -51,7 +51,7 @@ class ImageLoader { if (!valid || image != null) { return image; } - image = ImageFactory.loadImage(url, userAgent); + image = ImageFactory.getInstance().loadImage(url, userAgent); if (image == null) { cache.invalidateImage(url, userAgent); valid = false; diff --git a/src/java/org/apache/fop/image/analyser/BMPReader.java b/src/java/org/apache/fop/image/analyser/BMPReader.java index 4f39e30a9..077d4f229 100644 --- a/src/java/org/apache/fop/image/analyser/BMPReader.java +++ b/src/java/org/apache/fop/image/analyser/BMPReader.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2004 The Apache Software Foundation. + * Copyright 1999-2005 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -35,7 +35,16 @@ import org.apache.fop.apps.FOUserAgent; public class BMPReader implements ImageReader { /** Length of the BMP header */ - protected static final int BMP_SIG_LENGTH = 26; + protected static final int BMP_SIG_LENGTH = 46; + + /** offset to width */ + private static final int WIDTH_OFFSET = 18; + /** offset to height */ + private static final int HEIGHT_OFFSET = 18; + /** offset to horizontal res */ + private static final int HRES_OFFSET = 38; + /** offset to vertical res */ + private static final int VRES_OFFSET = 42; /** @see org.apache.fop.image.analyser.ImageReader */ public FopImage.ImageInfo verifySignature(String uri, InputStream bis, @@ -66,20 +75,39 @@ public class BMPReader implements ImageReader { info.mimeType = getMimeType(); // little endian notation - int byte1 = header[18] & 0xff; - int byte2 = header[19] & 0xff; - int byte3 = header[20] & 0xff; - int byte4 = header[21] & 0xff; + int byte1 = header[WIDTH_OFFSET] & 0xff; + int byte2 = header[WIDTH_OFFSET + 1] & 0xff; + int byte3 = header[WIDTH_OFFSET + 2] & 0xff; + int byte4 = header[WIDTH_OFFSET + 3] & 0xff; long l = (long) ((byte4 << 24) | (byte3 << 16) | (byte2 << 8) | byte1); info.width = (int) (l & 0xffffffff); - byte1 = header[22] & 0xff; - byte2 = header[23] & 0xff; - byte3 = header[24] & 0xff; - byte4 = header[25] & 0xff; + byte1 = header[HEIGHT_OFFSET] & 0xff; + byte2 = header[HEIGHT_OFFSET + 1] & 0xff; + byte3 = header[HEIGHT_OFFSET + 2] & 0xff; + byte4 = header[HEIGHT_OFFSET + 3] & 0xff; l = (long) ((byte4 << 24) | (byte3 << 16) | (byte2 << 8) | byte1); info.height = (int) (l & 0xffffffff); + + byte1 = header[HRES_OFFSET] & 0xff; + byte2 = header[HRES_OFFSET + 1] & 0xff; + byte3 = header[HRES_OFFSET + 2] & 0xff; + byte4 = header[HRES_OFFSET + 3] & 0xff; + l = (long) ((byte4 << 24) | (byte3 << 16) | (byte2 << 8) | byte1); + if (l > 0) { + info.dpiHorizontal = l / 39.37d; + } + + byte1 = header[VRES_OFFSET] & 0xff; + byte2 = header[VRES_OFFSET + 1] & 0xff; + byte3 = header[VRES_OFFSET + 2] & 0xff; + byte4 = header[VRES_OFFSET + 3] & 0xff; + l = (long) ((byte4 << 24) | (byte3 << 16) | (byte2 << 8) | byte1); + if (l > 0) { + info.dpiVertical = l / 39.37d; + } + return info; } |