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 6.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one or more
  3. * contributor license agreements. See the NOTICE file distributed with
  4. * this work for additional information regarding copyright ownership.
  5. * The ASF licenses this file to You under the Apache License, Version 2.0
  6. * (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. /* $Id$ */
  18. package org.apache.fop.image.analyser;
  19. // Java
  20. import java.io.InputStream;
  21. import java.io.IOException;
  22. import java.awt.geom.AffineTransform;
  23. // XML
  24. import org.w3c.dom.Element;
  25. import org.w3c.dom.svg.SVGDocument;
  26. // Batik
  27. import org.apache.batik.dom.svg.SAXSVGDocumentFactory;
  28. import org.apache.batik.dom.svg.SVGOMDocument;
  29. import org.apache.batik.bridge.BridgeContext;
  30. import org.apache.batik.bridge.UnitProcessor;
  31. import org.apache.batik.dom.svg.SVGDOMImplementation;
  32. import org.apache.commons.io.IOUtils;
  33. import org.apache.commons.logging.Log;
  34. import org.apache.commons.logging.LogFactory;
  35. // FOP
  36. import org.apache.fop.image.XMLImage;
  37. import org.apache.fop.image.FopImage;
  38. import org.apache.fop.apps.FOUserAgent;
  39. import org.apache.fop.svg.SVGUserAgent;
  40. import org.apache.fop.util.UnclosableInputStream;
  41. /**
  42. * ImageReader object for SVG document image type.
  43. */
  44. public class SVGReader implements ImageReader {
  45. /** Logger instance */
  46. protected static Log log = LogFactory.getLog(SVGReader.class);
  47. /** SVG's MIME type */
  48. public static final String SVG_MIME_TYPE = "image/svg+xml";
  49. private boolean batik = true;
  50. /** {@inheritDoc} */
  51. public FopImage.ImageInfo verifySignature(String uri, InputStream fis,
  52. FOUserAgent ua) throws IOException {
  53. FopImage.ImageInfo info = loadImage(uri, fis, ua);
  54. if (info != null) {
  55. IOUtils.closeQuietly(fis);
  56. }
  57. return info;
  58. }
  59. /**
  60. * Returns the MIME type supported by this implementation.
  61. *
  62. * @return The MIME type
  63. */
  64. public String getMimeType() {
  65. return SVG_MIME_TYPE;
  66. }
  67. /**
  68. * This means the external svg document will be loaded twice. Possibly need
  69. * a slightly different design for the image stuff.
  70. *
  71. * @param uri @todo Description of the Parameter
  72. * @param fis @todo Description of the Parameter
  73. * @param ua @todo Description of the Parameter
  74. * @return @todo Description of the Return Value
  75. */
  76. private FopImage.ImageInfo loadImage(String uri, InputStream bis,
  77. FOUserAgent ua) {
  78. if (batik) {
  79. try {
  80. Loader loader = new Loader();
  81. return loader.getImage(uri, bis,
  82. ua.getSourcePixelUnitToMillimeter());
  83. } catch (NoClassDefFoundError e) {
  84. batik = false;
  85. log.warn("Batik not in class path", e);
  86. return null;
  87. }
  88. }
  89. return null;
  90. }
  91. /**
  92. * This method is put in another class so that the classloader does not
  93. * attempt to load batik related classes when constructing the SVGReader
  94. * class.
  95. */
  96. class Loader {
  97. private FopImage.ImageInfo getImage(String uri, InputStream fis,
  98. float pixelUnitToMM) {
  99. // parse document and get the size attributes of the svg element
  100. try {
  101. fis = new UnclosableInputStream(fis);
  102. FopImage.ImageInfo info = new FopImage.ImageInfo();
  103. //Set the resolution to that of the FOUserAgent
  104. info.dpiHorizontal = 25.4f / pixelUnitToMM;
  105. info.dpiVertical = info.dpiHorizontal;
  106. info.originalURI = uri;
  107. info.mimeType = getMimeType();
  108. info.str = SVGDOMImplementation.SVG_NAMESPACE_URI;
  109. int length = fis.available();
  110. fis.mark(length + 1);
  111. SAXSVGDocumentFactory factory = new SAXSVGDocumentFactory(
  112. XMLImage.getParserName());
  113. SVGDocument doc = (SVGDocument) factory.createSVGDocument(uri, fis);
  114. info.data = doc;
  115. Element e = doc.getRootElement();
  116. String s;
  117. SVGUserAgent userAg = new SVGUserAgent(pixelUnitToMM,
  118. new AffineTransform());
  119. BridgeContext ctx = new BridgeContext(userAg);
  120. UnitProcessor.Context uctx = UnitProcessor.createContext(ctx, e);
  121. // 'width' attribute - default is 100%
  122. s = e.getAttributeNS(null,
  123. SVGOMDocument.SVG_WIDTH_ATTRIBUTE);
  124. if (s.length() == 0) {
  125. s = SVGOMDocument.SVG_SVG_WIDTH_DEFAULT_VALUE;
  126. }
  127. info.width = Math.round(UnitProcessor.svgHorizontalLengthToUserSpace(
  128. s, SVGOMDocument.SVG_WIDTH_ATTRIBUTE, uctx));
  129. // 'height' attribute - default is 100%
  130. s = e.getAttributeNS(null,
  131. SVGOMDocument.SVG_HEIGHT_ATTRIBUTE);
  132. if (s.length() == 0) {
  133. s = SVGOMDocument.SVG_SVG_HEIGHT_DEFAULT_VALUE;
  134. }
  135. info.height = Math.round(UnitProcessor.svgVerticalLengthToUserSpace(
  136. s, SVGOMDocument.SVG_HEIGHT_ATTRIBUTE, uctx));
  137. return info;
  138. } catch (NoClassDefFoundError ncdfe) {
  139. try {
  140. fis.reset();
  141. } catch (IOException ioe) {
  142. // we're more interested in the original exception
  143. }
  144. batik = false;
  145. log.warn("Batik not in class path", ncdfe);
  146. return null;
  147. } catch (IOException e) {
  148. // If the svg is invalid then it throws an IOException
  149. // so there is no way of knowing if it is an svg document
  150. log.debug("Error while trying to load stream as an SVG file: "
  151. + e.getMessage());
  152. // assuming any exception means this document is not svg
  153. // or could not be loaded for some reason
  154. try {
  155. fis.reset();
  156. } catch (IOException ioe) {
  157. // we're more interested in the original exception
  158. }
  159. return null;
  160. }
  161. }
  162. }
  163. }