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 18 /* $Id: PDFImageXObject.java 1758773 2016-09-01 13:02:29Z ssteiner $ */ 19 20 package org.apache.fop.pdf; 21 22 // Java 23 import java.io.ByteArrayOutputStream; 24 import java.io.IOException; 25 import java.io.OutputStream; 26 import java.util.Set; 27 import java.util.UUID; 28 29 /* modified by JKT to integrate with 0.12.0 */ 30 /* modified by Eric SCHAEFFER to integrate with 0.13.0 */ 31 32 /** 33 * PDF XObject 34 * 35 * A derivative of the PDF Object, is a PDF Stream that has not only a 36 * dictionary but a stream of image data. 37 * The dictionary just provides information like the stream length. 38 * This outputs the image dictionary and the image data. 39 * This is used as a reference for inserting the same image in the 40 * document in another place. 41 */ 42 public class PDFImageXObject extends PDFXObject { 43 44 private PDFImage pdfimage; 45 46 /** 47 * create an XObject with the given number and name and load the 48 * image in the object 49 * 50 * @param xnumber the pdf object X number 51 * @param img the pdf image that contains the image data 52 */ PDFImageXObject(int xnumber, PDFImage img)53 public PDFImageXObject(int xnumber, PDFImage img) { 54 super(); 55 put("Name", new PDFName("Im" + xnumber)); 56 pdfimage = img; 57 } 58 59 /** 60 * Output the image as PDF. 61 * This sets up the image dictionary and adds the image data stream. 62 * 63 * @param stream the output stream to write the data 64 * @throws IOException if there is an error writing the data 65 * @return the length of the data written 66 */ output(OutputStream stream)67 public int output(OutputStream stream) throws IOException { 68 if (getDocument().getProfile().isPDFVTActive()) { 69 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 70 pdfimage.outputContents(baos); 71 put("GTS_XID", "uuid:" + UUID.nameUUIDFromBytes(baos.toByteArray())); 72 } 73 int length = super.output(stream); 74 75 // let it gc 76 // this object is retained as a reference to inserting 77 // the same image but the image data is no longer needed 78 pdfimage = null; 79 return length; 80 } 81 82 /** {@inheritDoc} */ populateStreamDict(Object lengthEntry)83 protected void populateStreamDict(Object lengthEntry) { 84 super.populateStreamDict(lengthEntry); 85 if (pdfimage.isPS()) { 86 populateDictionaryFromPS(); 87 } else { 88 populateDictionaryFromImage(); 89 } 90 } 91 populateDictionaryFromPS()92 private void populateDictionaryFromPS() { 93 getDocumentSafely().getProfile().verifyPSXObjectsAllowed(); 94 put("Subtype", new PDFName("PS")); 95 } 96 populateDictionaryFromImage()97 private void populateDictionaryFromImage() { 98 put("Subtype", new PDFName("Image")); 99 put("Width", pdfimage.getWidth()); 100 put("Height", pdfimage.getHeight()); 101 put("BitsPerComponent", pdfimage.getBitsPerComponent()); 102 103 PDFICCStream pdfICCStream = pdfimage.getICCStream(); 104 if (pdfICCStream != null) { 105 put("ColorSpace", new PDFArray(this, 106 new Object[] {new PDFName("ICCBased"), pdfICCStream})); 107 } else { 108 PDFDeviceColorSpace cs = pdfimage.getColorSpace(); 109 put("ColorSpace", new PDFName(cs.getName())); 110 } 111 112 if (pdfimage.isInverted()) { 113 /* PhotoShop generates CMYK values that's inverse, 114 * this will invert the values - too bad if it's not 115 * a PhotoShop image... 116 */ 117 final Float zero = 0.0f; 118 final Float one = 1.0f; 119 PDFArray decode = new PDFArray(this); 120 for (int i = 0, c = pdfimage.getColorSpace().getNumComponents(); i < c; i++) { 121 decode.add(one); 122 decode.add(zero); 123 } 124 put("Decode", decode); 125 } 126 127 if (pdfimage.isTransparent()) { 128 PDFColor transp = pdfimage.getTransparentColor(); 129 PDFArray mask = new PDFArray(this); 130 if (pdfimage.getColorSpace().isGrayColorSpace()) { 131 mask.add(Integer.valueOf(transp.red255())); 132 mask.add(Integer.valueOf(transp.red255())); 133 } else { 134 mask.add(Integer.valueOf(transp.red255())); 135 mask.add(Integer.valueOf(transp.red255())); 136 mask.add(Integer.valueOf(transp.green255())); 137 mask.add(Integer.valueOf(transp.green255())); 138 mask.add(Integer.valueOf(transp.blue255())); 139 mask.add(Integer.valueOf(transp.blue255())); 140 } 141 put("Mask", mask); 142 } 143 PDFReference ref = pdfimage.getSoftMaskReference(); 144 if (ref != null) { 145 put("SMask", ref); 146 } 147 //Important: do this at the end so previous values can be overwritten. 148 pdfimage.populateXObjectDictionary(getDictionary()); 149 } 150 151 /** {@inheritDoc} */ outputRawStreamData(OutputStream out)152 protected void outputRawStreamData(OutputStream out) throws IOException { 153 pdfimage.outputContents(out); 154 } 155 156 /** {@inheritDoc} */ getSizeHint()157 protected int getSizeHint() throws IOException { 158 return 0; 159 } 160 161 /** {@inheritDoc} */ prepareImplicitFilters()162 protected void prepareImplicitFilters() { 163 PDFFilter pdfFilter = pdfimage.getPDFFilter(); 164 if (pdfFilter != null) { 165 getFilterList().ensureFilterInPlace(pdfFilter); 166 } 167 } 168 169 /** 170 * {@inheritDoc} 171 * This class uses the PDFImage instance to determine the default filter. 172 */ getDefaultFilterName()173 protected String getDefaultFilterName() { 174 return pdfimage.getFilterHint(); 175 } 176 177 /** {@inheritDoc} */ multipleFiltersAllowed()178 protected boolean multipleFiltersAllowed() { 179 return pdfimage.multipleFiltersAllowed(); 180 } 181 182 @Override getChildren(Set<PDFObject> children)183 public void getChildren(Set<PDFObject> children) { 184 super.getChildren(children); 185 PDFICCStream pdfICCStream = pdfimage.getICCStream(); 186 if (pdfICCStream != null) { 187 children.add(pdfICCStream); 188 pdfICCStream.getChildren(children); 189 } 190 } 191 192 } 193