/* * 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. */ package org.apache.pdfbox.pdmodel.graphics.color; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSBase; import org.apache.pdfbox.cos.COSInteger; import org.apache.pdfbox.cos.COSFloat; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSNumber; import org.apache.pdfbox.cos.COSStream; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.common.COSArrayList; import org.apache.pdfbox.pdmodel.common.PDRange; import org.apache.pdfbox.pdmodel.common.PDStream; import java.awt.Transparency; import java.awt.color.ColorSpace; import java.awt.color.ICC_ColorSpace; import java.awt.color.ICC_Profile; import java.awt.image.ColorModel; import java.awt.image.ComponentColorModel; import java.awt.image.DataBuffer; import java.io.InputStream; import java.io.IOException; import java.util.ArrayList; import java.util.List; /** * This class represents a ICC profile color space. * * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a> * @version $Revision: 1.6 $ */ public class PDICCBased extends PDColorSpace { /** * The name of this color space. */ public static final String NAME = "ICCBased"; //private COSArray array; private PDStream stream; /** * Default constructor, creates empty stream. * * @param doc The document to store the icc data. */ public PDICCBased( PDDocument doc ) { array = new COSArray(); array.add( COSName.ICCBASED ); array.add( new PDStream( doc ) ); } /** * Constructor. * * @param iccArray The ICC stream object. */ public PDICCBased( COSArray iccArray ) { array = iccArray; stream = new PDStream( (COSStream)iccArray.getObject( 1 ) ); } /** * This will return the name of the color space. * * @return The name of the color space. */ public String getName() { return NAME; } /** * Convert this standard java object to a COS object. * * @return The cos object that matches this Java object. */ public COSBase getCOSObject() { return array; } /** * Get the pd stream for this icc color space. * * @return Get the stream for this icc based color space. */ public PDStream getPDStream() { return stream; } /** * Create a Java colorspace for this colorspace. * * @return A color space that can be used for Java AWT operations. * * @throws IOException If there is an error creating the color space. */ protected ColorSpace createColorSpace() throws IOException { InputStream profile = null; ColorSpace cSpace = null; try { profile = stream.createInputStream(); ICC_Profile iccProfile = ICC_Profile.getInstance( profile ); cSpace = new ICC_ColorSpace( iccProfile ); } finally { if( profile != null ) { profile.close(); } } return cSpace; } /** * Create a Java color model for this colorspace. * * @param bpc The number of bits per component. * * @return A color model that can be used for Java AWT operations. * * @throws IOException If there is an error creating the color model. */ public ColorModel createColorModel( int bpc ) throws IOException { int[] nbBits = { bpc, bpc, bpc, bpc }; //added 4th bpc to handle CMYK ComponentColorModel componentColorModel = new ComponentColorModel( getJavaColorSpace(), nbBits, false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE ); return componentColorModel; } /** * This will return the number of color components. As of PDF 1.4 this will * be 1,3,4. * * @return The number of components in this color space. * * @throws IOException If there is an error getting the number of color components. */ public int getNumberOfComponents() throws IOException { COSNumber n = (COSNumber)stream.getStream().getDictionaryObject( COSName.N ); return n.intValue(); } /** * This will set the number of color components. * * @param n The number of color components. */ public void setNumberOfComponents( int n ) { stream.getStream().setInt( COSName.N, n ); } /** * This will return a list of alternate color spaces(PDColorSpace) if the display application * does not support this icc stream. * * @return A list of alternate color spaces. * * @throws IOException If there is an error getting the alternate color spaces. */ public List getAlternateColorSpaces() throws IOException { COSBase alternate = stream.getStream().getDictionaryObject( COSName.ALTERNATE ); COSArray alternateArray = null; if( alternate == null ) { alternateArray = new COSArray(); int numComponents = getNumberOfComponents(); COSName csName = null; if( numComponents == 1 ) { csName = COSName.DEVICEGRAY; } else if( numComponents == 3 ) { csName = COSName.DEVICERGB; } else if( numComponents == 4 ) { csName = COSName.DEVICECMYK; } else { throw new IOException( "Unknown colorspace number of components:" + numComponents ); } alternateArray.add( csName ); } else { if( alternate instanceof COSArray ) { alternateArray = (COSArray)alternate; } else if( alternate instanceof COSName ) { alternateArray = new COSArray(); alternateArray.add( alternate ); } else { throw new IOException( "Error: expected COSArray or COSName and not " + alternate.getClass().getName() ); } } List retval = new ArrayList(); for( int i=0; i<alternateArray.size(); i++ ) { retval.add( PDColorSpaceFactory.createColorSpace( alternateArray.get( i ) ) ); } return new COSArrayList( retval, alternateArray ); } /** * This will set the list of alternate color spaces. This should be a list * of PDColorSpace objects. * * @param list The list of colorspace objects. */ public void setAlternateColorSpaces( List list ) { COSArray altArray = null; if( list != null ) { altArray = COSArrayList.converterToCOSArray( list ); } stream.getStream().setItem( COSName.ALTERNATE, altArray ); } private COSArray getRangeArray( int n ) { COSArray rangeArray = (COSArray)stream.getStream().getDictionaryObject( COSName.RANGE); if( rangeArray == null ) { rangeArray = new COSArray(); stream.getStream().setItem( COSName.RANGE, rangeArray ); while( rangeArray.size() < n*2 ) { rangeArray.add( new COSFloat( -100 ) ); rangeArray.add( new COSFloat( 100 ) ); } } return rangeArray; } /** * This will get the range for a certain component number. This is will never * return null. If it is not present then the range -100 to 100 will * be returned. * * @param n The component number to get the range for. * * @return The range for this component. */ public PDRange getRangeForComponent( int n ) { COSArray rangeArray = getRangeArray( n ); return new PDRange( rangeArray, n ); } /** * This will set the a range for this color space. * * @param range The new range for the a component. * @param n The component to set the range for. */ public void setRangeForComponent( PDRange range, int n ) { COSArray rangeArray = getRangeArray( n ); rangeArray.set( n*2, new COSFloat( range.getMin() ) ); rangeArray.set( n*2+1, new COSFloat( range.getMax() ) ); } /** * This will get the metadata stream for this object. Null if there is no * metadata stream. * * @return The metadata stream, if it exists. */ public COSStream getMetadata() { return (COSStream)stream.getStream().getDictionaryObject( COSName.METADATA ); } /** * This will set the metadata stream that is associated with this color space. * * @param metadata The new metadata stream. */ public void setMetadata( COSStream metadata ) { stream.getStream().setItem( COSName.METADATA, metadata ); } // Need more info on the ICCBased ones ... Array contains very little. /** * {@inheritDoc} */ public String toString() { String retVal = super.toString() + "\n\t Number of Components: "; try { retVal = retVal + getNumberOfComponents(); } catch (IOException exception) { retVal = retVal + exception.toString(); } return retVal; } }