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.

PDFXObject.java 9.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  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. /* modified by JKT to integrate with 0.12.0 */
  8. /* modified by Eric SCHAEFFER to integrate with 0.13.0 */
  9. package org.apache.fop.pdf;
  10. // Java
  11. import java.io.IOException;
  12. import java.io.OutputStream;
  13. // FOP
  14. import org.apache.fop.datatypes.ColorSpace;
  15. import org.apache.fop.pdf.PDFDocument;
  16. import org.apache.fop.pdf.PDFICCStream;
  17. import org.apache.fop.image.FopImage;
  18. import org.apache.fop.image.EPSImage;
  19. import org.apache.fop.image.JpegImage;
  20. import org.apache.fop.image.FopImageException;
  21. /**
  22. * PDF XObject
  23. *
  24. * A derivative of the PDF Object, is a PDF Stream that has not only a
  25. * dictionary but a stream of image data.
  26. * the dictionary just provides information like the stream length
  27. */
  28. public class PDFXObject extends PDFObject {
  29. private boolean isPS;
  30. private PDFDocument pdfDoc;
  31. private PDFICCStream pdfICCStream;
  32. FopImage fopimage;
  33. int Xnum;
  34. /**
  35. * create an Xobject with the given number and name and load the
  36. * image in the object
  37. */
  38. public PDFXObject(int number, int Xnumber, FopImage img) {
  39. this(number, Xnumber, img, null);
  40. }
  41. public PDFXObject(int number, int Xnumber, FopImage img, PDFDocument pdfdoc) {
  42. super(number);
  43. isPS = false;
  44. this.Xnum = Xnumber;
  45. if (img == null)
  46. //log.error("FISH");
  47. fopimage = img;
  48. this.pdfDoc = pdfdoc;
  49. pdfICCStream = null;
  50. try {
  51. if (fopimage instanceof JpegImage) {
  52. /* hasICCProfile is not initialized before
  53. the bitmaps is read - should maybe fix this in
  54. the JpegImage instead...
  55. */
  56. fopimage.getBitmaps();
  57. JpegImage jpegimage = (JpegImage)fopimage;
  58. if (jpegimage.getColorSpace().hasICCProfile()) {
  59. pdfICCStream = pdfDoc.makePDFICCStream();
  60. pdfICCStream.setColorSpace(jpegimage.getColorSpace());
  61. pdfICCStream.addDefaultFilters();
  62. }
  63. }
  64. } catch (Exception e) {
  65. //log.error("Error while reading image " +
  66. // fopimage.getURL() +
  67. // ": " + e.getMessage());
  68. }
  69. }
  70. /**
  71. * @return the PDF XObject number
  72. */
  73. public int getXNumber() {
  74. return this.Xnum;
  75. }
  76. /**
  77. * represent as PDF
  78. */
  79. protected int output(OutputStream stream) throws IOException {
  80. int length = 0;
  81. int i = 0;
  82. try {
  83. if (fopimage instanceof EPSImage) {
  84. isPS = true;
  85. EPSImage epsImage = (EPSImage)fopimage;
  86. int[] bbox = epsImage.getBBox();
  87. int bboxw = bbox[2] - bbox[0];
  88. int bboxh = bbox[3] - bbox[1];
  89. // delegate the stream work to PDFStream
  90. PDFStream imgStream = new PDFStream(0);
  91. StringBuffer preamble = new StringBuffer();
  92. preamble.append("%%BeginDocument: " + epsImage.getDocName() + "\n");
  93. preamble.append("userdict begin % Push userdict on dict stack\n");
  94. preamble.append("/PreEPS_state save def\n");
  95. preamble.append("/dict_stack countdictstack def\n");
  96. preamble.append("/ops_count count 1 sub def\n");
  97. preamble.append("/showpage {} def\n");
  98. preamble.append((double)(1f/(double)bboxw) + " " + (double)(1f/(double)bboxh) + " scale\n");
  99. preamble.append(-bbox[0] + " " + (-bbox[1]) + " translate\n");
  100. preamble.append(bbox[0] + " " + bbox[1] + " " + bboxw + " " + bboxh + " rectclip\n");
  101. preamble.append("newpath\n");
  102. StringBuffer post = new StringBuffer();
  103. post.append("%%EndDocument\n");
  104. post.append("count ops_count sub {pop} repeat\n");
  105. post.append("countdictstack dict_stack sub {end} repeat\n");
  106. post.append("PreEPS_state restore\n");
  107. post.append("end % userdict\n");
  108. byte[] preBytes = preamble.toString().getBytes();
  109. byte[] postBytes = post.toString().getBytes();
  110. byte[] imgData = new byte[preBytes.length + postBytes.length + fopimage.getBitmaps().length];
  111. System.arraycopy (preBytes, 0, imgData, 0, preBytes.length);
  112. System.arraycopy (fopimage.getBitmaps(), 0, imgData, preBytes.length, fopimage.getBitmaps().length);
  113. System.arraycopy (postBytes, 0, imgData, preBytes.length + fopimage.getBitmaps().length, postBytes.length);
  114. imgStream.setData(imgData);
  115. imgStream.addDefaultFilters();
  116. String dictEntries = imgStream.applyFilters();
  117. String p = this.number + " " + this.generation + " obj\n";
  118. p = p + "<</Type /XObject\n";
  119. p = p + "/Subtype /PS\n";
  120. p = p + "/Length " + imgStream.getDataLength();
  121. // don't know if it's the good place (other objects can have references to it)
  122. fopimage.close();
  123. p = p + dictEntries;
  124. p = p + ">>\n";
  125. // push the pdf dictionary on the writer
  126. byte[] pdfBytes = p.getBytes();
  127. stream.write(pdfBytes);
  128. length += pdfBytes.length;
  129. // push all the image data on the writer and takes care of length for trailer
  130. length += imgStream.outputStreamData(stream);
  131. pdfBytes = ("endobj\n").getBytes();
  132. stream.write(pdfBytes);
  133. length += pdfBytes.length;
  134. } else {
  135. // delegate the stream work to PDFStream
  136. PDFStream imgStream = new PDFStream(0);
  137. imgStream.setData(fopimage.getBitmaps());
  138. /*
  139. * Added by Eric Dalquist
  140. * If the DCT filter hasn't been added to the object we add it here
  141. */
  142. if (fopimage.getPDFFilter() != null) {
  143. imgStream.addFilter(fopimage.getPDFFilter());
  144. }
  145. imgStream.addDefaultFilters();
  146. String dictEntries = imgStream.applyFilters();
  147. String p = this.number + " " + this.generation + " obj\n";
  148. p = p + "<</Type /XObject\n";
  149. p = p + "/Subtype /Image\n";
  150. p = p + "/Name /Im" + Xnum + "\n";
  151. p = p + "/Length " + imgStream.getDataLength() + "\n";
  152. p = p + "/Width " + fopimage.getWidth() + "\n";
  153. p = p + "/Height " + fopimage.getHeight() + "\n";
  154. p = p + "/BitsPerComponent " + fopimage.getBitsPerPixel() + "\n";
  155. if (pdfICCStream != null ) {
  156. p = p + "/ColorSpace [/ICCBased " + pdfICCStream.referencePDF() + "]\n";
  157. } else {
  158. ColorSpace cs = fopimage.getColorSpace();
  159. p = p + "/ColorSpace /" + cs.getColorSpacePDFString() + "\n";
  160. }
  161. /* PhotoShop generates CMYK values that's inverse,
  162. this will invert the values - too bad if it's not a PhotoShop image...*/
  163. if (fopimage.getColorSpace().getColorSpace() == ColorSpace.DEVICE_CMYK) {
  164. p = p + "/Decode [ 1.0 0.0 1.0 0.0 1.0 0.0 1.1 0.0 ]\n";
  165. }
  166. if (fopimage.isTransparent()) {
  167. PDFColor transp = fopimage.getTransparentColor();
  168. p = p + "/Mask [" + transp.red255() + " " + transp.red255()
  169. + " " + transp.green255() + " " + transp.green255() + " "
  170. + transp.blue255() + " " + transp.blue255() + "]\n";
  171. }
  172. p = p + dictEntries;
  173. p = p + ">>\n";
  174. // don't know if it's the good place (other objects can have references to it)
  175. fopimage.close();
  176. // push the pdf dictionary on the writer
  177. byte[] pdfBytes = p.getBytes();
  178. stream.write(pdfBytes);
  179. length += pdfBytes.length;
  180. // push all the image data on the writer and takes care of length for trailer
  181. length += imgStream.outputStreamData(stream);
  182. pdfBytes = ("endobj\n").getBytes();
  183. stream.write(pdfBytes);
  184. length += pdfBytes.length;
  185. }
  186. } catch (FopImageException imgex) {
  187. //log.error("Error in XObject : "
  188. // + imgex.getMessage());
  189. }
  190. return length;
  191. }
  192. byte[] toPDF() {
  193. return null;
  194. }
  195. }