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