001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: /**
018: * @author Oleg V. Khaschansky
019: * @version $Revision$
020: */package java.awt.color;
021:
022: import java.io.File;
023: import java.io.FileInputStream;
024: import java.io.FileNotFoundException;
025: import java.io.FileOutputStream;
026: import java.io.IOException;
027: import java.io.InputStream;
028: import java.io.ObjectInputStream;
029: import java.io.ObjectOutputStream;
030: import java.io.ObjectStreamException;
031: import java.io.OutputStream;
032: import java.io.Serializable;
033: import java.security.AccessController;
034: import java.security.PrivilegedAction;
035: import java.util.StringTokenizer;
036:
037: import org.apache.harmony.awt.gl.color.ICC_ProfileHelper;
038: import org.apache.harmony.awt.gl.color.NativeCMM;
039: import org.apache.harmony.awt.internal.nls.Messages;
040:
041: public class ICC_Profile implements Serializable {
042:
043: private static final long serialVersionUID = -3938515861990936766L;
044:
045: // NOTE: Constant field values are noted in 1.5 specification.
046:
047: public static final int CLASS_INPUT = 0;
048:
049: public static final int CLASS_DISPLAY = 1;
050:
051: public static final int CLASS_OUTPUT = 2;
052:
053: public static final int CLASS_DEVICELINK = 3;
054:
055: public static final int CLASS_COLORSPACECONVERSION = 4;
056:
057: public static final int CLASS_ABSTRACT = 5;
058:
059: public static final int CLASS_NAMEDCOLOR = 6;
060:
061: public static final int icSigXYZData = 1482250784;
062:
063: public static final int icSigLabData = 1281450528;
064:
065: public static final int icSigLuvData = 1282766368;
066:
067: public static final int icSigYCbCrData = 1497588338;
068:
069: public static final int icSigYxyData = 1501067552;
070:
071: public static final int icSigRgbData = 1380401696;
072:
073: public static final int icSigGrayData = 1196573017;
074:
075: public static final int icSigHsvData = 1213421088;
076:
077: public static final int icSigHlsData = 1212961568;
078:
079: public static final int icSigCmykData = 1129142603;
080:
081: public static final int icSigCmyData = 1129142560;
082:
083: public static final int icSigSpace2CLR = 843271250;
084:
085: public static final int icSigSpace3CLR = 860048466;
086:
087: public static final int icSigSpace4CLR = 876825682;
088:
089: public static final int icSigSpace5CLR = 893602898;
090:
091: public static final int icSigSpace6CLR = 910380114;
092:
093: public static final int icSigSpace7CLR = 927157330;
094:
095: public static final int icSigSpace8CLR = 943934546;
096:
097: public static final int icSigSpace9CLR = 960711762;
098:
099: public static final int icSigSpaceACLR = 1094929490;
100:
101: public static final int icSigSpaceBCLR = 1111706706;
102:
103: public static final int icSigSpaceCCLR = 1128483922;
104:
105: public static final int icSigSpaceDCLR = 1145261138;
106:
107: public static final int icSigSpaceECLR = 1162038354;
108:
109: public static final int icSigSpaceFCLR = 1178815570;
110:
111: public static final int icSigInputClass = 1935896178;
112:
113: public static final int icSigDisplayClass = 1835955314;
114:
115: public static final int icSigOutputClass = 1886549106;
116:
117: public static final int icSigLinkClass = 1818848875;
118:
119: public static final int icSigAbstractClass = 1633842036;
120:
121: public static final int icSigColorantOrderTag = 1668051567;
122:
123: public static final int icSigColorantTableTag = 1668051572;
124:
125: public static final int icSigColorSpaceClass = 1936744803;
126:
127: public static final int icSigNamedColorClass = 1852662636;
128:
129: public static final int icPerceptual = 0;
130:
131: public static final int icRelativeColorimetric = 1;
132:
133: public static final int icSaturation = 2;
134:
135: public static final int icAbsoluteColorimetric = 3;
136:
137: public static final int icSigHead = 1751474532;
138:
139: public static final int icSigAToB0Tag = 1093812784;
140:
141: public static final int icSigAToB1Tag = 1093812785;
142:
143: public static final int icSigAToB2Tag = 1093812786;
144:
145: public static final int icSigBlueColorantTag = 1649957210;
146:
147: public static final int icSigBlueMatrixColumnTag = 1649957210;
148:
149: public static final int icSigBlueTRCTag = 1649693251;
150:
151: public static final int icSigBToA0Tag = 1110589744;
152:
153: public static final int icSigBToA1Tag = 1110589745;
154:
155: public static final int icSigBToA2Tag = 1110589746;
156:
157: public static final int icSigCalibrationDateTimeTag = 1667329140;
158:
159: public static final int icSigCharTargetTag = 1952543335;
160:
161: public static final int icSigCopyrightTag = 1668313716;
162:
163: public static final int icSigCrdInfoTag = 1668441193;
164:
165: public static final int icSigDeviceMfgDescTag = 1684893284;
166:
167: public static final int icSigDeviceModelDescTag = 1684890724;
168:
169: public static final int icSigDeviceSettingsTag = 1684371059;
170:
171: public static final int icSigGamutTag = 1734438260;
172:
173: public static final int icSigGrayTRCTag = 1800688195;
174:
175: public static final int icSigGreenColorantTag = 1733843290;
176:
177: public static final int icSigGreenMatrixColumnTag = 1733843290;
178:
179: public static final int icSigGreenTRCTag = 1733579331;
180:
181: public static final int icSigLuminanceTag = 1819635049;
182:
183: public static final int icSigMeasurementTag = 1835360627;
184:
185: public static final int icSigMediaBlackPointTag = 1651208308;
186:
187: public static final int icSigMediaWhitePointTag = 2004119668;
188:
189: public static final int icSigNamedColor2Tag = 1852009522;
190:
191: public static final int icSigOutputResponseTag = 1919251312;
192:
193: public static final int icSigPreview0Tag = 1886545200;
194:
195: public static final int icSigPreview1Tag = 1886545201;
196:
197: public static final int icSigPreview2Tag = 1886545202;
198:
199: public static final int icSigProfileDescriptionTag = 1684370275;
200:
201: public static final int icSigProfileSequenceDescTag = 1886610801;
202:
203: public static final int icSigPs2CRD0Tag = 1886610480;
204:
205: public static final int icSigPs2CRD1Tag = 1886610481;
206:
207: public static final int icSigPs2CRD2Tag = 1886610482;
208:
209: public static final int icSigPs2CRD3Tag = 1886610483;
210:
211: public static final int icSigPs2CSATag = 1886597747;
212:
213: public static final int icSigPs2RenderingIntentTag = 1886597737;
214:
215: public static final int icSigRedColorantTag = 1918392666;
216:
217: public static final int icSigRedMatrixColumnTag = 1918392666;
218:
219: public static final int icSigRedTRCTag = 1918128707;
220:
221: public static final int icSigScreeningDescTag = 1935897188;
222:
223: public static final int icSigScreeningTag = 1935897198;
224:
225: public static final int icSigTechnologyTag = 1952801640;
226:
227: public static final int icSigUcrBgTag = 1650877472;
228:
229: public static final int icSigViewingCondDescTag = 1987405156;
230:
231: public static final int icSigViewingConditionsTag = 1986618743;
232:
233: public static final int icSigChromaticAdaptationTag = 1667785060;
234:
235: public static final int icSigChromaticityTag = 1667789421;
236:
237: public static final int icHdrSize = 0;
238:
239: public static final int icHdrCmmId = 4;
240:
241: public static final int icHdrVersion = 8;
242:
243: public static final int icHdrDeviceClass = 12;
244:
245: public static final int icHdrColorSpace = 16;
246:
247: public static final int icHdrPcs = 20;
248:
249: public static final int icHdrDate = 24;
250:
251: public static final int icHdrMagic = 36;
252:
253: public static final int icHdrPlatform = 40;
254:
255: public static final int icHdrProfileID = 84;
256:
257: public static final int icHdrFlags = 44;
258:
259: public static final int icHdrManufacturer = 48;
260:
261: public static final int icHdrModel = 52;
262:
263: public static final int icHdrAttributes = 56;
264:
265: public static final int icHdrRenderingIntent = 64;
266:
267: public static final int icHdrIlluminant = 68;
268:
269: public static final int icHdrCreator = 80;
270:
271: public static final int icICCAbsoluteColorimetric = 3;
272:
273: public static final int icMediaRelativeColorimetric = 1;
274:
275: public static final int icTagType = 0;
276:
277: public static final int icTagReserved = 4;
278:
279: public static final int icCurveCount = 8;
280:
281: public static final int icCurveData = 12;
282:
283: public static final int icXYZNumberX = 8;
284:
285: /**
286: * Size of a profile header
287: */
288: private static final int headerSize = 128;
289:
290: /**
291: * header magic number
292: */
293: private static final int headerMagicNumber = 0x61637370;
294:
295: // Cache of predefined profiles
296: private static ICC_Profile sRGBProfile;
297: private static ICC_Profile xyzProfile;
298: private static ICC_Profile grayProfile;
299: private static ICC_Profile pyccProfile;
300: private static ICC_Profile linearRGBProfile;
301:
302: /**
303: * Handle to the current profile
304: */
305: private transient long profileHandle = 0;
306:
307: /**
308: * If handle is used by another class
309: * this object is not responsible for closing profile
310: */
311: private transient boolean handleStolen = false;
312:
313: /**
314: * Cached header data
315: */
316: private transient byte[] headerData = null;
317:
318: /**
319: * Serialization support
320: */
321: private transient ICC_Profile openedProfileObject;
322:
323: private ICC_Profile(byte[] data) {
324: profileHandle = NativeCMM.cmmOpenProfile(data);
325: NativeCMM.addHandle(this , profileHandle);
326: }
327:
328: /**
329: * Used to instantiate dummy ICC_ProfileStub objects
330: */
331: ICC_Profile() {
332: }
333:
334: /**
335: * Used to instantiate subclasses (ICC_ProfileGrey and ICC_ProfileRGB)
336: *
337: * @param profileHandle - should be valid handle to opened color profile
338: */
339: ICC_Profile(long profileHandle) {
340: this .profileHandle = profileHandle;
341: // A new object reference, need to add it.
342: NativeCMM.addHandle(this , profileHandle);
343: }
344:
345: public void write(String fileName) throws IOException {
346: FileOutputStream oStream = new FileOutputStream(fileName);
347: oStream.write(getData());
348: oStream.close();
349: }
350:
351: /**
352: * Serializable implementation
353: * @param s
354: * @throws IOException
355: */
356: private void writeObject(ObjectOutputStream s) throws IOException {
357: s.defaultWriteObject();
358: s.writeObject(null);
359: s.writeObject(getData());
360: }
361:
362: /**
363: * Serializable implementation
364: * @param s
365: * @throws IOException
366: * @throws ClassNotFoundException
367: */
368: private void readObject(ObjectInputStream s) throws IOException,
369: ClassNotFoundException {
370: s.defaultReadObject();
371: String colorSpaceStr = (String) s.readObject();
372: byte[] data = (byte[]) s.readObject();
373:
374: if (colorSpaceStr != null) {
375: if (colorSpaceStr.equals("CS_sRGB")) { //$NON-NLS-1$
376: openedProfileObject = getInstance(ColorSpace.CS_sRGB);
377: } else if (colorSpaceStr.equals("CS_GRAY")) { //$NON-NLS-1$
378: openedProfileObject = getInstance(ColorSpace.CS_GRAY);
379: } else if (colorSpaceStr.equals("CS_LINEAR_RGB")) { //$NON-NLS-1$
380: openedProfileObject = getInstance(ColorSpace.CS_LINEAR_RGB);
381: } else if (colorSpaceStr.equals("CS_CIEXYZ")) { //$NON-NLS-1$
382: openedProfileObject = getInstance(ColorSpace.CS_CIEXYZ);
383: } else if (colorSpaceStr.equals("CS_PYCC")) { //$NON-NLS-1$
384: openedProfileObject = getInstance(ColorSpace.CS_PYCC);
385: } else {
386: openedProfileObject = ICC_Profile.getInstance(data);
387: }
388: } else {
389: openedProfileObject = ICC_Profile.getInstance(data);
390: }
391: }
392:
393: protected Object readResolve() throws ObjectStreamException {
394: return openedProfileObject;
395: }
396:
397: public void write(OutputStream s) throws IOException {
398: s.write(getData());
399: }
400:
401: public void setData(int tagSignature, byte[] tagData) {
402: NativeCMM.cmmSetProfileElement(profileHandle, tagSignature,
403: tagData);
404: // Remove cached header data if header is modified
405: if (tagSignature == icSigHead) {
406: headerData = null;
407: }
408: }
409:
410: public byte[] getData(int tagSignature) {
411: int tagSize = 0;
412: try {
413: tagSize = NativeCMM.cmmGetProfileElementSize(profileHandle,
414: tagSignature);
415: } catch (CMMException e) {
416: // We'll get this exception if there's no element with
417: // the specified tag signature
418: return null;
419: }
420:
421: byte[] data = new byte[tagSize];
422: NativeCMM.cmmGetProfileElement(profileHandle, tagSignature,
423: data);
424: return data;
425: }
426:
427: public byte[] getData() {
428: int profileSize = NativeCMM.cmmGetProfileSize(profileHandle);
429: byte[] data = new byte[profileSize];
430: NativeCMM.cmmGetProfile(profileHandle, data);
431: return data;
432: }
433:
434: @Override
435: protected void finalize() {
436: if (profileHandle != 0 && !handleStolen) {
437: NativeCMM.cmmCloseProfile(profileHandle);
438: }
439:
440: // Always remove because key no more exist
441: // when object is destroyed
442: NativeCMM.removeHandle(this );
443: }
444:
445: public int getProfileClass() {
446: int deviceClassSignature = getIntFromHeader(icHdrDeviceClass);
447:
448: switch (deviceClassSignature) {
449: case icSigColorSpaceClass:
450: return CLASS_COLORSPACECONVERSION;
451: case icSigDisplayClass:
452: return CLASS_DISPLAY;
453: case icSigOutputClass:
454: return CLASS_OUTPUT;
455: case icSigInputClass:
456: return CLASS_INPUT;
457: case icSigLinkClass:
458: return CLASS_DEVICELINK;
459: case icSigAbstractClass:
460: return CLASS_ABSTRACT;
461: case icSigNamedColorClass:
462: return CLASS_NAMEDCOLOR;
463: default:
464: }
465:
466: // Not an ICC profile class
467: // awt.15F=Profile class does not comply with ICC specification
468: throw new IllegalArgumentException(Messages
469: .getString("awt.15F")); //$NON-NLS-1$
470:
471: }
472:
473: public int getPCSType() {
474: return csFromSignature(getIntFromHeader(icHdrPcs));
475: }
476:
477: public int getNumComponents() {
478: switch (getIntFromHeader(icHdrColorSpace)) {
479: // The most common cases go first to increase speed
480: case icSigRgbData:
481: case icSigXYZData:
482: case icSigLabData:
483: return 3;
484: case icSigCmykData:
485: return 4;
486: // Then all other
487: case icSigGrayData:
488: return 1;
489: case icSigSpace2CLR:
490: return 2;
491: case icSigYCbCrData:
492: case icSigLuvData:
493: case icSigYxyData:
494: case icSigHlsData:
495: case icSigHsvData:
496: case icSigCmyData:
497: case icSigSpace3CLR:
498: return 3;
499: case icSigSpace4CLR:
500: return 4;
501: case icSigSpace5CLR:
502: return 5;
503: case icSigSpace6CLR:
504: return 6;
505: case icSigSpace7CLR:
506: return 7;
507: case icSigSpace8CLR:
508: return 8;
509: case icSigSpace9CLR:
510: return 9;
511: case icSigSpaceACLR:
512: return 10;
513: case icSigSpaceBCLR:
514: return 11;
515: case icSigSpaceCCLR:
516: return 12;
517: case icSigSpaceDCLR:
518: return 13;
519: case icSigSpaceECLR:
520: return 14;
521: case icSigSpaceFCLR:
522: return 15;
523: default:
524: }
525:
526: // awt.160=Color space doesn't comply with ICC specification
527: throw new ProfileDataException(Messages.getString("awt.160") //$NON-NLS-1$
528: );
529: }
530:
531: public int getMinorVersion() {
532: return getByteFromHeader(icHdrVersion + 1);
533: }
534:
535: public int getMajorVersion() {
536: return getByteFromHeader(icHdrVersion);
537: }
538:
539: public int getColorSpaceType() {
540: return csFromSignature(getIntFromHeader(icHdrColorSpace));
541: }
542:
543: /**
544: * Tries to open file at the specified path. Path entries can be divided by separator char
545: *
546: * @param path
547: * @param fileName
548: * @return
549: */
550: private static FileInputStream tryPath(String path, String fileName) {
551: FileInputStream fiStream = null;
552:
553: if (path == null) {
554: return null;
555: }
556:
557: StringTokenizer st = new StringTokenizer(path,
558: File.pathSeparator);
559:
560: while (st.hasMoreTokens()) {
561: String pathEntry = st.nextToken();
562: try {
563: fiStream = new FileInputStream(pathEntry
564: + File.separatorChar + fileName);
565: if (fiStream != null) {
566: return fiStream;
567: }
568: } catch (FileNotFoundException e) {
569: }
570: }
571:
572: return fiStream;
573: }
574:
575: public static ICC_Profile getInstance(String fileName)
576: throws IOException {
577: final String fName = fileName; // to use in the privileged block
578:
579: FileInputStream fiStream = AccessController
580: .doPrivileged(new PrivilegedAction<FileInputStream>() {
581: public FileInputStream run() {
582: FileInputStream fiStream = null;
583:
584: // Open absolute path
585: try {
586: fiStream = new FileInputStream(fName);
587: if (fiStream != null) {
588: return fiStream;
589: }
590: } catch (FileNotFoundException e) {
591: }
592:
593: // Check java.iccprofile.path entries
594: fiStream = tryPath(
595: System
596: .getProperty("java.iccprofile.path"), fName); //$NON-NLS-1$
597: if (fiStream != null) {
598: return fiStream;
599: }
600:
601: // Check java.class.path entries
602: fiStream = tryPath(System
603: .getProperty("java.class.path"), fName); //$NON-NLS-1$
604: if (fiStream != null) {
605: return fiStream;
606: }
607:
608: // Check directory with java sample profiles
609: String home = System.getProperty("java.home"); //$NON-NLS-1$
610: if (home != null) {
611: fiStream = tryPath(
612: home
613: + File.separatorChar
614: + "lib" + File.separatorChar + "cmm", fName //$NON-NLS-1$ //$NON-NLS-2$
615: );
616: }
617:
618: return fiStream;
619: }
620: });
621:
622: if (fiStream == null) {
623: // awt.161=Unable to open file {0}
624: throw new IOException(Messages.getString(
625: "awt.161", fileName)); //$NON-NLS-1$
626: }
627:
628: ICC_Profile pf = getInstance(fiStream);
629: fiStream.close();
630: return pf;
631: }
632:
633: public static ICC_Profile getInstance(InputStream s)
634: throws IOException {
635: byte[] header = new byte[headerSize];
636: // awt.162=Invalid ICC Profile Data
637: String invalidDataMessage = Messages.getString("awt.162"); //$NON-NLS-1$
638:
639: // Get header from the input stream
640: if (s.read(header) != headerSize) {
641: throw new IllegalArgumentException(invalidDataMessage);
642: }
643:
644: // Check the profile data for consistency
645: if (ICC_ProfileHelper.getBigEndianFromByteArray(header,
646: icHdrMagic) != headerMagicNumber) {
647: throw new IllegalArgumentException(invalidDataMessage);
648: }
649:
650: // Get profile size from header, create an array for profile data
651: int profileSize = ICC_ProfileHelper.getBigEndianFromByteArray(
652: header, icHdrSize);
653: byte[] profileData = new byte[profileSize];
654:
655: // Copy header into it
656: System.arraycopy(header, 0, profileData, 0, headerSize);
657:
658: // Read the profile itself
659: if (s.read(profileData, headerSize, profileSize - headerSize) != profileSize
660: - headerSize) {
661: throw new IllegalArgumentException(invalidDataMessage);
662: }
663:
664: return getInstance(profileData);
665: }
666:
667: public static ICC_Profile getInstance(byte[] data) {
668: ICC_Profile res = null;
669:
670: try {
671: res = new ICC_Profile(data);
672: } catch (CMMException e) {
673: // awt.162=Invalid ICC Profile Data
674: throw new IllegalArgumentException(Messages
675: .getString("awt.162")); //$NON-NLS-1$
676: }
677:
678: if (System
679: .getProperty("os.name").toLowerCase().indexOf("windows") >= 0) { //$NON-NLS-1$ //$NON-NLS-2$
680: try {
681: if (res.getColorSpaceType() == ColorSpace.TYPE_RGB
682: && res.getDataSize(icSigMediaWhitePointTag) > 0
683: && res.getDataSize(icSigRedColorantTag) > 0
684: && res.getDataSize(icSigGreenColorantTag) > 0
685: && res.getDataSize(icSigBlueColorantTag) > 0
686: && res.getDataSize(icSigRedTRCTag) > 0
687: && res.getDataSize(icSigGreenTRCTag) > 0
688: && res.getDataSize(icSigBlueTRCTag) > 0) {
689: res = new ICC_ProfileRGB(res.getProfileHandle());
690: } else if (res.getColorSpaceType() == ColorSpace.TYPE_GRAY
691: && res.getDataSize(icSigMediaWhitePointTag) > 0
692: && res.getDataSize(icSigGrayTRCTag) > 0) {
693: res = new ICC_ProfileGray(res.getProfileHandle());
694: }
695:
696: } catch (CMMException e) { /* return res in this case */
697: }
698: }
699:
700: return res;
701: }
702:
703: public static ICC_Profile getInstance(int cspace) {
704: try {
705: switch (cspace) {
706:
707: case ColorSpace.CS_sRGB:
708: if (sRGBProfile == null) {
709: sRGBProfile = getInstance("sRGB.pf"); //$NON-NLS-1$
710: }
711: return sRGBProfile;
712:
713: case ColorSpace.CS_CIEXYZ:
714: if (xyzProfile == null) {
715: xyzProfile = getInstance("CIEXYZ.pf"); //$NON-NLS-1$
716: }
717: return xyzProfile;
718:
719: case ColorSpace.CS_GRAY:
720: if (grayProfile == null) {
721: grayProfile = getInstance("GRAY.pf"); //$NON-NLS-1$
722: }
723: return grayProfile;
724:
725: case ColorSpace.CS_PYCC:
726: if (pyccProfile == null) {
727: pyccProfile = getInstance("PYCC.pf"); //$NON-NLS-1$
728: }
729: return pyccProfile;
730:
731: case ColorSpace.CS_LINEAR_RGB:
732: if (linearRGBProfile == null) {
733: linearRGBProfile = getInstance("LINEAR_RGB.pf"); //$NON-NLS-1$
734: }
735: return linearRGBProfile;
736: }
737:
738: } catch (IOException e) {
739: // awt.163=Can't open color profile
740: throw new IllegalArgumentException(Messages
741: .getString("awt.163")); //$NON-NLS-1$
742: }
743:
744: // awt.164=Not a predefined color space
745: throw new IllegalArgumentException(Messages
746: .getString("awt.164")); //$NON-NLS-1$
747: }
748:
749: /**
750: * Reads integer from the profile header at the specified position
751: * @param idx - offset in bytes from the beginning of the header
752: * @return
753: */
754: private int getIntFromHeader(int idx) {
755: if (headerData == null) {
756: headerData = getData(icSigHead);
757: }
758:
759: return ((headerData[idx] & 0xFF) << 24)
760: | ((headerData[idx + 1] & 0xFF) << 16)
761: | ((headerData[idx + 2] & 0xFF) << 8)
762: | ((headerData[idx + 3] & 0xFF));
763: }
764:
765: /**
766: * Reads byte from the profile header at the specified position
767: * @param idx - offset in bytes from the beginning of the header
768: * @return
769: */
770: private byte getByteFromHeader(int idx) {
771: if (headerData == null) {
772: headerData = getData(icSigHead);
773: }
774:
775: return headerData[idx];
776: }
777:
778: /**
779: * Converts ICC color space signature to the java predefined
780: * color space type
781: * @param signature
782: * @return
783: */
784: private int csFromSignature(int signature) {
785: switch (signature) {
786: case icSigRgbData:
787: return ColorSpace.TYPE_RGB;
788: case icSigXYZData:
789: return ColorSpace.TYPE_XYZ;
790: case icSigCmykData:
791: return ColorSpace.TYPE_CMYK;
792: case icSigLabData:
793: return ColorSpace.TYPE_Lab;
794: case icSigGrayData:
795: return ColorSpace.TYPE_GRAY;
796: case icSigHlsData:
797: return ColorSpace.TYPE_HLS;
798: case icSigLuvData:
799: return ColorSpace.TYPE_Luv;
800: case icSigYCbCrData:
801: return ColorSpace.TYPE_YCbCr;
802: case icSigYxyData:
803: return ColorSpace.TYPE_Yxy;
804: case icSigHsvData:
805: return ColorSpace.TYPE_HSV;
806: case icSigCmyData:
807: return ColorSpace.TYPE_CMY;
808: case icSigSpace2CLR:
809: return ColorSpace.TYPE_2CLR;
810: case icSigSpace3CLR:
811: return ColorSpace.TYPE_3CLR;
812: case icSigSpace4CLR:
813: return ColorSpace.TYPE_4CLR;
814: case icSigSpace5CLR:
815: return ColorSpace.TYPE_5CLR;
816: case icSigSpace6CLR:
817: return ColorSpace.TYPE_6CLR;
818: case icSigSpace7CLR:
819: return ColorSpace.TYPE_7CLR;
820: case icSigSpace8CLR:
821: return ColorSpace.TYPE_8CLR;
822: case icSigSpace9CLR:
823: return ColorSpace.TYPE_9CLR;
824: case icSigSpaceACLR:
825: return ColorSpace.TYPE_ACLR;
826: case icSigSpaceBCLR:
827: return ColorSpace.TYPE_BCLR;
828: case icSigSpaceCCLR:
829: return ColorSpace.TYPE_CCLR;
830: case icSigSpaceDCLR:
831: return ColorSpace.TYPE_DCLR;
832: case icSigSpaceECLR:
833: return ColorSpace.TYPE_ECLR;
834: case icSigSpaceFCLR:
835: return ColorSpace.TYPE_FCLR;
836: default:
837: }
838:
839: // awt.165=Color space doesn't comply with ICC specification
840: throw new IllegalArgumentException(Messages
841: .getString("awt.165")); //$NON-NLS-1$
842: }
843:
844: private long getProfileHandle() {
845: handleStolen = true;
846: return profileHandle;
847: }
848:
849: private int getDataSize(int tagSignature) {
850: return NativeCMM.cmmGetProfileElementSize(profileHandle,
851: tagSignature);
852: }
853:
854: /**
855: * Reads XYZ value from the tag data
856: *
857: * @param tagSignature
858: * @return
859: */
860: float[] getXYZValue(int tagSignature) {
861: float[] res = new float[3];
862: byte[] data = getData(tagSignature);
863:
864: // Convert from ICC s15Fixed16Number type
865: // 1 (float) = 0x10000 (s15Fixed16Number),
866: // hence dividing by 0x10000
867: res[0] = ICC_ProfileHelper.getIntFromByteArray(data, 0) / 65536.f;
868: res[1] = ICC_ProfileHelper.getIntFromByteArray(data, 4) / 65536.f;
869: res[2] = ICC_ProfileHelper.getIntFromByteArray(data, 8) / 65536.f;
870:
871: return res;
872: }
873:
874: float[] getMediaWhitePoint() {
875: return getXYZValue(icSigMediaWhitePointTag);
876: }
877:
878: /**
879: * If TRC is not a table returns gamma via return value
880: * and sets dataTRC to null. If TRC is a table returns 0
881: * and fills dataTRC with values.
882: *
883: * @param tagSignature
884: * @param dataTRC
885: * @return - gamma or zero if TRC is a table
886: */
887: private float getGammaOrTRC(int tagSignature, short[] dataTRC) {
888: byte[] data = getData(tagSignature);
889: int trcSize = ICC_ProfileHelper.getIntFromByteArray(data,
890: icCurveCount);
891:
892: dataTRC = null;
893:
894: if (trcSize == 0) {
895: return 1.0f;
896: }
897:
898: if (trcSize == 1) {
899: // Cast from ICC u8Fixed8Number to float
900: return ICC_ProfileHelper.getShortFromByteArray(data,
901: icCurveData) / 256.f;
902: }
903:
904: // TRC is a table
905: dataTRC = new short[trcSize];
906: for (int i = 0, pos = icCurveData; i < trcSize; i++, pos += 2) {
907: dataTRC[i] = ICC_ProfileHelper.getShortFromByteArray(data,
908: pos);
909: }
910: return 0;
911: }
912:
913: float getGamma(int tagSignature) {
914: short[] dataTRC = null;
915: float gamma = getGammaOrTRC(tagSignature, dataTRC);
916:
917: if (dataTRC == null) {
918: return gamma;
919: }
920: // awt.166=TRC is not a simple gamma value.
921: throw new ProfileDataException(Messages.getString("awt.166")); //$NON-NLS-1$
922: }
923:
924: short[] getTRC(int tagSignature) {
925: short[] dataTRC = null;
926: getGammaOrTRC(tagSignature, dataTRC);
927:
928: if (dataTRC == null) {
929: // awt.167=TRC is a gamma value, not a table.
930: throw new ProfileDataException(Messages
931: .getString("awt.167")); //$NON-NLS-1$
932: }
933: return dataTRC;
934: }
935: }
|