001: /*
002: * Copyright (c) 2007, intarsys consulting GmbH
003: *
004: * Redistribution and use in source and binary forms, with or without
005: * modification, are permitted provided that the following conditions are met:
006: *
007: * - Redistributions of source code must retain the above copyright notice,
008: * this list of conditions and the following disclaimer.
009: *
010: * - 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: *
014: * - Neither the name of intarsys nor the names of its contributors may be used
015: * to endorse or promote products derived from this software without specific
016: * prior written permission.
017: *
018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
020: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
021: * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
022: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
023: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
024: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
025: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
026: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
027: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
028: * POSSIBILITY OF SUCH DAMAGE.
029: */
030: package de.intarsys.pdf.pd;
031:
032: import java.io.IOException;
033:
034: import de.intarsys.pdf.cos.COSArray;
035: import de.intarsys.pdf.cos.COSBasedObject;
036: import de.intarsys.pdf.cos.COSBoolean;
037: import de.intarsys.pdf.cos.COSInteger;
038: import de.intarsys.pdf.cos.COSName;
039: import de.intarsys.pdf.cos.COSNumber;
040: import de.intarsys.pdf.cos.COSObject;
041: import de.intarsys.pdf.cos.COSStream;
042:
043: /**
044: * The representation of an image.
045: */
046: public class PDImage extends PDXObject {
047: /**
048: * The meta class implementation
049: */
050: public static class MetaClass extends PDXObject.MetaClass {
051: protected MetaClass(Class paramInstanceClass) {
052: super (paramInstanceClass);
053: }
054:
055: protected COSBasedObject doCreateCOSBasedObject(COSObject object) {
056: return new PDImage(object);
057: }
058: }
059:
060: /** the valid rendering intents * */
061: public static final String C_RENDERING_VALID1 = "RelativeColorimetric"; //$NON-NLS-1$
062:
063: public static final String C_RENDERING_VALID2 = "AbsoluteColorimetric"; //$NON-NLS-1$
064:
065: public static final String C_RENDERING_VALID3 = "Perceptual"; //$NON-NLS-1$
066:
067: public static final String C_RENDERING_VALID4 = "Saturation"; //$NON-NLS-1$
068:
069: public static final COSName CN_Subtype_Image = COSName
070: .constant("Image"); //$NON-NLS-1$
071:
072: public static final COSName DK_Alternates = COSName
073: .constant("Alternates"); //$NON-NLS-1$
074:
075: public static final COSName DK_BitsPerComponent = COSName
076: .constant("BitsPerComponent"); //$NON-NLS-1$
077:
078: public static final COSName DK_BPC = COSName.constant("BPC"); //$NON-NLS-1$
079:
080: public static final COSName DK_ColorSpace = COSName
081: .constant("ColorSpace"); //$NON-NLS-1$
082:
083: public static final COSName DK_CS = COSName.constant("CS"); //$NON-NLS-1$
084:
085: public static final COSName DK_D = COSName.constant("D"); //$NON-NLS-1$
086:
087: public static final COSName DK_Decode = COSName.constant("Decode"); //$NON-NLS-1$
088:
089: public static final COSName DK_DecodeParms = COSName
090: .constant("DecodeParms"); //$NON-NLS-1$
091:
092: public static final COSName DK_DP = COSName.constant("DP"); //$NON-NLS-1$
093:
094: public static final COSName DK_H = COSName.constant("H"); //$NON-NLS-1$
095:
096: public static final COSName DK_Height = COSName.constant("Height"); //$NON-NLS-1$
097:
098: public static final COSName DK_I = COSName.constant("I"); //$NON-NLS-1$
099:
100: public static final COSName DK_ID = COSName.constant("ID"); //$NON-NLS-1$
101:
102: public static final COSName DK_IM = COSName.constant("IM"); //$NON-NLS-1$
103:
104: public static final COSName DK_ImageMask = COSName
105: .constant("ImageMask"); //$NON-NLS-1$
106:
107: public static final COSName DK_Intent = COSName.constant("Intent"); //$NON-NLS-1$
108:
109: public static final COSName DK_Interpolate = COSName
110: .constant("Interpolate"); //$NON-NLS-1$
111:
112: public static final COSName DK_Mask = COSName.constant("Mask"); //$NON-NLS-1$
113:
114: public static final COSName DK_Metadata = COSName
115: .constant("Metadata"); //$NON-NLS-1$
116:
117: public static final COSName DK_Name = COSName.constant("Name"); //$NON-NLS-1$
118:
119: public static final COSName DK_OC = COSName.constant("OC"); //$NON-NLS-1$
120:
121: public static final COSName DK_OPI = COSName.constant("OPI"); //$NON-NLS-1$
122:
123: public static final COSName DK_SMask = COSName.constant("SMask"); //$NON-NLS-1$
124:
125: public static final COSName DK_SMaskInData = COSName
126: .constant("SMaskInData"); //$NON-NLS-1$
127:
128: public static final COSName DK_StructParent = COSName
129: .constant("StructParent"); //$NON-NLS-1$
130:
131: public static final COSName DK_W = COSName.constant("W"); //$NON-NLS-1$
132:
133: public static final COSName DK_Width = COSName.constant("Width"); //$NON-NLS-1$
134:
135: /** The meta class instance */
136: public static final MetaClass META = new MetaClass(MetaClass.class
137: .getDeclaringClass());
138:
139: private PDColorSpace cachedColorSpace = null;
140:
141: private int cachedHeight = -1;
142:
143: private int cachedIsImageMask = -1;
144:
145: private int cachedIsInterpolate = -1;
146:
147: private int cachedWidth = -1;
148:
149: /**
150: * Create the receiver class from an already defined {@link COSStream}.
151: * NEVER use the constructor directly.
152: *
153: * @param object
154: * the PDDocument containing the new object
155: */
156: protected PDImage(COSObject object) {
157: super (object);
158: }
159:
160: public COSObject cosGetColorSpace() {
161: COSObject object = cosGetField(DK_CS);
162: if (!object.isNull()) {
163: return object;
164: }
165: return cosGetField(DK_ColorSpace);
166: }
167:
168: public COSObject cosGetMask() {
169: return cosGetField(DK_Mask);
170: }
171:
172: public COSStream cosExtractJPEGStream() throws IOException {
173: COSStream cosStream;
174:
175: cosStream = cosGetStream();
176: while (!cosStream.getFirstFilter().stringValue().equals(
177: "DCTDecode") //$NON-NLS-1$
178: && !cosStream.getFirstFilter().stringValue().equals(
179: "DCT") //$NON-NLS-1$
180: && !cosStream.getFirstFilter().stringValue().equals(
181: "JPXDecode")) { //$NON-NLS-1$
182: cosStream = cosStream.copyDecodeFirst();
183: }
184: return cosStream;
185: }
186:
187: /**
188: * The number of bits per component.
189: *
190: * <p>
191: * This information is stored in different attributes depending if the image
192: * is inlined or explicit.
193: * </p>
194: *
195: * @return The number of bits per component.
196: */
197: public int getBitsPerComponent() {
198: COSInteger bpc = cosGetField(DK_BPC).asInteger();
199: if (bpc != null) {
200: return bpc.intValue();
201: }
202: return getFieldInt(DK_BitsPerComponent, 1);
203: }
204:
205: public byte[][] getColorKeyMask(int colors) {
206: COSArray colorKeyMask;
207: byte[][] bytes;
208:
209: colorKeyMask = cosGetMask().asArray();
210: if (colorKeyMask == null) {
211: return null;
212: }
213:
214: bytes = new byte[colorKeyMask.size() / colors][colors];
215: for (int keyIndex = 0; keyIndex < bytes.length; keyIndex++) {
216: for (int colorIndex = 0; colorIndex < colors; colorIndex++) {
217: bytes[keyIndex][colorIndex] = (byte) ((COSNumber) colorKeyMask
218: .get((keyIndex * colors) + colorIndex))
219: .intValue();
220: }
221: }
222: return bytes;
223: }
224:
225: /**
226: * The color space used by the image.
227: *
228: * <p>
229: * Color space information is stored in different attributes in inlined and
230: * explicit images.
231: * </p>
232: *
233: * @return The color space used by the image.
234: */
235: public PDColorSpace getColorSpace() {
236: if (cachedColorSpace == null) {
237: COSObject object = cosGetField(DK_CS);
238: if (!object.isNull()) {
239: cachedColorSpace = (PDColorSpace) PDColorSpace.META
240: .createFromCos(object);
241: } else {
242: cachedColorSpace = (PDColorSpace) PDColorSpace.META
243: .createFromCos(cosGetField(DK_ColorSpace));
244: }
245: if ((cachedColorSpace == null) && isImageMask()) {
246: cachedColorSpace = PDCSDeviceGray.SINGLETON;
247: }
248: }
249: return cachedColorSpace;
250: }
251:
252: public int[] getDecode() {
253: COSArray cosArray;
254: int[] decode;
255:
256: cosArray = cosGetField(DK_Decode).asArray();
257: if (cosArray == null) {
258: cosArray = cosGetField(DK_D).asArray();
259: }
260: if (cosArray == null) {
261: return null;
262: }
263: decode = new int[cosArray.size()];
264: for (int index = 0; index < decode.length; index++) {
265: decode[index] = cosArray.get(index).asNumber().intValue();
266: }
267: return decode;
268: }
269:
270: /**
271: * get the height of the raster image
272: *
273: * @return the height
274: */
275: public int getHeight() {
276: if (cachedHeight == -1) {
277: cachedHeight = getFieldInt(DK_Height, -1);
278: if (cachedHeight == -1) {
279: cachedHeight = getFieldInt(DK_H, 0);
280: }
281: }
282: return cachedHeight;
283: }
284:
285: public PDImage getMaskImage() {
286: COSObject mask;
287:
288: mask = cosGetMask();
289: if (mask.isNull()) {
290: return null;
291: }
292:
293: try {
294: return (PDImage) PDXObject.META.createFromCos(mask);
295: } catch (ClassCastException ex) {
296: return null;
297: }
298: }
299:
300: public PDXObject getSMask() {
301: return (PDXObject) PDXObject.META
302: .createFromCos(cosGetField(DK_SMask));
303: }
304:
305: /*
306: * (non-Javadoc)
307: *
308: * @see de.intarsys.pdf.pd.PDObject#cosGetExpectedSubtype()
309: */
310: protected COSName cosGetExpectedSubtype() {
311: return CN_Subtype_Image;
312: }
313:
314: /**
315: * get the width of the raster image
316: *
317: * @return the width
318: */
319: public int getWidth() {
320: if (cachedWidth == -1) {
321: cachedWidth = getFieldInt(DK_Width, -1);
322: if (cachedWidth == -1) {
323: cachedWidth = getFieldInt(DK_W, 0);
324: }
325: }
326: return cachedWidth;
327: }
328:
329: public boolean hasTransparency() {
330: return !cosGetMask().isNull() || (getSMask() != null);
331: }
332:
333: public void invalidateCaches() {
334: super .invalidateCaches();
335: cachedColorSpace = null;
336: cachedHeight = -1;
337: cachedWidth = -1;
338: }
339:
340: public boolean isImage() {
341: return true;
342: }
343:
344: public boolean isImageMask() {
345: if (cachedIsImageMask == -1) {
346: COSBoolean result = cosGetField(DK_ImageMask).asBoolean();
347: if (result == null) {
348: result = cosGetField(DK_IM).asBoolean();
349: }
350: if ((result != null) && result.booleanValue()) {
351: cachedIsImageMask = 1;
352: } else {
353: cachedIsImageMask = 0;
354: }
355: }
356: return cachedIsImageMask == 1;
357: }
358:
359: /**
360: * @return interpolation flag (used if a image is scaled)
361: */
362: public boolean isInterpolate() {
363: if (cachedIsInterpolate == -1) {
364: if (getFieldBoolean(DK_Interpolate, false)) {
365: cachedIsInterpolate = 1;
366: } else {
367: cachedIsInterpolate = 0;
368: }
369: }
370: return cachedIsInterpolate == 1;
371: }
372:
373: public void setBitsPerComponent(int bits) {
374: setFieldInt(DK_BitsPerComponent, bits);
375: }
376:
377: /**
378: * In inline images the color space may reference the resource dictionary.
379: * In this case the color space is resolved and assigned externaly.
380: *
381: * @param paramCachedColorSpace
382: * The color space to use.
383: */
384: public void setColorSpace(PDColorSpace paramCachedColorSpace) {
385: // todo 1 review usage, EI
386: cachedColorSpace = paramCachedColorSpace;
387: }
388:
389: public COSArray cosSetColorSpace(COSArray colorspace) {
390: return cosSetField(DK_ColorSpace, colorspace).asArray();
391: }
392:
393: public COSName cosSetColorSpace(COSName colorspace) {
394: return cosSetField(DK_ColorSpace, colorspace).asName();
395: }
396:
397: public void setDecode(int[] decode) {
398: COSArray cosArray;
399:
400: cosArray = COSArray.create(decode.length);
401: for (int index = 0; index < decode.length; index++) {
402: cosArray.add(COSInteger.create(decode[index]));
403: }
404: cosSetField(DK_Decode, cosArray);
405: }
406:
407: /**
408: * set the height of the raster image
409: *
410: * @param height
411: * the height of the raster image
412: */
413: public void setHeight(int height) {
414: setFieldInt(DK_Height, height);
415: }
416:
417: public void setImageMask(boolean flag) {
418: setFieldBoolean(DK_ImageMask, flag);
419: }
420:
421: public void setMask(PDXObject object) {
422: setFieldObject(DK_Mask, object);
423: }
424:
425: public void setSMask(PDXObject object) {
426: setFieldObject(DK_SMask, object);
427: }
428:
429: /**
430: * set the width of the raster image
431: *
432: * @param width
433: * the width of the raster image
434: */
435: public void setWidth(int width) {
436: setFieldInt(DK_Width, width);
437: }
438: }
|