001/* 002 * $RCSfile: FileFormatReader.java,v $ 003 * $Revision: 1.2 $ 004 * $Date: 2005/04/28 01:25:38 $ 005 * $State: Exp $ 006 * 007 * Class: FileFormatReader 008 * 009 * Description: Read J2K file stream 010 * 011 * COPYRIGHT: 012 * 013 * This software module was originally developed by Raphaël Grosbois and 014 * Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel 015 * Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David 016 * Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research 017 * Centre France S.A) in the course of development of the JPEG2000 018 * standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This 019 * software module is an implementation of a part of the JPEG 2000 020 * Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio 021 * Systems AB and Canon Research Centre France S.A (collectively JJ2000 022 * Partners) agree not to assert against ISO/IEC and users of the JPEG 023 * 2000 Standard (Users) any of their rights under the copyright, not 024 * including other intellectual property rights, for this software module 025 * with respect to the usage by ISO/IEC and Users of this software module 026 * or modifications thereof for use in hardware or software products 027 * claiming conformance to the JPEG 2000 Standard. Those intending to use 028 * this software module in hardware or software products are advised that 029 * their use may infringe existing patents. The original developers of 030 * this software module, JJ2000 Partners and ISO/IEC assume no liability 031 * for use of this software module or modifications thereof. No license 032 * or right to this software module is granted for non JPEG 2000 Standard 033 * conforming products. JJ2000 Partners have full right to use this 034 * software module for his/her own purpose, assign or donate this 035 * software module to any third party and to inhibit third parties from 036 * using this software module for non JPEG 2000 Standard conforming 037 * products. This copyright notice must be included in all copies or 038 * derivative works of this software module. 039 * 040 * Copyright (c) 1999/2000 JJ2000 Partners. 041 * */ 042package jj2000.j2k.fileformat.reader; 043 044import java.awt.Transparency; 045import java.awt.color.ICC_Profile; 046import java.awt.color.ColorSpace; 047import java.awt.color.ICC_ColorSpace; 048import java.awt.image.ColorModel; 049import java.awt.image.ComponentColorModel; 050import java.awt.image.DataBuffer; 051import java.awt.image.IndexColorModel; 052 053import jj2000.j2k.codestream.*; 054import jj2000.j2k.fileformat.*; 055import jj2000.j2k.io.*; 056 057import java.util.*; 058import java.io.*; 059import com.sun.media.imageioimpl.plugins.jpeg2000.Box; 060import com.sun.media.imageioimpl.plugins.jpeg2000.BitsPerComponentBox; 061import com.sun.media.imageioimpl.plugins.jpeg2000.ChannelDefinitionBox; 062import com.sun.media.imageioimpl.plugins.jpeg2000.ColorSpecificationBox; 063import com.sun.media.imageioimpl.plugins.jpeg2000.ComponentMappingBox; 064import com.sun.media.imageioimpl.plugins.jpeg2000.DataEntryURLBox; 065import com.sun.media.imageioimpl.plugins.jpeg2000.FileTypeBox; 066import com.sun.media.imageioimpl.plugins.jpeg2000.HeaderBox; 067import com.sun.media.imageioimpl.plugins.jpeg2000.J2KMetadata; 068import com.sun.media.imageioimpl.plugins.jpeg2000.ResolutionBox; 069import com.sun.media.imageioimpl.plugins.jpeg2000.PaletteBox; 070import com.sun.media.imageioimpl.plugins.jpeg2000.UUIDBox; 071import com.sun.media.imageioimpl.plugins.jpeg2000.UUIDListBox; 072import com.sun.media.imageioimpl.plugins.jpeg2000.XMLBox; 073import com.sun.media.imageioimpl.plugins.jpeg2000.SignatureBox; 074 075/** 076 * This class reads the file format wrapper that may or may not exist around a 077 * valid JPEG 2000 codestream. Since no information from the file format is 078 * used in the actual decoding, this class simply goes through the file and 079 * finds the first valid codestream. 080 * 081 * @see jj2000.j2k.fileformat.writer.FileFormatWriter 082 * */ 083public class FileFormatReader implements FileFormatBoxes{ 084 085 /** The random access from which the file format boxes are read */ 086 private RandomAccessIO in; 087 088 /** The positions of the codestreams in the fileformat*/ 089 private Vector codeStreamPos; 090 091 /** The lengths of the codestreams in the fileformat*/ 092 private Vector codeStreamLength; 093 094 /** Create a IndexColorModel from the palette box if there is one */ 095 private ColorModel colorModel = null; 096 097 /** The meta data */ 098 private J2KMetadata metadata; 099 100 /** Parameters in header box */ 101 private int width; 102 private int height; 103 private int numComp; 104 private int bitDepth; 105 private int compressionType; 106 private int unknownColor; 107 private int intelProp; 108 109 /** Various bit depth */ 110 private byte[] bitDepths; 111 112 /** The lut in the palette box */ 113 private byte[][] lut; 114 private byte[] compSize; 115 116 /** Component mapping */ 117 private short[] comps; 118 private byte[] type; 119 private byte[] maps; 120 121 /** Channel definitions */ 122 private short[] channels ; 123 private short[] cType; 124 private short[] associations; 125 126 /** Color specification */ 127 private int colorSpaceType; 128 129 /** ICC profile */ 130 private ICC_Profile profile; 131 132 /** 133 * The constructor of the FileFormatReader 134 * 135 * @param in The RandomAccessIO from which to read the file format 136 * */ 137 public FileFormatReader(RandomAccessIO in, J2KMetadata metadata){ 138 this.in = in; 139 this.metadata = metadata; 140 } 141 142 143 /** 144 * This method checks whether the given RandomAccessIO is a valid JP2 file 145 * and if so finds the first codestream in the file. Currently, the 146 * information in the codestream is not used 147 * 148 * @param in The RandomAccessIO from which to read the file format 149 * 150 * @exception java.io.IOException If an I/O error ocurred. 151 * 152 * @exception java.io.EOFException If end of file is reached 153 * */ 154 public void readFileFormat() throws IOException, EOFException { 155 156 int foundCodeStreamBoxes=0; 157 int box; 158 int length; 159 long longLength=0; 160 int pos; 161 short marker; 162 boolean jp2HeaderBoxFound=false; 163 boolean lastBoxFound = false; 164 165 try{ 166 167 // Go through the randomaccessio and find the first 168 // contiguous codestream box. Check also that the File Format is 169 // correct 170 171 pos = in.getPos(); 172 173 // Make sure that the first 12 bytes is the JP2_SIGNATURE_BOX 174 // or if not that the first 2 bytes is the SOC marker 175 if(in.readInt() != 0x0000000c || 176 in.readInt() != JP2_SIGNATURE_BOX || 177 in.readInt() != 0x0d0a870a){ // Not a JP2 file 178 in.seek(pos); 179 180 marker = (short)in.readShort(); 181 if(marker != Markers.SOC) //Standard syntax marker found 182 throw new Error("File is neither valid JP2 file nor "+ 183 "valid JPEG 2000 codestream"); 184 in.seek(pos); 185 if(codeStreamPos == null) 186 codeStreamPos = new Vector(); 187 codeStreamPos.addElement(new Integer(pos)); 188 return; 189 } 190 191 if (metadata != null) 192 metadata.addNode(new SignatureBox()); 193 194 // Read all remaining boxes 195 while(!lastBoxFound){ 196 pos = in.getPos(); 197 length = in.readInt(); 198 if((pos+length) == in.length()) 199 lastBoxFound = true; 200 201 box = in.readInt(); 202 if (length == 0) { 203 lastBoxFound = true; 204 length = in.length()-in.getPos(); 205 } else if(length == 1) { 206 longLength = in.readLong(); 207 throw new IOException("File too long."); 208 } else longLength = (long) 0; 209 210 pos = in.getPos(); 211 length -= 8; 212 213 switch(box){ 214 case FILE_TYPE_BOX: 215 readFileTypeBox(length + 8, longLength); 216 break; 217 case CONTIGUOUS_CODESTREAM_BOX: 218 if(!jp2HeaderBoxFound) 219 throw new Error("Invalid JP2 file: JP2Header box not "+ 220 "found before Contiguous codestream "+ 221 "box "); 222 readContiguousCodeStreamBox(length + 8, longLength); 223 break; 224 case JP2_HEADER_BOX: 225 if(jp2HeaderBoxFound) 226 throw new Error("Invalid JP2 file: Multiple "+ 227 "JP2Header boxes found"); 228 readJP2HeaderBox(length + 8); 229 jp2HeaderBoxFound = true; 230 length = 0; 231 break; 232 case IMAGE_HEADER_BOX: 233 readImageHeaderBox(length); 234 break; 235 case INTELLECTUAL_PROPERTY_BOX: 236 readIntPropertyBox(length); 237 break; 238 case XML_BOX: 239 readXMLBox(length); 240 break; 241 case UUID_INFO_BOX: 242 length = 0; 243 break; 244 case UUID_BOX: 245 readUUIDBox(length); 246 break; 247 case UUID_LIST_BOX: 248 readUUIDListBox(length); 249 break; 250 case URL_BOX: 251 readURLBox(length); 252 break; 253 case PALETTE_BOX: 254 readPaletteBox(length + 8); 255 break; 256 case BITS_PER_COMPONENT_BOX: 257 readBitsPerComponentBox(length); 258 break; 259 case COMPONENT_MAPPING_BOX: 260 readComponentMappingBox(length); 261 break; 262 case COLOUR_SPECIFICATION_BOX: 263 readColourSpecificationBox(length); 264 break; 265 case CHANNEL_DEFINITION_BOX: 266 readChannelDefinitionBox(length); 267 break; 268 case RESOLUTION_BOX: 269 length = 0; 270 break; 271 case CAPTURE_RESOLUTION_BOX: 272 case DEFAULT_DISPLAY_RESOLUTION_BOX: 273 readResolutionBox(box, length); 274 break; 275 default: 276 if (metadata != null) { 277 byte[] data = new byte[length]; 278 in.readFully(data, 0, length); 279 metadata.addNode(new Box(length + 8, 280 box, 281 longLength, 282 data)); 283 } 284 } 285 if(!lastBoxFound) 286 in.seek(pos+length); 287 } 288 }catch( EOFException e ){ 289 throw new Error("EOF reached before finding Contiguous "+ 290 "Codestream Box"); 291 } 292 293 if(codeStreamPos.size() == 0){ 294 // Not a valid JP2 file or codestream 295 throw new Error("Invalid JP2 file: Contiguous codestream box "+ 296 "missing"); 297 } 298 299 return; 300 } 301 302 /** 303 * This method reads the File Type box 304 * 305 * @return false if the File Type box was not found or invalid else true 306 * 307 * @exception java.io.IOException If an I/O error ocurred. 308 * 309 * @exception java.io.EOFException If the end of file was reached 310 * */ 311 public boolean readFileTypeBox(int length, long longLength) 312 throws IOException, EOFException { 313 int nComp; 314 boolean foundComp=false; 315 316 // Check for XLBox 317 if(length == 1) { // Box has 8 byte length; 318 longLength = in.readLong(); 319 throw new IOException("File too long."); 320 } 321 322 // Check that this is a correct DBox value 323 // Read Brand field 324 if(in.readInt() != FT_BR) 325 return false; 326 327 // Read MinV field 328 int minorVersion = in.readInt(); 329 330 // Check that there is at least one FT_BR entry in in 331 // compatibility list 332 nComp = (length - 16)/4; // Number of compatibilities. 333 int[] comp = new int[nComp]; 334 for(int i=0; i < nComp; i++){ 335 if((comp[i] = in.readInt()) == FT_BR) 336 foundComp = true; 337 } 338 if(!foundComp) 339 return false; 340 341 if (metadata != null) 342 metadata.addNode(new FileTypeBox(FT_BR, minorVersion, comp)); 343 344 return true; 345 } 346 347 /** 348 * This method reads the JP2Header box 349 * 350 * @param pos The position in the file 351 * 352 * @param length The length of the JP2Header box 353 * 354 * @param long length The length of the JP2Header box if greater than 355 * 1<<32 356 * 357 * @return false if the JP2Header box was not found or invalid else true 358 * 359 * @exception java.io.IOException If an I/O error ocurred. 360 * 361 * @exception java.io.EOFException If the end of file was reached 362 * */ 363 public boolean readJP2HeaderBox(int length) 364 throws IOException, EOFException { 365 366 if(length == 0) // This can not be last box 367 throw new Error("Zero-length of JP2Header Box"); 368 369 // Here the JP2Header data (DBox) would be read if we were to use it 370 return true; 371 } 372 373 /** 374 * This method reads the Image Header box 375 * @param length The length of the JP2Header box 376 * 377 * @return false if the JP2Header box was not found or invalid else true 378 * 379 * @exception java.io.IOException If an I/O error ocurred. 380 * 381 * @exception java.io.EOFException If the end of file was reached 382 * */ 383 public boolean readImageHeaderBox(int length) 384 throws IOException, EOFException { 385 386 if(length == 0) // This can not be last box 387 throw new Error("Zero-length of JP2Header Box"); 388 389 // Here the JP2Header data (DBox) would be read if we were to use it 390 391 height = in.readInt(); 392 width = in.readInt(); 393 numComp = in.readShort(); 394 bitDepth = in.readByte(); 395 396 compressionType = in.readByte(); 397 unknownColor = in.readByte(); 398 intelProp = in.readByte(); 399 400 if (metadata != null) { 401 402 metadata.addNode(new HeaderBox(height, width, numComp, bitDepth, 403 compressionType, unknownColor, 404 intelProp)); 405 } 406 return true; 407 } 408 409 /** 410 * This method skips the Contiguous codestream box and adds position 411 * of contiguous codestream to a vector 412 * 413 * @param pos The position in the file 414 * 415 * @param length The length of the JP2Header box 416 * 417 * @param long length The length of the JP2Header box if greater than 1<<32 418 * 419 * @return false if the Contiguous codestream box was not found or invalid 420 * else true 421 * 422 * @exception java.io.IOException If an I/O error ocurred. 423 * 424 * @exception java.io.EOFException If the end of file was reached 425 * */ 426 public boolean readContiguousCodeStreamBox(int length, 427 long longLength) 428 throws IOException, EOFException { 429 430 // Add new codestream position to position vector 431 int ccpos = in.getPos(); 432 433 if(codeStreamPos == null) 434 codeStreamPos = new Vector(); 435 codeStreamPos.addElement(new Integer(ccpos)); 436 437 // Add new codestream length to length vector 438 if(codeStreamLength == null) 439 codeStreamLength = new Vector(); 440 codeStreamLength.addElement(new Integer(length)); 441 442 return true; 443 } 444 445 /** 446 * This method reads the contents of the Intellectual property box 447 * */ 448 public void readIntPropertyBox(int length) throws IOException { 449 if (metadata != null) { 450 byte[] data = new byte[length]; 451 in.readFully(data, 0, length); 452 metadata.addNode(new Box(length + 8, 0x6A703269, data)); 453 } 454 } 455 456 /** 457 * This method reads the contents of the XML box 458 */ 459 public void readXMLBox(int length) throws IOException { 460 if (metadata != null) { 461 byte[] data = new byte[length]; 462 in.readFully(data, 0, length); 463 metadata.addNode(new XMLBox(data)); 464 } 465 } 466 467 /** 468 * This method reads the contents of the XML box 469 */ 470 public void readURLBox(int length) throws IOException { 471 if (metadata != null) { 472 byte[] data = new byte[length]; 473 in.readFully(data, 0, length); 474 metadata.addNode(new DataEntryURLBox(data)); 475 } 476 } 477 478 /** 479 * This method reads the contents of the Intellectual property box 480 */ 481 public void readUUIDBox(int length) throws IOException { 482 if (metadata != null) { 483 byte[] data = new byte[length]; 484 in.readFully(data, 0, length); 485 metadata.addNode(new UUIDBox(data)); 486 } 487 } 488 489 /** 490 * This method reads the contents of the UUID List box 491 * */ 492 public void readUUIDListBox(int length) throws IOException { 493 if (metadata != null) { 494 byte[] data = new byte[length]; 495 in.readFully(data, 0, length); 496 metadata.addNode(new UUIDListBox(data)); 497 } 498 } 499 500 /** This method reads the content of the palette box */ 501 public void readPaletteBox(int length) throws IOException { 502 // Get current position in file 503 int pos = in.getPos(); 504 505 int lutSize = in.readShort(); 506 int numComp = in.readByte(); 507 compSize = new byte[numComp]; 508 509 for (int i = 0; i < numComp; i++) { 510 compSize[i] = (byte)in.readByte(); 511 } 512 513 lut = new byte[numComp][lutSize]; 514 515 for (int n=0; n < lutSize; n++) { 516 for (int c = 0; c < numComp; c++) { 517 int depth = 1 + (compSize[c] & 0x7F); 518 if (depth > 32) 519 depth = 32; 520 int numBytes = (depth + 7)>>3; 521 int mask = (1 << depth) - 1; 522 byte[] buf = new byte[numBytes]; 523 in.readFully(buf, 0, numBytes); 524 525 int val = 0; 526 527 for (int k = 0; k < numBytes; k++) { 528 val = buf[k] + (val << 8); 529 } 530 lut[c][n] = (byte)val; 531 } 532 } 533 if (metadata != null) { 534 metadata.addNode(new PaletteBox(length, compSize, lut)); 535 } 536 } 537 538 /** Read the component mapping channel. 539 */ 540 public void readComponentMappingBox(int length)throws IOException { 541 int num = length / 4; 542 543 comps = new short[num]; 544 type = new byte[num]; 545 maps = new byte[num]; 546 547 for (int i = 0; i < num; i++) { 548 comps[i] = in.readShort(); 549 type[i] = in.readByte(); 550 maps[i] = in.readByte(); 551 } 552 553 if (metadata != null) { 554 metadata.addNode(new ComponentMappingBox(comps, type, maps)); 555 } 556 } 557 558 /** 559 * This method reads the Channel Definition box 560 * 561 * @exception java.io.IOException If an I/O error ocurred. 562 * 563 */ 564 public void readChannelDefinitionBox(int length)throws IOException { 565 int num = in.readShort(); 566 channels = new short[num]; 567 cType = new short[num]; 568 associations = new short[num]; 569 570 for (int i = 0; i < num; i++) { 571 channels[i] = in.readShort(); 572 cType[i] = in.readShort(); 573 associations[i] = in.readShort(); 574 } 575 if (metadata != null) { 576 metadata.addNode(new ChannelDefinitionBox(channels, cType, associations)); 577 } 578 } 579 580 /** Read the bits per component. 581 */ 582 public void readBitsPerComponentBox(int length)throws IOException { 583 bitDepths = new byte[length]; 584 in.readFully(bitDepths, 0, length); 585 586 if (metadata != null) { 587 metadata.addNode(new BitsPerComponentBox(bitDepths)); 588 } 589 } 590 591 /** Read the color specifications. 592 */ 593 public void readColourSpecificationBox(int length)throws IOException { 594 // read METHOD field 595 byte method = (byte)in.readByte(); 596 597 // read PREC field 598 byte prec = (byte)in.readByte(); 599 600 // read APPROX field 601 byte approx = (byte)in.readByte(); 602 603 if (method == 2) { 604 byte[] data = new byte[length - 3]; 605 in.readFully(data, 0, data.length); 606 profile = ICC_Profile.getInstance(data); 607 } else // read EnumCS field 608 colorSpaceType = in.readInt(); 609 610 if (metadata != null) { 611 metadata.addNode(new ColorSpecificationBox(method, prec, approx, 612 colorSpaceType, 613 profile)); 614 } 615 } 616 617 /** Read the resolution. 618 */ 619 public void readResolutionBox(int type, int length)throws IOException { 620 byte[] data = new byte[length]; 621 in.readFully(data, 0, length); 622 if (metadata != null) { 623 metadata.addNode(new ResolutionBox(type, data)); 624 } 625 } 626 627 /** 628 * This method creates and returns an array of positions to contiguous 629 * codestreams in the file 630 * 631 * @return The positions of the contiguous codestreams in the file 632 * */ 633 public long[] getCodeStreamPos(){ 634 int size = codeStreamPos.size(); 635 long[] pos = new long[size]; 636 for(int i=0 ; i<size ; i++) 637 pos[i]=((Integer)(codeStreamPos.elementAt(i))).longValue(); 638 return pos; 639 } 640 641 /** 642 * This method returns the position of the first contiguous codestreams in 643 * the file 644 * 645 * @return The position of the first contiguous codestream in the file 646 * */ 647 public int getFirstCodeStreamPos(){ 648 return ((Integer)(codeStreamPos.elementAt(0))).intValue(); 649 } 650 651 /** 652 * This method returns the length of the first contiguous codestreams in 653 * the file 654 * 655 * @return The length of the first contiguous codestream in the file 656 * */ 657 public int getFirstCodeStreamLength(){ 658 return ((Integer)(codeStreamLength.elementAt(0))).intValue(); 659 } 660 661 /** 662 * Returns the color model created from the palette box. 663 */ 664 public ColorModel getColorModel() { 665 // Check 'numComp' instance variable here in case there is an 666 // embedded palette such as in the pngsuite images pp0n2c16.png 667 // and pp0n6a08.png. 668 if (lut != null && numComp == 1) { 669 int numComp = lut.length; 670 671 int maxDepth = 1 + (bitDepth & 0x7F); 672 673 if (maps == null) { 674 maps = new byte[numComp]; 675 for (int i = 0; i < numComp; i++) 676 maps[i] = (byte)i; 677 } 678 if (numComp == 3) 679 colorModel = new IndexColorModel(maxDepth, lut[0].length, 680 lut[maps[0]], 681 lut[maps[1]], 682 lut[maps[2]]); 683 else if (numComp == 4) 684 colorModel = new IndexColorModel(maxDepth, lut[0].length, 685 lut[maps[0]], 686 lut[maps[1]], 687 lut[maps[2]], 688 lut[maps[3]]); 689 } else if (channels != null){ 690 boolean hasAlpha = false; 691 int alphaChannel = numComp - 1; 692 693 for (int i = 0; i < channels.length; i++) { 694 if (cType[i] == 1 && channels[i] == alphaChannel) 695 hasAlpha = true; 696 } 697 698 boolean[] isPremultiplied = new boolean[] {false}; 699 700 if (hasAlpha) { 701 isPremultiplied = new boolean[alphaChannel]; 702 703 for (int i = 0; i < alphaChannel; i++) 704 isPremultiplied[i] = false; 705 706 for (int i = 0; i < channels.length; i++) { 707 if (cType[i] == 2) 708 isPremultiplied[associations[i] - 1] = true; 709 } 710 711 for (int i = 1; i < alphaChannel; i++) 712 isPremultiplied[0] &= isPremultiplied[i]; 713 } 714 715 ColorSpace cs = null; 716 if (profile != null) 717 cs = new ICC_ColorSpace(profile); 718 else if (colorSpaceType == CSB_ENUM_SRGB) 719 cs = ColorSpace.getInstance(ColorSpace.CS_sRGB); 720 else if (colorSpaceType == CSB_ENUM_GREY) 721 cs = ColorSpace.getInstance(ColorSpace.CS_GRAY); 722 else if (colorSpaceType == CSB_ENUM_YCC) 723 cs = ColorSpace.getInstance(ColorSpace.CS_PYCC); 724 725 int[] bits = new int[numComp]; 726 for (int i = 0; i < numComp; i++) 727 if (bitDepths != null) 728 bits[i] = (bitDepths[i] & 0x7F) + 1; 729 else 730 bits[i] = (bitDepth &0x7F) + 1; 731 732 int maxBitDepth = 1 + (bitDepth & 0x7F); 733 boolean isSigned = (bitDepth & 0x80) == 0x80; 734 if (bitDepths != null) 735 isSigned = (bitDepths[0] & 0x80) == 0x80; 736 737 if (bitDepths != null) 738 for (int i = 0; i < numComp; i++) 739 if (bits[i] > maxBitDepth) 740 maxBitDepth = bits[i]; 741 742 int type = -1; 743 744 if (maxBitDepth <= 8) 745 type = DataBuffer.TYPE_BYTE; 746 else if (maxBitDepth <= 16) 747 type = isSigned ? DataBuffer.TYPE_SHORT : DataBuffer.TYPE_USHORT; 748 else if (maxBitDepth <= 32) 749 type = DataBuffer.TYPE_INT; 750 751 if (type == -1) 752 return null; 753 754 if (cs != null) { 755 colorModel = new ComponentColorModel(cs, 756 bits, 757 hasAlpha, 758 isPremultiplied[0], 759 hasAlpha ? Transparency.TRANSLUCENT : Transparency.OPAQUE , 760 type); 761 } 762 } 763 return colorModel; 764 } 765}