/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* $Id$ */ package org.apache.fop.pdf; // Java import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.Set; import java.util.UUID; /* modified by JKT to integrate with 0.12.0 */ /* modified by Eric SCHAEFFER to integrate with 0.13.0 */ /** * PDF XObject * * A derivative of the PDF Object, is a PDF Stream that has not only a * dictionary but a stream of image data. * The dictionary just provides information like the stream length. * This outputs the image dictionary and the image data. * This is used as a reference for inserting the same image in the * document in another place. */ public class PDFImageXObject extends PDFXObject { private PDFImage pdfimage; /** * create an XObject with the given number and name and load the * image in the object * * @param xnumber the pdf object X number * @param img the pdf image that contains the image data */ public PDFImageXObject(int xnumber, PDFImage img) { super(); put("Name", new PDFName("Im" + xnumber)); pdfimage = img; } /** * Output the image as PDF. * This sets up the image dictionary and adds the image data stream. * * @param stream the output stream to write the data * @throws IOException if there is an error writing the data * @return the length of the data written */ public int output(OutputStream stream) throws IOException { if (getDocument().getProfile().isPDFVTActive()) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); pdfimage.outputContents(baos); put("GTS_XID", "uuid:" + UUID.nameUUIDFromBytes(baos.toByteArray())); } int length = super.output(stream); // let it gc // this object is retained as a reference to inserting // the same image but the image data is no longer needed pdfimage = null; return length; } /** {@inheritDoc} */ protected void populateStreamDict(Object lengthEntry) { super.populateStreamDict(lengthEntry); if (pdfimage.isPS()) { populateDictionaryFromPS(); } else { populateDictionaryFromImage(); } } private void populateDictionaryFromPS() { getDocumentSafely().getProfile().verifyPSXObjectsAllowed(); put("Subtype", new PDFName("PS")); } private void populateDictionaryFromImage() { put("Subtype", new PDFName("Image")); put("Width", pdfimage.getWidth()); put("Height", pdfimage.getHeight()); put("BitsPerComponent", pdfimage.getBitsPerComponent()); PDFICCStream pdfICCStream = pdfimage.getICCStream(); if (pdfICCStream != null) { put("ColorSpace", new PDFArray(this, new Object[] {new PDFName("ICCBased"), pdfICCStream})); } else { PDFDeviceColorSpace cs = pdfimage.getColorSpace(); put("ColorSpace", new PDFName(cs.getName())); } if (pdfimage.isInverted()) { /* PhotoShop generates CMYK values that's inverse, * this will invert the values - too bad if it's not * a PhotoShop image... */ final Float zero = 0.0f; final Float one = 1.0f; PDFArray decode = new PDFArray(this); for (int i = 0, c = pdfimage.getColorSpace().getNumComponents(); i < c; i++) { decode.add(one); decode.add(zero); } put("Decode", decode); } if (pdfimage.isTransparent()) { PDFColor transp = pdfimage.getTransparentColor(); PDFArray mask = new PDFArray(this); if (pdfimage.getColorSpace().isGrayColorSpace()) { mask.add(Integer.valueOf(transp.red255())); mask.add(Integer.valueOf(transp.red255())); } else { mask.add(Integer.valueOf(transp.red255())); mask.add(Integer.valueOf(transp.red255())); mask.add(Integer.valueOf(transp.green255())); mask.add(Integer.valueOf(transp.green255())); mask.add(Integer.valueOf(transp.blue255())); mask.add(Integer.valueOf(transp.blue255())); } put("Mask", mask); } PDFReference ref = pdfimage.getSoftMaskReference(); if (ref != null) { put("SMask", ref); } //Important: do this at the end so previous values can be overwritten. pdfimage.populateXObjectDictionary(getDictionary()); } /** {@inheritDoc} */ protected void outputRawStreamData(OutputStream out) throws IOException { pdfimage.outputContents(out); } /** {@inheritDoc} */ protected int getSizeHint() throws IOException { return 0; } /** {@inheritDoc} */ protected void prepareImplicitFilters() { PDFFilter pdfFilter = pdfimage.getPDFFilter(); if (pdfFilter != null) { getFilterList().ensureFilterInPlace(pdfFilter); } } /** * {@inheritDoc} * This class uses the PDFImage instance to determine the default filter. */ protected String getDefaultFilterName() { return pdfimage.getFilterHint(); } /** {@inheritDoc} */ protected boolean multipleFiltersAllowed() { return pdfimage.multipleFiltersAllowed(); } @Override public void getChildren(Set<PDFObject> children) { super.getChildren(children); PDFICCStream pdfICCStream = pdfimage.getICCStream(); if (pdfICCStream != null) { children.add(pdfICCStream); pdfICCStream.getChildren(children); } } }