xmlgraphics-fop-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Jeremias Maerki <...@jeremias-maerki.ch>
Subject Re: Outputting intrinsic dimension info of images
Date Tue, 26 Jul 2011 19:06:31 GMT
No, I don't think there's an easy way to find out how much FOP scales
the image. You could look in one of the immediate formats but that only
gets you the target size but not the original size.

I found some code I wrote some time ago which is a Xalan-J extension
that does basically what you need (except share the image manager with

import java.io.File;
import java.io.IOException;
import java.lang.ref.SoftReference;
import java.net.URI;
import java.net.URISyntaxException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Source;
import javax.xml.transform.TransformerException;
import javax.xml.transform.URIResolver;
import javax.xml.transform.stream.StreamSource;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

import org.apache.xalan.extensions.ExpressionContext;
import org.apache.xml.utils.QName;

import org.apache.xmlgraphics.image.loader.ImageContext;
import org.apache.xmlgraphics.image.loader.ImageException;
import org.apache.xmlgraphics.image.loader.ImageInfo;
import org.apache.xmlgraphics.image.loader.ImageManager;
import org.apache.xmlgraphics.image.loader.ImageSessionContext;
import org.apache.xmlgraphics.image.loader.ImageSize;
import org.apache.xmlgraphics.image.loader.impl.AbstractImageSessionContext;
import org.apache.xmlgraphics.image.loader.impl.DefaultImageContext;

public class ImageExtension {

    private static SoftReference<ImageManager> imageManagerRef = null;

     * Returns a document fragment with information on the given image.
     * @param context the expression context
     * @param uri the image URI
     * @param baseUri the optional base URI for resolving relative URIs
     * @return the image information
     * @throws IOException if an I/O error occurs
     * @throws ParserConfigurationException Problems creating a DocumentBuilder
     * @throws ImageException Failure to load the image
    public static Node imageInfo(final ExpressionContext context, final String uri)
                throws IOException, ParserConfigurationException, ImageException {
        return imageInfo(context, uri, null);

     * Returns a document fragment with information on the given image.
     * @param context the expression context
     * @param uri the image URI
     * @param baseUri the optional base URI for resolving relative URIs
     * @return the image information
     * @throws IOException if an I/O error occurs
     * @throws ParserConfigurationException Problems creating a DocumentBuilder
     * @throws ImageException Failure to load the image
    public static Node imageInfo(final ExpressionContext context, final String uri,
            final String baseUri)
                throws IOException, ParserConfigurationException, ImageException {
        final ImageManager imageManager = getImageManager();
        ImageSessionContext sessionContext = new AbstractImageSessionContext() {

            public float getTargetResolution() {
                return 300; //dpi

            public ImageContext getParentContext() {
                return imageManager.getImageContext();

            protected Source resolveURI(String uri) {
                //TODO Improve resolution with xml:base etc.
                try {
                    String base = baseUri;
                    if (base == null || base.length() == 0) {
                        base = context.getVariableOrParam(new QName("resource-base")).str();
                    URIResolver resolver = context.getXPathContext().getURIResolver();
                    if (resolver != null) {
                        //System.out.println("Resolving: " + uri + ", " + base);
                        return resolver.resolve(uri, base);
                    } else {
                        URI b;
                        try {
                            b = new URI(base);
                        } catch (URISyntaxException use) {
                            File f = new File(base);
                            b = f.toURI();
                        URI fileURI;
                        try {
                            fileURI = new URI(uri);
                        } catch (URISyntaxException use) {
                            File f = new File(uri);
                            fileURI = f.toURI();
                        URI resolved = b.resolve(fileURI);
                        //System.out.println("Basic resolution: uri=" + f + ", base=" + b
+ " --> " + resolved);
                        Source src;
                        if (resolved.getScheme() == null) {
                            src = new StreamSource(new File(resolved.toASCIIString()));
                        } else {
                            src = new StreamSource(resolved.toASCIIString());
                        return src;
                } catch (TransformerException te) {
                    try {
                    } catch (TransformerException e) {
                    return null; //Fail

        ImageInfo info = imageManager.getImageInfo(uri, sessionContext);
        return toNode(info);

    private static Node toNode(ImageInfo info) throws ParserConfigurationException {
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        DocumentBuilder db = dbf.newDocumentBuilder();
        Document doc = db.newDocument();

        Element imageInfo = doc.createElement("image-info");
        imageInfo.setAttribute("uri", info.getOriginalURI());
        imageInfo.setAttribute("format", info.getMimeType());

        Element imageSize = doc.createElement("size");
        ImageSize size = info.getSize();
        imageSize.setAttribute("width-mpt", Integer.toString(size.getWidthMpt()));
        imageSize.setAttribute("height-mpt", Integer.toString(size.getHeightMpt()));
        imageSize.setAttribute("width-px", Integer.toString(size.getWidthPx()));
        imageSize.setAttribute("height-px", Integer.toString(size.getHeightPx()));
        imageSize.setAttribute("resolution-horz", Double.toString(size.getDpiHorizontal()));
        imageSize.setAttribute("resolution-vert", Double.toString(size.getDpiVertical()));
        return imageInfo;

    private static ImageManager getImageManager() {
        ImageManager imageManager = null;
        if (imageManagerRef != null) {
            imageManager = imageManagerRef.get();
        if (imageManager == null) {
            imageManager = new ImageManager(new DefaultImageContext());
            imageManagerRef = new SoftReference<ImageManager>(imageManager);
        return imageManager;

Integration in the stylesheet:

  xmlns:img="<packagename for extension>.ImageExtension"

<t:variable name="image-info" select="img:image-info({@href})"/>

XPath to access the width: $image-info/size/@width-mpt

More info: http://xml.apache.org/xalan-j/extensions.html

On 26.07.2011 20:50:09 Erik Wiklander wrote:
> Ok, thanks for the reply!
> This is the background to my question:
> I'm working on an application where we have an image markup tool that lets the user put
a message somewhere on the image. The message is stored together with the coordinates of where
on the image it is placed.
> Now, when we run the report, I want the message to be displayed on top of the image in
the correct place. I want this to work even if the picture has been scaled down to fit the
> To place the text on the correct place, I have to compare the intrinsic dimensions of
the image with the fixed dimensions of the image in the report, to correctly place the message
on top.
> I currently have a working solution for this, but it is not very good from a performance
perspective: Before running the report I download the image and get the dimensions using Sanselan
and I send these dimensions to the report. If I could profit from the image cache, that would
of course be great. But I'm not really sure how I could write my own extension to do this.
> Another solution to my problem would be if I somehow could find out by how much the image
was scaled. Is that possible to find out? (In a simple way :)
> -----Original Message-----
> From: Jeremias Maerki [mailto:dev@jeremias-maerki.ch] 
> Sent: Tuesday, July 26, 2011 1:09 PM
> To: fop-users@xmlgraphics.apache.org
> Subject: Re: Outputting intrinsic dimension info of images
> Erik,
> you can "preload" the image using the XML Graphics Commons image loading
> framework (which FOP uses, too):
> http://xmlgraphics.apache.org/commons/image-loader.html#preloading
> The ImageInfo object will then contain the intrinsic size. You can use
> the ImageManager from the FopFactory and probably re-use the
> ImageSessionContext from the FOUserAgent:
> ImageManager imageManager = fopFactory.getImageManager();
> ImageSessionContext imageSessionContext = foUserAgent.getImageSessionContext();
> This allows you to profit from the image cache.
> What you do with the values and where exactly you want to write it in
> the PDF is a different question. I don't know what you have in mind here.
> Do you want to print the values on the page along with the image? Sounds
> like an XSLT extension then.
> On 26.07.2011 18:42:15 Erik Wiklander wrote:
> > Hi,
> > 
> > I'm using fo:external-graphic to include images in the pdf. Is there
> > any way that I can find out the intrinsic width and height of an image? So
> > that I can include that information in the resulting pdf.
> > 
> > Thanks
> > //Erik
> > 

Jeremias Maerki

To unsubscribe, e-mail: fop-users-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: fop-users-help@xmlgraphics.apache.org

View raw message