You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

SVGReader.java 8.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. /*
  2. * Copyright 1999-2004 The Apache Software Foundation.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. /* $Id$ */
  17. package org.apache.fop.image.analyser;
  18. // Java
  19. import java.io.InputStream;
  20. import java.io.IOException;
  21. import java.awt.geom.AffineTransform;
  22. // XML
  23. import org.w3c.dom.Element;
  24. import org.w3c.dom.svg.SVGDocument;
  25. // Avalon
  26. import org.apache.avalon.framework.logger.Logger;
  27. // Batik
  28. import org.apache.batik.dom.svg.SAXSVGDocumentFactory;
  29. import org.apache.batik.dom.svg.SVGOMDocument;
  30. import org.apache.batik.bridge.BridgeContext;
  31. import org.apache.batik.bridge.UnitProcessor;
  32. import org.apache.batik.dom.svg.SVGDOMImplementation;
  33. // FOP
  34. import org.apache.fop.image.XMLImage;
  35. import org.apache.fop.image.FopImage;
  36. import org.apache.fop.apps.FOUserAgent;
  37. import org.apache.fop.svg.SVGUserAgent;
  38. /**
  39. * ImageReader object for SVG document image type.
  40. */
  41. public class SVGReader implements ImageReader {
  42. /** SVG's MIME type */
  43. public static final String SVG_MIME_TYPE = "image/svg+xml";
  44. private boolean batik = true;
  45. /** @see org.apache.fop.image.analyser.ImageReader */
  46. public FopImage.ImageInfo verifySignature(String uri, InputStream fis,
  47. FOUserAgent ua) throws IOException {
  48. FopImage.ImageInfo info = loadImage(uri, fis, ua);
  49. if (info != null) {
  50. try {
  51. fis.close();
  52. } catch (Exception e) {
  53. //ignore
  54. }
  55. }
  56. return info;
  57. }
  58. /**
  59. * Returns the MIME type supported by this implementation.
  60. *
  61. * @return The MIME type
  62. */
  63. public String getMimeType() {
  64. return SVG_MIME_TYPE;
  65. }
  66. /**
  67. * This means the external svg document will be loaded twice. Possibly need
  68. * a slightly different design for the image stuff.
  69. *
  70. * @param uri @todo Description of the Parameter
  71. * @param fis @todo Description of the Parameter
  72. * @param ua @todo Description of the Parameter
  73. * @return @todo Description of the Return Value
  74. */
  75. private FopImage.ImageInfo loadImage(String uri, InputStream bis,
  76. FOUserAgent ua) {
  77. if (batik) {
  78. try {
  79. Loader loader = new Loader();
  80. return loader.getImage(uri, bis, ua.getLogger(),
  81. ua.getPixelUnitToMillimeter());
  82. } catch (NoClassDefFoundError e) {
  83. batik = false;
  84. //ua.getLogger().error("Batik not in class path", e);
  85. return null;
  86. }
  87. }
  88. return null;
  89. }
  90. /**
  91. * This method is put in another class so that the classloader does not
  92. * attempt to load batik related classes when constructing the SVGReader
  93. * class.
  94. */
  95. class Loader {
  96. private FopImage.ImageInfo getImage(String uri, InputStream fis,
  97. Logger logger, float pixelUnitToMM) {
  98. // parse document and get the size attributes of the svg element
  99. try {
  100. int length = 5;
  101. fis.mark(length);
  102. byte[] b = new byte[length];
  103. fis.read(b);
  104. String start = new String(b);
  105. fis.reset();
  106. if (start.equals("<?xml")) {
  107. // we have xml, might be another doc
  108. // so stop batik from closing the stream
  109. final InputStream input = fis;
  110. fis =
  111. new InputStream() {
  112. public int read() throws IOException {
  113. return input.read();
  114. }
  115. public int read(byte[] b) throws IOException {
  116. return input.read(b);
  117. }
  118. public int read(byte[] b, int off, int len)
  119. throws IOException {
  120. return input.read(b, off, len);
  121. }
  122. public long skip(long n) throws IOException {
  123. return input.skip(n);
  124. }
  125. public int available() throws IOException {
  126. return input.available();
  127. }
  128. public void mark(int rl) {
  129. input.mark(rl);
  130. }
  131. public boolean markSupported() {
  132. return input.markSupported();
  133. }
  134. public void reset() throws IOException {
  135. input.reset();
  136. }
  137. public void close() throws IOException {
  138. //ignore
  139. }
  140. };
  141. }
  142. FopImage.ImageInfo info = new FopImage.ImageInfo();
  143. info.mimeType = getMimeType();
  144. info.str = SVGDOMImplementation.SVG_NAMESPACE_URI;
  145. length = fis.available();
  146. fis.mark(length + 1);
  147. SAXSVGDocumentFactory factory = new SAXSVGDocumentFactory(
  148. XMLImage.getParserName());
  149. SVGDocument doc = (SVGDocument) factory.createSVGDocument(uri, fis);
  150. info.data = doc;
  151. Element e = doc.getRootElement();
  152. String s;
  153. SVGUserAgent userAg = new SVGUserAgent(logger, pixelUnitToMM,
  154. new AffineTransform());
  155. BridgeContext ctx = new BridgeContext(userAg);
  156. UnitProcessor.Context uctx =
  157. UnitProcessor.createContext(ctx, e);
  158. // 'width' attribute - default is 100%
  159. s = e.getAttributeNS(null,
  160. SVGOMDocument.SVG_WIDTH_ATTRIBUTE);
  161. if (s.length() == 0) {
  162. s = SVGOMDocument.SVG_SVG_WIDTH_DEFAULT_VALUE;
  163. }
  164. info.width = (int) UnitProcessor.svgHorizontalLengthToUserSpace(
  165. s, SVGOMDocument.SVG_WIDTH_ATTRIBUTE, uctx);
  166. // 'height' attribute - default is 100%
  167. s = e.getAttributeNS(null,
  168. SVGOMDocument.SVG_HEIGHT_ATTRIBUTE);
  169. if (s.length() == 0) {
  170. s = SVGOMDocument.SVG_SVG_HEIGHT_DEFAULT_VALUE;
  171. }
  172. info.height = (int) UnitProcessor.svgVerticalLengthToUserSpace(
  173. s, SVGOMDocument.SVG_HEIGHT_ATTRIBUTE, uctx);
  174. return info;
  175. } catch (NoClassDefFoundError ncdfe) {
  176. try {
  177. fis.reset();
  178. } catch (IOException ioe) {
  179. // we're more interested in the original exception
  180. }
  181. batik = false;
  182. //ua.getLogger().error("Batik not in class path", ncdfe);
  183. return null;
  184. } catch (Exception e) {
  185. // If the svg is invalid then it throws an IOException
  186. // so there is no way of knowing if it is an svg document
  187. // ua.getLogger().error("Could not load external SVG: " +
  188. // e.getMessage(), e);
  189. // assuming any exception means this document is not svg
  190. // or could not be loaded for some reason
  191. try {
  192. fis.reset();
  193. } catch (IOException ioe) {
  194. // we're more interested in the original exception
  195. }
  196. return null;
  197. }
  198. }
  199. }
  200. }