1package com.nwalsh.xalan;
2
3import java.io.*;
4import java.awt.*;
5import java.awt.image.*;
6import java.lang.Thread;
7import java.util.StringTokenizer;
8
9import org.apache.xalan.extensions.ExpressionContext;
10
11/**
12 * <p>Xalan extension to examine intrinsic size of images</p>
13 *
14 * <p>$Id: ImageIntrinsics.java,v 1.1 2006/05/04 13:23:51 nwalsh Exp $</p>
15 *
16 * <p>Copyright (C) 2002 Norman Walsh.</p>
17 *
18 * <p>This class provides a
19 * <a href="http://xml.apache.org/xalan-j/">Xalan</a>
20 * extension to find the intrinsic size of images.</p>
21 *
22 * <p><b>Change Log:</b></p>
23 * <dl>
24 * <dt>1.0</dt>
25 * <dd><p>Initial release.</p></dd>
26 * </dl>
27 *
28 * @author Norman Walsh
29 * <a href="mailto:ndw@nwalsh.com">ndw@nwalsh.com</a>
30 *
31 * @version $Id: ImageIntrinsics.java,v 1.1 2006/05/04 13:23:51 nwalsh Exp $
32 *
33 */
34public class ImageIntrinsics implements ImageObserver {
35  boolean imageLoaded = false;
36  boolean imageFailed = false;
37  Image image = null;
38  int width = -1;
39  int depth = -1;
40
41  /**
42   * <p>Constructor for ImageIntrinsics</p>
43   */
44  public ImageIntrinsics(ExpressionContext context, String imageFn) {
45    System.setProperty("java.awt.headless","true");
46    image = Toolkit.getDefaultToolkit().getImage (imageFn);
47    width = image.getWidth(this);
48
49    while (!imageFailed && (width == -1 || depth == -1)) {
50      try {
51	java.lang.Thread.currentThread().sleep(50);
52      } catch (Exception e) {
53	// nop;
54      }
55      width = image.getWidth(this);
56      depth = image.getHeight(this);
57    }
58
59    if (imageFailed) {
60      // Maybe it's an EPS or PDF?
61      // FIXME: this code is crude
62      BufferedReader ir = null;
63      String line = null;
64      int lineLimit = 100;
65
66      try {
67	ir = new BufferedReader(new FileReader(new File(imageFn)));
68	line = ir.readLine();
69
70	if (line != null && line.startsWith("%PDF-")) {
71	  // We've got a PDF!
72	  while (lineLimit > 0 && line != null) {
73	    lineLimit--;
74	    if (line.startsWith("/CropBox [")) {
75	      line = line.substring(10);
76	      if (line.indexOf("]") >= 0) {
77		line = line.substring(0, line.indexOf("]"));
78	      }
79	      parseBox(line);
80	      lineLimit = 0;
81	    }
82	    line = ir.readLine();
83	  }
84	} else if (line != null && line.startsWith("%!") && line.indexOf(" EPSF-") > 0) {
85	  // We've got an EPS!
86	  while (lineLimit > 0 && line != null) {
87	    lineLimit--;
88	    if (line.startsWith("%%BoundingBox: ")) {
89	      line = line.substring(15);
90	      parseBox(line);
91	      lineLimit = 0;
92	    }
93	    line = ir.readLine();
94	  }
95	}
96      } catch (Exception e) {
97	// nop;
98      }
99
100      if (ir != null) {
101	try {
102	  ir.close();
103	} catch (Exception e) {
104	  // nop;
105	}
106      }
107    }
108  }
109
110  public int getWidth(ExpressionContext context, int defaultWidth) {
111    if (width >= 0) {
112      return width;
113    } else {
114      return defaultWidth;
115    }
116  }
117
118  public int getDepth(ExpressionContext context, int defaultDepth) {
119    if (depth >= 0) {
120      return depth;
121    } else {
122      return defaultDepth;
123    }
124  }
125
126  private void parseBox(String line) {
127    int [] corners = new int [4];
128    int count = 0;
129
130    StringTokenizer st = new StringTokenizer(line);
131    while (count < 4 && st.hasMoreTokens()) {
132      try {
133	corners[count++] = Integer.parseInt(st.nextToken());
134      } catch (Exception e) {
135	// nop;
136      }
137    }
138
139    width = corners[2] - corners[0];
140    depth = corners[3] - corners[1];
141  }
142
143  public boolean imageUpdate(Image img, int infoflags,
144			     int x, int y, int width, int height) {
145    if ((infoflags & ImageObserver.ERROR) == ImageObserver.ERROR) {
146      imageFailed = true;
147      return false;
148    }
149
150    // I really only care about the width and height, but if I return false as
151    // soon as those are available, the BufferedInputStream behind the loader
152    // gets closed too early.
153    int flags = ImageObserver.ALLBITS;
154    if ((infoflags & flags) == flags) {
155      return false;
156    } else {
157      return true;
158    }
159  }
160}
161