001: /**
002: * Copyright (c) 2004, www.pdfbox.org
003: * All rights reserved.
004: *
005: * Redistribution and use in source and binary forms, with or without
006: * modification, are permitted provided that the following conditions are met:
007: *
008: * 1. Redistributions of source code must retain the above copyright notice,
009: * this list of conditions and the following disclaimer.
010: * 2. Redistributions in binary form must reproduce the above copyright notice,
011: * this list of conditions and the following disclaimer in the documentation
012: * and/or other materials provided with the distribution.
013: * 3. Neither the name of pdfbox; nor the names of its
014: * contributors may be used to endorse or promote products derived from this
015: * software without specific prior written permission.
016: *
017: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
018: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
019: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
020: * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
021: * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
022: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
023: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
024: * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
025: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
026: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
027: *
028: * http://www.pdfbox.org
029: *
030: */package org.pdfbox.pdmodel.graphics.color;
031:
032: import org.pdfbox.cos.COSArray;
033: import org.pdfbox.cos.COSBase;
034: import org.pdfbox.cos.COSInteger;
035: import org.pdfbox.cos.COSFloat;
036: import org.pdfbox.cos.COSName;
037: import org.pdfbox.cos.COSNumber;
038: import org.pdfbox.cos.COSStream;
039:
040: import org.pdfbox.pdmodel.PDDocument;
041: import org.pdfbox.pdmodel.common.COSArrayList;
042: import org.pdfbox.pdmodel.common.PDRange;
043: import org.pdfbox.pdmodel.common.PDStream;
044:
045: import java.awt.Transparency;
046: import java.awt.color.ColorSpace;
047: import java.awt.color.ICC_ColorSpace;
048: import java.awt.color.ICC_Profile;
049: import java.awt.image.ColorModel;
050: import java.awt.image.ComponentColorModel;
051: import java.awt.image.DataBuffer;
052:
053: import java.io.InputStream;
054: import java.io.IOException;
055:
056: import java.util.ArrayList;
057: import java.util.List;
058:
059: /**
060: * This class represents a ICC profile color space.
061: *
062: * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
063: * @version $Revision: 1.6 $
064: */
065: public class PDICCBased extends PDColorSpace {
066: /**
067: * The name of this color space.
068: */
069: public static final String NAME = "ICCBased";
070:
071: private COSArray array;
072: private PDStream stream;
073:
074: /**
075: * Default constructor, creates empty stream.
076: *
077: * @param doc The document to store the icc data.
078: */
079: public PDICCBased(PDDocument doc) {
080: array = new COSArray();
081: array.add(COSName.getPDFName(NAME));
082: array.add(new PDStream(doc));
083: }
084:
085: /**
086: * Constructor.
087: *
088: * @param iccArray The ICC stream object.
089: */
090: public PDICCBased(COSArray iccArray) {
091: array = iccArray;
092: stream = new PDStream((COSStream) iccArray.getObject(1));
093: }
094:
095: /**
096: * This will return the name of the color space.
097: *
098: * @return The name of the color space.
099: */
100: public String getName() {
101: return NAME;
102: }
103:
104: /**
105: * Convert this standard java object to a COS object.
106: *
107: * @return The cos object that matches this Java object.
108: */
109: public COSBase getCOSObject() {
110: return array;
111: }
112:
113: /**
114: * Get the pd stream for this icc color space.
115: *
116: * @return Get the stream for this icc based color space.
117: */
118: public PDStream getPDStream() {
119: return stream;
120: }
121:
122: /**
123: * Create a Java colorspace for this colorspace.
124: *
125: * @return A color space that can be used for Java AWT operations.
126: *
127: * @throws IOException If there is an error creating the color space.
128: */
129: public ColorSpace createColorSpace() throws IOException {
130: InputStream profile = null;
131: ColorSpace cSpace = null;
132: try {
133: profile = stream.createInputStream();
134: ICC_Profile iccProfile = ICC_Profile.getInstance(profile);
135: cSpace = new ICC_ColorSpace(iccProfile);
136: } finally {
137: if (profile != null) {
138: profile.close();
139: }
140: }
141: return cSpace;
142: }
143:
144: /**
145: * Create a Java color model for this colorspace.
146: *
147: * @param bpc The number of bits per component.
148: *
149: * @return A color model that can be used for Java AWT operations.
150: *
151: * @throws IOException If there is an error creating the color model.
152: */
153: public ColorModel createColorModel(int bpc) throws IOException {
154: int[] nbBits = { bpc, bpc, bpc };
155: ComponentColorModel componentColorModel = new ComponentColorModel(
156: createColorSpace(), nbBits, false, false,
157: Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
158:
159: return componentColorModel;
160: }
161:
162: /**
163: * This will return the number of color components. As of PDF 1.4 this will
164: * be 1,3,4.
165: *
166: * @return The number of components in this color space.
167: *
168: * @throws IOException If there is an error getting the number of color components.
169: */
170: public int getNumberOfComponents() throws IOException {
171: COSNumber n = (COSNumber) stream.getStream()
172: .getDictionaryObject(COSName.getPDFName("N"));
173: return n.intValue();
174: }
175:
176: /**
177: * This will set the number of color components.
178: *
179: * @param n The number of color components.
180: */
181: public void setNumberOfComponents(int n) {
182: stream.getStream().setItem(COSName.getPDFName("N"),
183: new COSInteger(n));
184: }
185:
186: /**
187: * This will return a list of alternate color spaces(PDColorSpace) if the display application
188: * does not support this icc stream.
189: *
190: * @return A list of alternate color spaces.
191: *
192: * @throws IOException If there is an error getting the alternate color spaces.
193: */
194: public List getAlternateColorSpaces() throws IOException {
195: COSBase alternate = stream.getStream().getDictionaryObject(
196: COSName.getPDFName("Alternate"));
197: COSArray alternateArray = null;
198: if (alternate == null) {
199: alternateArray = new COSArray();
200: int numComponents = getNumberOfComponents();
201: String csName = null;
202: if (numComponents == 1) {
203: csName = PDDeviceGray.NAME;
204: } else if (numComponents == 3) {
205: csName = PDDeviceRGB.NAME;
206: } else if (numComponents == 4) {
207: csName = PDDeviceCMYK.NAME;
208: } else {
209: throw new IOException(
210: "Unknown colorspace number of components:"
211: + numComponents);
212: }
213: alternateArray.add(COSName.getPDFName(csName));
214: } else {
215: if (alternate instanceof COSArray) {
216: alternateArray = (COSArray) alternate;
217: } else if (alternate instanceof COSName) {
218: alternateArray = new COSArray();
219: alternateArray.add(alternate);
220: } else {
221: throw new IOException(
222: "Error: expected COSArray or COSName and not "
223: + alternate.getClass().getName());
224: }
225: }
226: List retval = new ArrayList();
227: for (int i = 0; i < alternateArray.size(); i++) {
228: retval.add(PDColorSpaceFactory
229: .createColorSpace(alternateArray.get(i)));
230: }
231: return new COSArrayList(retval, alternateArray);
232: }
233:
234: /**
235: * This will set the list of alternate color spaces. This should be a list
236: * of PDColorSpace objects.
237: *
238: * @param list The list of colorspace objects.
239: */
240: public void setAlternateColorSpaces(List list) {
241: COSArray altArray = null;
242: if (list != null) {
243: altArray = COSArrayList.converterToCOSArray(list);
244: }
245: stream.getStream().setItem(COSName.getPDFName("Alternate"),
246: altArray);
247: }
248:
249: private COSArray getRangeArray(int n) {
250: COSArray rangeArray = (COSArray) stream.getStream()
251: .getDictionaryObject(COSName.getPDFName("Range"));
252: if (rangeArray == null) {
253: rangeArray = new COSArray();
254: stream.getStream().setItem(COSName.getPDFName("Range"),
255: rangeArray);
256: while (rangeArray.size() < n * 2) {
257: rangeArray.add(new COSFloat(-100));
258: rangeArray.add(new COSFloat(100));
259: }
260: }
261: return rangeArray;
262: }
263:
264: /**
265: * This will get the range for a certain component number. This is will never
266: * return null. If it is not present then the range -100 to 100 will
267: * be returned.
268: *
269: * @param n The component number to get the range for.
270: *
271: * @return The range for this component.
272: */
273: public PDRange getRangeForComponent(int n) {
274: COSArray rangeArray = getRangeArray(n);
275: return new PDRange(rangeArray, n);
276: }
277:
278: /**
279: * This will set the a range for this color space.
280: *
281: * @param range The new range for the a component.
282: * @param n The component to set the range for.
283: */
284: public void setRangeForComponent(PDRange range, int n) {
285: COSArray rangeArray = getRangeArray(n);
286: rangeArray.set(n * 2, new COSFloat(range.getMin()));
287: rangeArray.set(n * 2 + 1, new COSFloat(range.getMax()));
288: }
289:
290: /**
291: * This will get the metadata stream for this object. Null if there is no
292: * metadata stream.
293: *
294: * @return The metadata stream, if it exists.
295: */
296: public COSStream getMetadata() {
297: return (COSStream) stream.getStream().getDictionaryObject(
298: COSName.getPDFName("Metadata"));
299: }
300:
301: /**
302: * This will set the metadata stream that is associated with this color space.
303: *
304: * @param metadata The new metadata stream.
305: */
306: public void setMetadata(COSStream metadata) {
307: stream.getStream().setItem(COSName.getPDFName("Metadata"),
308: metadata);
309: }
310: }
|