Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

PDFContentGenerator.java 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  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.render.pdf;
  19. import java.awt.Color;
  20. import java.awt.geom.AffineTransform;
  21. import java.io.IOException;
  22. import java.io.OutputStream;
  23. import org.apache.fop.pdf.PDFColor;
  24. import org.apache.fop.pdf.PDFDocument;
  25. import org.apache.fop.pdf.PDFFilterList;
  26. import org.apache.fop.pdf.PDFNumber;
  27. import org.apache.fop.pdf.PDFResourceContext;
  28. import org.apache.fop.pdf.PDFState;
  29. import org.apache.fop.pdf.PDFStream;
  30. import org.apache.fop.pdf.PDFTextUtil;
  31. import org.apache.fop.pdf.PDFXObject;
  32. /**
  33. * Generator class encapsulating all object references and state necessary to generate a
  34. * PDF content stream.
  35. */
  36. public class PDFContentGenerator {
  37. /** Controls whether comments are written to the PDF stream. */
  38. protected static final boolean WRITE_COMMENTS = true;
  39. private PDFDocument document;
  40. private OutputStream outputStream;
  41. private PDFResourceContext resourceContext;
  42. /** the current stream to add PDF commands to */
  43. private PDFStream currentStream;
  44. /** drawing state */
  45. protected PDFState currentState = null;
  46. /** Text generation utility holding the current font status */
  47. protected PDFTextUtil textutil;
  48. /**
  49. * Main constructor. Creates a new PDF stream and additional helper classes for text painting
  50. * and state management.
  51. * @param document the PDF document
  52. * @param out the output stream the PDF document is generated to
  53. * @param resourceContext the resource context
  54. */
  55. public PDFContentGenerator(PDFDocument document, OutputStream out,
  56. PDFResourceContext resourceContext) {
  57. this.document = document;
  58. this.outputStream = out;
  59. this.resourceContext = resourceContext;
  60. this.currentStream = document.getFactory()
  61. .makeStream(PDFFilterList.CONTENT_FILTER, false);
  62. this.textutil = new PDFTextUtil() {
  63. protected void write(String code) {
  64. currentStream.add(code);
  65. }
  66. };
  67. this.currentState = new PDFState();
  68. }
  69. /**
  70. * Returns the applicable resource context for the generator.
  71. * @return the resource context
  72. */
  73. public PDFDocument getDocument() {
  74. return this.document;
  75. }
  76. /**
  77. * Returns the output stream the PDF document is written to.
  78. * @return the output stream
  79. */
  80. public OutputStream getOutputStream() {
  81. return this.outputStream;
  82. }
  83. /**
  84. * Returns the applicable resource context for the generator.
  85. * @return the resource context
  86. */
  87. public PDFResourceContext getResourceContext() {
  88. return this.resourceContext;
  89. }
  90. /**
  91. * Returns the {@code PDFStream} associated with this instance.
  92. * @return the PDF stream
  93. */
  94. public PDFStream getStream() {
  95. return this.currentStream;
  96. }
  97. /**
  98. * Returns the {@code PDFState} associated with this instance.
  99. * @return the PDF state
  100. */
  101. public PDFState getState() {
  102. return this.currentState;
  103. }
  104. /**
  105. * Returns the {@code PDFTextUtil} associated with this instance.
  106. * @return the text utility
  107. */
  108. public PDFTextUtil getTextUtil() {
  109. return this.textutil;
  110. }
  111. /**
  112. * Flushes all queued PDF objects ready to be written to the output stream.
  113. * @throws IOException if an error occurs while flushing the PDF objects
  114. */
  115. public void flushPDFDoc() throws IOException {
  116. this.document.output(this.outputStream);
  117. }
  118. /**
  119. * Writes out a comment.
  120. * @param text text for the comment
  121. */
  122. protected void comment(String text) {
  123. if (WRITE_COMMENTS) {
  124. currentStream.add("% " + text + "\n");
  125. }
  126. }
  127. /** {@inheritDoc} */
  128. protected void saveGraphicsState() {
  129. endTextObject();
  130. currentState.push();
  131. currentStream.add("q\n");
  132. }
  133. /**
  134. * Restored the graphics state valid before the previous {@code #saveGraphicsState()}.
  135. * @param popState true if the state should also be popped, false if only the PDF command
  136. * should be issued
  137. */
  138. protected void restoreGraphicsState(boolean popState) {
  139. endTextObject();
  140. currentStream.add("Q\n");
  141. if (popState) {
  142. currentState.pop();
  143. }
  144. }
  145. /** {@inheritDoc} */
  146. protected void restoreGraphicsState() {
  147. restoreGraphicsState(true);
  148. }
  149. /** Indicates the beginning of a text object. */
  150. protected void beginTextObject() {
  151. if (!textutil.isInTextObject()) {
  152. textutil.beginTextObject();
  153. }
  154. }
  155. /** Indicates the end of a text object. */
  156. protected void endTextObject() {
  157. if (textutil.isInTextObject()) {
  158. textutil.endTextObject();
  159. }
  160. }
  161. /**
  162. * Converts a transformation matrix from millipoints to points.
  163. * @param transform the transformation matrix (in millipoints)
  164. * @return the converted transformation matrix (in points)
  165. */
  166. public AffineTransform toPoints(AffineTransform transform) {
  167. final double[] matrix = new double[6];
  168. transform.getMatrix(matrix);
  169. //Convert from millipoints to points
  170. matrix[4] /= 1000;
  171. matrix[5] /= 1000;
  172. return new AffineTransform(matrix);
  173. }
  174. /**
  175. * Concatenates the given transformation matrix with the current one.
  176. * @param transform the transformation matrix (in points)
  177. */
  178. public void concatenate(AffineTransform transform) {
  179. if (!transform.isIdentity()) {
  180. currentState.concatenate(transform);
  181. currentStream.add(CTMHelper.toPDFString(transform, false) + " cm\n");
  182. }
  183. }
  184. /**
  185. * Adds content to the stream.
  186. * @param content the PDF content
  187. */
  188. public void add(String content) {
  189. currentStream.add(content);
  190. }
  191. /**
  192. * Formats a float value (normally coordinates in points) as Strings.
  193. * @param value the value
  194. * @return the formatted value
  195. */
  196. public static final String format(float value) {
  197. return PDFNumber.doubleOut(value);
  198. }
  199. /**
  200. * Sets the current line width in points.
  201. * @param width line width in points
  202. */
  203. public void updateLineWidth(float width) {
  204. if (currentState.setLineWidth(width)) {
  205. //Only write if value has changed WRT the current line width
  206. currentStream.add(format(width) + " w\n");
  207. }
  208. }
  209. /**
  210. * Establishes a new foreground or fill color. In contrast to updateColor
  211. * this method does not check the PDFState for optimization possibilities.
  212. * @param col the color to apply
  213. * @param fill true to set the fill color, false for the foreground color
  214. * @param pdf StringBuffer to write the PDF code to
  215. *//*
  216. public void setColor(Color col, boolean fill, StringBuffer pdf) {
  217. assert pdf != null;
  218. }*/
  219. /**
  220. * Establishes a new foreground or fill color.
  221. * @param col the color to apply
  222. * @param fill true to set the fill color, false for the foreground color
  223. * @param stream the PDFStream to write the PDF code to
  224. */
  225. public void setColor(Color col, boolean fill, PDFStream stream) {
  226. assert stream != null;
  227. PDFColor color = new PDFColor(this.document, col);
  228. stream.add(color.getColorSpaceOut(fill));
  229. }
  230. /**
  231. * Establishes a new foreground or fill color.
  232. * @param col the color to apply
  233. * @param fill true to set the fill color, false for the foreground color
  234. */
  235. public void setColor(Color col, boolean fill) {
  236. setColor(col, fill, getStream());
  237. }
  238. /**
  239. * Establishes a new foreground or fill color. In contrast to updateColor
  240. * this method does not check the PDFState for optimization possibilities.
  241. * @param col the color to apply
  242. * @param fill true to set the fill color, false for the foreground color
  243. * @param pdf StringBuffer to write the PDF code to, if null, the code is
  244. * written to the current stream.
  245. */
  246. protected void setColor(Color col, boolean fill, StringBuffer pdf) {
  247. if (pdf != null) {
  248. PDFColor color = new PDFColor(this.document, col);
  249. pdf.append(color.getColorSpaceOut(fill));
  250. } else {
  251. setColor(col, fill, this.currentStream);
  252. }
  253. }
  254. /**
  255. * Establishes a new foreground or fill color.
  256. * @param col the color to apply (null skips this operation)
  257. * @param fill true to set the fill color, false for the foreground color
  258. * @param pdf StringBuffer to write the PDF code to, if null, the code is
  259. * written to the current stream.
  260. */
  261. public void updateColor(Color col, boolean fill, StringBuffer pdf) {
  262. if (col == null) {
  263. return;
  264. }
  265. boolean update = false;
  266. if (fill) {
  267. update = getState().setBackColor(col);
  268. } else {
  269. update = getState().setColor(col);
  270. }
  271. if (update) {
  272. setColor(col, fill, pdf);
  273. }
  274. }
  275. /**
  276. * Places a previously registered image at a certain place on the page.
  277. * @param x X coordinate
  278. * @param y Y coordinate
  279. * @param w width for image
  280. * @param h height for image
  281. * @param xobj the image XObject
  282. */
  283. public void placeImage(float x, float y, float w, float h, PDFXObject xobj) {
  284. saveGraphicsState();
  285. add(format(w) + " 0 0 "
  286. + format(-h) + " "
  287. + format(x) + " "
  288. + format(y + h)
  289. + " cm\n" + xobj.getName() + " Do\n");
  290. restoreGraphicsState();
  291. }
  292. }