選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

SVGRenderer.java 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. /*
  2. * $Id$
  3. * Copyright (C) 2001 The Apache Software Foundation. All rights reserved.
  4. * For details on use and redistribution please refer to the
  5. * LICENSE file included with these sources.
  6. */
  7. package org.apache.fop.render.svg;
  8. import org.apache.fop.apps.FOPException;
  9. import org.apache.fop.area.*;
  10. import org.apache.fop.area.inline.*;
  11. import org.apache.fop.datatypes.ColorType;
  12. import org.apache.fop.image.*;
  13. import org.apache.fop.svg.SVGUtilities;
  14. import org.apache.fop.layout.FontInfo;
  15. import org.apache.fop.fo.FOUserAgent;
  16. import org.w3c.dom.Node;
  17. import org.w3c.dom.ProcessingInstruction;
  18. import org.w3c.dom.svg.SVGSVGElement;
  19. import org.w3c.dom.svg.SVGDocument;
  20. import org.w3c.dom.Document;
  21. import org.w3c.dom.Element;
  22. import org.w3c.dom.DOMImplementation;
  23. import org.w3c.dom.Text;
  24. import org.apache.batik.dom.svg.SVGDOMImplementation;
  25. import org.apache.batik.dom.svg.SVGOMElement;
  26. import org.apache.batik.dom.util.XMLSupport;
  27. import org.apache.batik.transcoder.svg2svg.SVGTranscoder;
  28. import org.apache.batik.transcoder.TranscoderInput;
  29. import org.apache.batik.transcoder.TranscoderOutput;
  30. import org.apache.batik.transcoder.TranscoderException;
  31. import org.apache.batik.dom.util.DOMUtilities;
  32. import java.awt.Color;
  33. import java.awt.Image;
  34. import java.awt.image.BufferedImage;
  35. import java.awt.geom.Rectangle2D;
  36. import java.util.HashMap;
  37. import java.net.URL;
  38. import java.net.MalformedURLException;
  39. import java.io.OutputStream;
  40. import java.io.IOException;
  41. import java.io.OutputStreamWriter;
  42. import javax.swing.ImageIcon;
  43. import org.apache.fop.render.AbstractRenderer;
  44. import org.apache.fop.render.XMLHandler;
  45. import org.apache.fop.render.RendererContext;
  46. public class SVGRenderer extends AbstractRenderer implements XMLHandler {
  47. public static final String mimeType = "image/svg+xml";
  48. static final String svgNS = SVGDOMImplementation.SVG_NAMESPACE_URI;
  49. Document svgDocument;
  50. Element svgRoot;
  51. Element currentPageG = null;
  52. Element lastLink = null;
  53. String lastViewbox = null;
  54. Element docDefs = null;
  55. Element pageDefs = null;
  56. Element pagesGroup = null;
  57. // first sequence title
  58. Title docTitle = null;
  59. RendererContext context;
  60. OutputStream ostream;
  61. float totalWidth = 0;
  62. float totalHeight = 0;
  63. float sequenceWidth = 0;
  64. float sequenceHeight = 0;
  65. protected float pageWidth = 0;
  66. protected float pageHeight = 0;
  67. protected int pageNumber = 0;
  68. protected HashMap fontNames = new HashMap();
  69. protected HashMap fontStyles = new HashMap();
  70. protected Color saveColor = null;
  71. /**
  72. * The current (internal) font name
  73. */
  74. protected String currentFontName;
  75. /**
  76. * The current font size in millipoints
  77. */
  78. protected int currentFontSize;
  79. /**
  80. * The current colour's red, green and blue component
  81. */
  82. protected float currentRed = 0;
  83. protected float currentGreen = 0;
  84. protected float currentBlue = 0;
  85. public SVGRenderer() {
  86. context = new RendererContext(mimeType);
  87. }
  88. public void setUserAgent(FOUserAgent agent) {
  89. super.setUserAgent(agent);
  90. userAgent.setDefaultXMLHandler(mimeType, this);
  91. userAgent.addXMLHandler(mimeType, svgNS, this);
  92. }
  93. public void setupFontInfo(FontInfo fontInfo) {
  94. // create a temp Image to test font metrics on
  95. BufferedImage fontImage =
  96. new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB);
  97. org.apache.fop.render.awt.FontSetup.setup(fontInfo,
  98. fontImage.createGraphics());
  99. }
  100. public void setProducer(String producer) {
  101. }
  102. public void startRenderer(OutputStream outputStream)
  103. throws IOException {
  104. ostream = outputStream;
  105. DOMImplementation impl =
  106. SVGDOMImplementation.getDOMImplementation();
  107. svgDocument = impl.createDocument(svgNS, "svg", null);
  108. ProcessingInstruction pi =
  109. svgDocument.createProcessingInstruction("xml", " version=\"1.0\" encoding=\"ISO-8859-1\"");
  110. svgRoot = svgDocument.getDocumentElement();
  111. svgDocument.insertBefore(pi, svgRoot);
  112. docDefs = svgDocument.createElementNS(svgNS, "defs");
  113. svgRoot.appendChild(docDefs);
  114. pagesGroup = svgDocument.createElementNS(svgNS, "g");
  115. pageDefs = svgDocument.createElementNS(svgNS, "defs");
  116. pagesGroup.appendChild(pageDefs);
  117. svgRoot.appendChild(pagesGroup);
  118. }
  119. /**
  120. *
  121. */
  122. public void stopRenderer() throws IOException {
  123. totalWidth += sequenceWidth;
  124. if (sequenceHeight > totalHeight) {
  125. totalHeight = sequenceHeight;
  126. }
  127. svgRoot.setAttributeNS(null, "width", "" + (totalWidth + 1));
  128. svgRoot.setAttributeNS(null, "height", "" + (totalHeight + 1));
  129. //svgRoot.setAttributeNS(null, "viewBox", "0 0 " + pageWidth + " " + pageHeight);
  130. SVGTranscoder svgT = new SVGTranscoder();
  131. TranscoderInput input = new TranscoderInput(svgDocument);
  132. TranscoderOutput output =
  133. new TranscoderOutput(new OutputStreamWriter(ostream));
  134. try {
  135. svgT.transcode(input, output);
  136. } catch (TranscoderException e) {
  137. getLogger().error("could not write svg file :" + e.getMessage(), e);
  138. }
  139. ostream.flush();
  140. ostream = null;
  141. svgDocument = null;
  142. svgRoot = null;
  143. currentPageG = null;
  144. lastLink = null;
  145. totalWidth = 0;
  146. totalHeight = 0;
  147. pageNumber = 0;
  148. }
  149. public void startPageSequence(Title seqTitle) {
  150. totalWidth += sequenceWidth;
  151. if (sequenceHeight > totalHeight) {
  152. totalHeight = sequenceHeight;
  153. }
  154. sequenceWidth = 0;
  155. sequenceHeight = 0;
  156. if (seqTitle != null && docTitle == null) {
  157. // convert first title to a string and set for svg document title
  158. docTitle = seqTitle;
  159. String str = convertTitleToString(seqTitle);
  160. Element svgTitle = svgDocument.createElementNS(svgNS, "title");
  161. Text strNode = svgDocument.createTextNode(str);
  162. svgTitle.appendChild(strNode);
  163. svgRoot.insertBefore(svgTitle, svgRoot.getFirstChild());
  164. }
  165. }
  166. public void renderPage(PageViewport page) throws IOException,
  167. FOPException {
  168. float lastWidth = pageWidth;
  169. float lastHeight = pageHeight;
  170. Rectangle2D area = page.getViewArea();
  171. pageWidth = (float) area.getWidth() / 1000f;
  172. pageHeight = (float) area.getHeight() / 1000f;
  173. // if there is a link from the last page
  174. if (lastLink != null) {
  175. lastLink.setAttributeNS(null, "xlink:href",
  176. "#svgView(viewBox(" + totalWidth + ", "+
  177. sequenceHeight + ", " + pageWidth + ", " +
  178. pageHeight + "))");
  179. pagesGroup.appendChild(lastLink);
  180. }
  181. currentPageG = svgDocument.createElementNS(svgNS, "svg");
  182. currentPageG.setAttributeNS(null, "viewbox",
  183. "0 0 " + (int) pageWidth + " " + (int) pageHeight);
  184. currentPageG.setAttributeNS(null, "width",
  185. "" + ((int) pageWidth + 1));
  186. currentPageG.setAttributeNS(null, "height",
  187. "" + ((int) pageHeight + 1));
  188. currentPageG.setAttributeNS(null, "id", "Page-" + pageNumber);
  189. currentPageG.setAttributeNS(null, "style", "font-family:sanserif;font-size:12");
  190. pageDefs.appendChild(currentPageG);
  191. if (pageWidth > sequenceWidth) {
  192. sequenceWidth = pageWidth;
  193. }
  194. sequenceHeight += pageHeight;
  195. Element border =
  196. SVGUtilities.createRect(svgDocument, 0, 0, pageWidth,
  197. pageHeight);
  198. border.setAttributeNS(null, "style", "fill:none;stroke:black");
  199. currentPageG.appendChild(border);
  200. // render the page contents
  201. super.renderPage(page);
  202. Element use = svgDocument.createElementNS(svgNS, "use");
  203. use.setAttributeNS(null, "xlink:href", "#Page-" + pageNumber);
  204. use.setAttributeNS(null, "x", "" + totalWidth);
  205. use.setAttributeNS(null, "y", "" + (sequenceHeight - pageHeight));
  206. pagesGroup.appendChild(use);
  207. Element lastPageLink = svgDocument.createElementNS(svgNS, "a");
  208. if (lastLink != null) {
  209. lastPageLink.setAttributeNS(null, "xlink:href", lastViewbox);
  210. } else {
  211. lastPageLink.setAttributeNS(null, "xlink:href",
  212. "#svgView(viewBox(" + totalWidth + ", " +
  213. (sequenceHeight - pageHeight) + ", " + pageWidth +
  214. ", " + pageHeight + "))");
  215. }
  216. pagesGroup.appendChild(lastPageLink);
  217. // setup a link to the next page, only added when the
  218. // next page is rendered
  219. Element rect = SVGUtilities.createRect(svgDocument, totalWidth,
  220. (sequenceHeight - pageHeight), pageWidth / 2, pageHeight);
  221. rect.setAttributeNS(null, "style", "fill:blue;visibility:hidden");
  222. lastPageLink.appendChild(rect);
  223. lastLink = svgDocument.createElementNS(svgNS, "a");
  224. rect = SVGUtilities.createRect(svgDocument,
  225. totalWidth + pageWidth / 2,
  226. (sequenceHeight - pageHeight), pageWidth / 2, pageHeight);
  227. rect.setAttributeNS(null, "style", "fill:blue;visibility:hidden");
  228. lastLink.appendChild(rect);
  229. lastViewbox = "#svgView(viewBox(" + totalWidth + ", " +
  230. (sequenceHeight - pageHeight) + ", " + pageWidth +
  231. ", " + pageHeight + "))";
  232. pageNumber++;
  233. }
  234. public void renderForeignObject(ForeignObject fo) {
  235. Document doc = fo.getDocument();
  236. String ns = fo.getNameSpace();
  237. userAgent.renderXML(context, doc, ns);
  238. }
  239. public void handleXML(RendererContext context, Document doc,
  240. String ns) throws Exception {
  241. if (svgNS.equals(ns)) {
  242. if (!(doc instanceof SVGDocument)) {
  243. DOMImplementation impl =
  244. SVGDOMImplementation.getDOMImplementation();
  245. doc = DOMUtilities.deepCloneDocument(doc, impl);
  246. }
  247. SVGSVGElement svg = ((SVGDocument) doc).getRootElement();
  248. Element view = svgDocument.createElementNS(svgNS, "svg");
  249. Node newsvg = svgDocument.importNode(svg, true);
  250. //view.setAttributeNS(null, "viewBox", "0 0 ");
  251. view.setAttributeNS(null, "x",
  252. "" + currentBlockIPPosition / 1000f);
  253. view.setAttributeNS(null, "y", "" + currentBPPosition / 1000f);
  254. // this fixes a problem where the xmlns is repeated sometimes
  255. Element ele = (Element) newsvg;
  256. ele.setAttributeNS(XMLSupport.XMLNS_NAMESPACE_URI, "xmlns",
  257. svgNS);
  258. if (ele.hasAttributeNS(null, "xmlns")) {
  259. ele.removeAttributeNS(null, "xmlns");
  260. }
  261. view.appendChild(newsvg);
  262. currentPageG.appendChild(view);
  263. }
  264. }
  265. public void renderLeader(Leader area) {
  266. String style = "stroke:black;stroke-width:" +
  267. (area.getRuleThickness() / 1000) + ";";
  268. switch (area.getRuleStyle()) {
  269. case Leader.DOTTED:
  270. style += "stroke-dasharray:1,1";
  271. break;
  272. case Leader.DASHED:
  273. style += "stroke-dasharray:5,1";
  274. break;
  275. case Leader.SOLID:
  276. break;
  277. case Leader.DOUBLE:
  278. break;
  279. case Leader.GROOVE:
  280. break;
  281. case Leader.RIDGE:
  282. break;
  283. }
  284. Element line = SVGUtilities.createLine(svgDocument,
  285. currentBlockIPPosition / 1000,
  286. (currentBPPosition + area.getOffset() -
  287. area.getRuleThickness() / 2) / 1000,
  288. (currentBlockIPPosition + area.getWidth()) / 1000,
  289. (currentBPPosition + area.getOffset() -
  290. area.getRuleThickness() / 2) / 1000);
  291. line.setAttributeNS(null, "style", style);
  292. currentPageG.appendChild(line);
  293. super.renderLeader(area);
  294. }
  295. public void renderWord(Word word) {
  296. Element text = SVGUtilities.createText(svgDocument,
  297. currentBlockIPPosition / 1000,
  298. (currentBPPosition + word.getOffset()) / 1000,
  299. word.getWord());
  300. currentPageG.appendChild(text);
  301. super.renderWord(word);
  302. }
  303. public void renderCharacter(org.apache.fop.area.inline.Character ch) {
  304. Element text = SVGUtilities.createText(svgDocument,
  305. currentBlockIPPosition / 1000,
  306. (currentBPPosition + ch.getOffset()) / 1000,
  307. "" + ch.getChar());
  308. currentPageG.appendChild(text);
  309. super.renderCharacter(ch);
  310. }
  311. }