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.

AbstractPDFStream.java 9.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  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.pdf;
  19. import java.io.IOException;
  20. import java.io.OutputStream;
  21. import org.apache.commons.io.output.CountingOutputStream;
  22. import org.apache.fop.util.CloseBlockerOutputStream;
  23. /**
  24. * This is an abstract base class for PDF streams.
  25. */
  26. public abstract class AbstractPDFStream extends PDFObject {
  27. private final PDFDictionary dictionary;
  28. /** The filters that should be applied */
  29. private PDFFilterList filters;
  30. private final boolean encodeOnTheFly;
  31. protected AbstractPDFStream() {
  32. this(true);
  33. }
  34. protected AbstractPDFStream(PDFDictionary dictionary) {
  35. this(dictionary, true);
  36. }
  37. protected AbstractPDFStream(boolean encodeOnTheFly) {
  38. this(new PDFDictionary(), encodeOnTheFly);
  39. }
  40. protected AbstractPDFStream(PDFDictionary dictionary, boolean encodeOnTheFly) {
  41. this.dictionary = dictionary;
  42. dictionary.setParent(this);
  43. this.encodeOnTheFly = encodeOnTheFly;
  44. }
  45. protected final PDFDictionary getDictionary() {
  46. return dictionary;
  47. }
  48. public Object get(String key) {
  49. return dictionary.get(key);
  50. }
  51. /**
  52. * Puts the given object in the dictionary associated to this stream.
  53. *
  54. * @param key the key in the dictionary
  55. * @param value the value to store
  56. */
  57. public void put(String key, Object value) {
  58. dictionary.put(key, value);
  59. }
  60. /**
  61. * Sets up the default filters for this stream if they haven't been set
  62. * from outside.
  63. */
  64. protected void setupFilterList() {
  65. if (multipleFiltersAllowed() && !getFilterList().isInitialized()) {
  66. getFilterList().addDefaultFilters(
  67. getDocumentSafely().getFilterMap(),
  68. getDefaultFilterName());
  69. }
  70. prepareImplicitFilters();
  71. getDocument().applyEncryption(this);
  72. }
  73. /**
  74. * Returns the name of a suitable filter for this PDF object.
  75. *
  76. * @return the default filter
  77. * @see PDFFilterList
  78. */
  79. protected String getDefaultFilterName() {
  80. return PDFFilterList.DEFAULT_FILTER;
  81. }
  82. /**
  83. * Returns the associated filter list.
  84. * @return the filter list
  85. */
  86. public PDFFilterList getFilterList() {
  87. if (this.filters == null) {
  88. if (getDocument() == null) {
  89. this.filters = new PDFFilterList();
  90. } else {
  91. this.filters = new PDFFilterList(getDocument().isEncryptionActive());
  92. }
  93. boolean hasFilterEntries = (get("Filter") != null);
  94. if (hasFilterEntries) {
  95. this.filters.setDisableAllFilters(true);
  96. }
  97. }
  98. return this.filters;
  99. }
  100. /**
  101. * Returns a value that hints at the size of the encoded stream. This is
  102. * used to optimize buffer allocation so fewer buffer reallocations are
  103. * necessary.
  104. * @return an estimated size (0 if no hint can be given)
  105. * @throws IOException in case of an I/O problem
  106. */
  107. protected abstract int getSizeHint() throws IOException;
  108. /**
  109. * Sends the raw stream data to the target OutputStream.
  110. * @param out OutputStream to write to
  111. * @throws IOException In case of an I/O problem
  112. */
  113. protected abstract void outputRawStreamData(OutputStream out)
  114. throws IOException;
  115. /**
  116. * Output just the stream data enclosed by stream/endstream markers
  117. * @param encodedStream already encoded/filtered stream to write
  118. * @param out OutputStream to write to
  119. * @return int number of bytes written
  120. * @throws IOException in case of an I/O problem
  121. */
  122. protected int outputStreamData(StreamCache encodedStream, OutputStream out) throws IOException {
  123. int length = 0;
  124. byte[] p = encode("\nstream\n");
  125. out.write(p);
  126. length += p.length;
  127. encodedStream.outputContents(out);
  128. length += encodedStream.getSize();
  129. p = encode("\nendstream");
  130. out.write(p);
  131. length += p.length;
  132. return length;
  133. }
  134. /**
  135. * Encodes the raw data stream for output to a PDF file.
  136. * @return the encoded stream
  137. * @throws IOException in case of an I/O problem
  138. */
  139. protected StreamCache encodeStream() throws IOException {
  140. //Allocate a temporary buffer to find out the size of the encoded stream
  141. final StreamCache encodedStream = StreamCacheFactory.getInstance()
  142. .createStreamCache(getSizeHint());
  143. OutputStream filteredOutput
  144. = getFilterList().applyFilters(encodedStream.getOutputStream());
  145. outputRawStreamData(filteredOutput);
  146. filteredOutput.flush();
  147. filteredOutput.close();
  148. return encodedStream;
  149. }
  150. /**
  151. * Encodes and writes a stream directly to an OutputStream. The length of
  152. * the stream, in this case, is set on a PDFNumber object that has to be
  153. * prepared beforehand.
  154. * @param out OutputStream to write to
  155. * @param refLength PDFNumber object to receive the stream length
  156. * @return number of bytes written (header and trailer included)
  157. * @throws IOException in case of an I/O problem
  158. */
  159. protected int encodeAndWriteStream(OutputStream out, PDFNumber refLength)
  160. throws IOException {
  161. int bytesWritten = 0;
  162. //Stream header
  163. byte[] buf = encode("\nstream\n");
  164. out.write(buf);
  165. bytesWritten += buf.length;
  166. //Stream contents
  167. CloseBlockerOutputStream cbout = new CloseBlockerOutputStream(out);
  168. CountingOutputStream cout = new CountingOutputStream(cbout);
  169. OutputStream filteredOutput = getFilterList().applyFilters(cout);
  170. outputRawStreamData(filteredOutput);
  171. filteredOutput.close();
  172. refLength.setNumber(Integer.valueOf(cout.getCount()));
  173. bytesWritten += cout.getCount();
  174. //Stream trailer
  175. buf = encode("\nendstream");
  176. out.write(buf);
  177. bytesWritten += buf.length;
  178. return bytesWritten;
  179. }
  180. /**
  181. * Overload the base object method so we don't have to copy
  182. * byte arrays around so much
  183. * {@inheritDoc}
  184. */
  185. @Override
  186. public int output(OutputStream stream) throws IOException {
  187. setupFilterList();
  188. CountingOutputStream cout = new CountingOutputStream(stream);
  189. StringBuilder textBuffer = new StringBuilder(64);
  190. StreamCache encodedStream = null;
  191. PDFNumber refLength = null;
  192. final Object lengthEntry;
  193. if (encodeOnTheFly) {
  194. refLength = new PDFNumber();
  195. getDocumentSafely().registerObject(refLength);
  196. lengthEntry = refLength;
  197. } else {
  198. encodedStream = encodeStream();
  199. lengthEntry = Integer.valueOf(encodedStream.getSize() + 1);
  200. }
  201. populateStreamDict(lengthEntry);
  202. dictionary.writeDictionary(cout, textBuffer);
  203. //Send encoded stream to target OutputStream
  204. PDFDocument.flushTextBuffer(textBuffer, cout);
  205. if (encodedStream == null) {
  206. encodeAndWriteStream(cout, refLength);
  207. } else {
  208. outputStreamData(encodedStream, cout);
  209. encodedStream.clear(); //Encoded stream can now be discarded
  210. }
  211. PDFDocument.flushTextBuffer(textBuffer, cout);
  212. return cout.getCount();
  213. }
  214. @Override
  215. public void setDocument(PDFDocument doc) {
  216. dictionary.setDocument(doc);
  217. super.setDocument(doc);
  218. }
  219. /**
  220. * Populates the dictionary with all necessary entries for the stream.
  221. * Override this method if you need additional entries.
  222. * @param lengthEntry value for the /Length entry
  223. */
  224. protected void populateStreamDict(Object lengthEntry) {
  225. put("Length", lengthEntry);
  226. if (!getFilterList().isDisableAllFilters()) {
  227. getFilterList().putFilterDictEntries(dictionary);
  228. }
  229. }
  230. /**
  231. * Prepares implicit filters (such as the DCTFilter for JPEG images). You
  232. * must make sure that the appropriate filters are in the filter list at
  233. * the right places.
  234. */
  235. protected void prepareImplicitFilters() {
  236. //nop: No default implicit filters
  237. }
  238. /**
  239. * Whether multiple filters can be applied.
  240. * @return true if multiple filters allowed
  241. */
  242. protected boolean multipleFiltersAllowed() {
  243. return true;
  244. }
  245. }