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.

PDFStream.java 8.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  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.pdf;
  8. import java.io.ByteArrayOutputStream;
  9. import java.io.OutputStream;
  10. import java.io.IOException;
  11. import java.util.ArrayList;
  12. import java.util.Enumeration;
  13. import org.apache.fop.configuration.Configuration;
  14. /**
  15. * class representing a PDF stream.
  16. *
  17. * A derivative of the PDF Object, a PDF Stream has not only a dictionary
  18. * but a stream of PDF commands. The stream of commands is where the real
  19. * work is done, the dictionary just provides information like the stream
  20. * length.
  21. */
  22. public class PDFStream extends PDFObject {
  23. /**
  24. * the stream of PDF commands
  25. */
  26. protected ByteArrayOutputStream _data;
  27. /**
  28. * the filters that should be applied
  29. */
  30. private ArrayList _filters;
  31. /**
  32. * create an empty stream object
  33. *
  34. * @param number the object's number
  35. */
  36. public PDFStream(int number) {
  37. super(number);
  38. _data = new ByteArrayOutputStream();
  39. _filters = new ArrayList();
  40. }
  41. /**
  42. * append data to the stream
  43. *
  44. * @param s the string of PDF to add
  45. */
  46. public void add(String s) {
  47. try {
  48. _data.write(s.getBytes());
  49. } catch (IOException ex) {
  50. ex.printStackTrace();
  51. }
  52. }
  53. /**
  54. * Add a filter for compression of the stream. Filters are
  55. * applied in the order they are added. This should always be a
  56. * new instance of the particular filter of choice. The applied
  57. * flag in the filter is marked true after it has been applied to the
  58. * data.
  59. */
  60. public void addFilter(PDFFilter filter) {
  61. if (filter != null) {
  62. _filters.add(filter);
  63. }
  64. }
  65. public void addFilter(String filterType) {
  66. if (filterType == null) {
  67. return;
  68. }
  69. if (filterType.equals("flate")) {
  70. addFilter(new FlateFilter());
  71. } else if (filterType.equals("ascii-85")) {
  72. addFilter(new ASCII85Filter());
  73. } else if (filterType.equals("ascii-hex")) {
  74. addFilter(new ASCIIHexFilter());
  75. } else if (filterType.equals("")) {
  76. return;
  77. } else {
  78. //log.error("Unsupported filter type in stream-filter-list: "
  79. // + filterType);
  80. }
  81. }
  82. protected void addDefaultFilters() {
  83. ArrayList filters = Configuration.getListValue("stream-filter-list",
  84. Configuration.PDF);
  85. if (filters == null) {
  86. // try getting it as a String
  87. String filter = Configuration.getStringValue("stream-filter-list",
  88. Configuration.PDF);
  89. if (filter == null) {
  90. // built-in default to flate
  91. addFilter(new FlateFilter());
  92. } else {
  93. addFilter(filter);
  94. }
  95. } else {
  96. for (int i = 0; i < filters.size(); i++) {
  97. String v = (String)filters.get(i);
  98. addFilter(v);
  99. }
  100. }
  101. }
  102. /**
  103. * append an array of xRGB pixels, ASCII Hex Encoding it first
  104. *
  105. * @param pixels the area of pixels
  106. * @param width the width of the image in pixels
  107. * @param height the height of the image in pixels
  108. */
  109. public void addImageArray(int[] pixels, int width, int height) {
  110. try {
  111. for (int i = 0; i < height; i++) {
  112. for (int j = 0; j < width; j++) {
  113. int p = pixels[i * width + j];
  114. int r = (p >> 16) & 0xFF;
  115. int g = (p >> 8) & 0xFF;
  116. int b = (p) & 0xFF;
  117. if (r < 16) {
  118. _data.write('0');
  119. }
  120. _data.write(Integer.toHexString(r).getBytes());
  121. if (g < 16) {
  122. _data.write('0');
  123. }
  124. _data.write(Integer.toHexString(g).getBytes());
  125. if (b < 16) {
  126. _data.write('0');
  127. }
  128. _data.write(Integer.toHexString(b).getBytes());
  129. _data.write(' ');
  130. }
  131. }
  132. _data.write(">\n".getBytes());
  133. } catch (IOException ex) {
  134. ex.printStackTrace();
  135. }
  136. }
  137. public void setData(byte[] data) throws IOException {
  138. _data.reset();
  139. _data.write(data);
  140. }
  141. public byte[] getData() {
  142. return _data.toByteArray();
  143. }
  144. public int getDataLength() {
  145. return _data.size();
  146. }
  147. /**
  148. * represent as PDF.
  149. *
  150. * @return the PDF string.
  151. */
  152. /*
  153. * public byte[] toPDF() {
  154. * byte[] d = _data.toByteArray();
  155. * ByteArrayOutputStream s = new ByteArrayOutputStream();
  156. * String p = this.number + " " + this.generation
  157. * + " obj\n<< /Length " + (d.length+1)
  158. * + " >>\nstream\n";
  159. * s.write(p.getBytes());
  160. * s.write(d);
  161. * s.write("\nendstream\nendobj\n".getBytes());
  162. * return s.toByteArray();
  163. * }
  164. */
  165. public byte[] toPDF() {
  166. throw new RuntimeException();
  167. }
  168. // overload the base object method so we don't have to copy
  169. // byte arrays around so much
  170. protected int output(OutputStream stream) throws IOException {
  171. int length = 0;
  172. String filterEntry = applyFilters();
  173. byte[] p = (this.number + " " + this.generation + " obj\n<< /Length "
  174. + (_data.size() + 1) + " " + filterEntry
  175. + " >>\n").getBytes();
  176. stream.write(p);
  177. length += p.length;
  178. length += outputStreamData(stream);
  179. p = "endobj\n".getBytes();
  180. stream.write(p);
  181. length += p.length;
  182. return length;
  183. }
  184. /**
  185. * Output just the stream data enclosed by stream/endstream markers
  186. */
  187. protected int outputStreamData(OutputStream stream) throws IOException {
  188. int length = 0;
  189. byte[] p = "stream\n".getBytes();
  190. stream.write(p);
  191. length += p.length;
  192. _data.writeTo(stream);
  193. length += _data.size();
  194. p = "\nendstream\n".getBytes();
  195. stream.write(p);
  196. length += p.length;
  197. return length;
  198. }
  199. /**
  200. * Apply the filters to the data
  201. * in the order given and return the /Filter and /DecodeParms
  202. * entries for the stream dictionary. If the filters have already
  203. * been applied to the data (either externally, or internally)
  204. * then the dictionary entries are built and returned.
  205. */
  206. protected String applyFilters() throws IOException {
  207. if (_filters.size() > 0) {
  208. ArrayList names = new ArrayList();
  209. ArrayList parms = new ArrayList();
  210. // run the filters
  211. for (int count = 0; count < _filters.size(); count++) {
  212. PDFFilter filter = (PDFFilter)_filters.get(count);
  213. // apply the filter encoding if neccessary
  214. if (!filter.isApplied()) {
  215. byte[] tmp = filter.encode(_data.toByteArray());
  216. _data.reset();
  217. _data.write(tmp);
  218. filter.setApplied(true);
  219. }
  220. // place the names in our local vector in reverse order
  221. names.add(0, filter.getName());
  222. parms.add(0, filter.getDecodeParms());
  223. }
  224. // now build up the filter entries for the dictionary
  225. return buildFilterEntries(names) + buildDecodeParms(parms);
  226. }
  227. return "";
  228. }
  229. private String buildFilterEntries(ArrayList names) {
  230. StringBuffer sb = new StringBuffer();
  231. sb.append("/Filter ");
  232. if (names.size() > 1) {
  233. sb.append("[ ");
  234. }
  235. for (int count = 0; count < names.size(); count++) {
  236. sb.append((String)names.get(count));
  237. sb.append(" ");
  238. }
  239. if (names.size() > 1) {
  240. sb.append("]");
  241. }
  242. sb.append("\n");
  243. return sb.toString();
  244. }
  245. private String buildDecodeParms(ArrayList parms) {
  246. StringBuffer sb = new StringBuffer();
  247. boolean needParmsEntry = false;
  248. sb.append("/DecodeParms ");
  249. if (parms.size() > 1) {
  250. sb.append("[ ");
  251. }
  252. for (int count = 0; count < parms.size(); count++) {
  253. String s = (String)parms.get(count);
  254. if (s != null) {
  255. sb.append(s);
  256. needParmsEntry = true;
  257. } else {
  258. sb.append("null");
  259. }
  260. sb.append(" ");
  261. }
  262. if (parms.size() > 1) {
  263. sb.append("]");
  264. }
  265. sb.append("\n");
  266. if (needParmsEntry) {
  267. return sb.toString();
  268. } else {
  269. return "";
  270. }
  271. }
  272. }